^ madeline.phar.vendor/daverandom/libdns/examples/SOAQuery.php` o]` eZ{,vendor/daverandom/libdns/examples/AQuery.phpo]X.vendor/daverandom/libdns/examples/autoload.phpo]&vendor/daverandom/libdns/composer.jsono]xez5vendor/daverandom/libdns/tools/autoload_generator.php o] ̘Z.vendor/daverandom/libdns/src/Records/RData.phpo]F7vendor/daverandom/libdns/src/Records/ResourceQTypes.phpo]\^,8vendor/daverandom/libdns/src/Records/ResourceFactory.phpo]p7Ͷ1vendor/daverandom/libdns/src/Records/Question.phpo]]1vendor/daverandom/libdns/src/Records/Resource.phpo]V~8vendor/daverandom/libdns/src/Records/ResourceClasses.phpo]v8vendor/daverandom/libdns/src/Records/ResourceBuilder.phpo]t%Y6vendor/daverandom/libdns/src/Records/ResourceTypes.phpo]z|[8vendor/daverandom/libdns/src/Records/QuestionFactory.phpEo]EPӭHvendor/daverandom/libdns/src/Records/TypeDefinitions/FieldDefinition.phpo]<Nvendor/daverandom/libdns/src/Records/TypeDefinitions/TypeDefinitionFactory.phpao]a:_׶Ovendor/daverandom/libdns/src/Records/TypeDefinitions/FieldDefinitionFactory.phpGo]GGBj׶Gvendor/daverandom/libdns/src/Records/TypeDefinitions/TypeDefinition.phpo]^X޶Uvendor/daverandom/libdns/src/Records/TypeDefinitions/TypeDefinitionManagerFactory.phpo]p[Nvendor/daverandom/libdns/src/Records/TypeDefinitions/TypeDefinitionManager.php;)o];)1]>>vendor/daverandom/libdns/src/Records/Types/CharacterString.phpZo]ZJ3:vendor/daverandom/libdns/src/Records/Types/TypeFactory.php o] 5vendor/daverandom/libdns/src/Records/Types/BitMap.phpo]ku7vendor/daverandom/libdns/src/Records/Types/Anything.php]o]]24vendor/daverandom/libdns/src/Records/Types/Short.phpo]9vendor/daverandom/libdns/src/Records/Types/DomainName.php1 o]1 Q3vendor/daverandom/libdns/src/Records/Types/Long.phpo]w+:vendor/daverandom/libdns/src/Records/Types/TypeBuilder.phpUo]Ut3vendor/daverandom/libdns/src/Records/Types/Type.phpo]Շ#!:vendor/daverandom/libdns/src/Records/Types/IPv6Address.phpo]p 3vendor/daverandom/libdns/src/Records/Types/Char.phpo]>9^:vendor/daverandom/libdns/src/Records/Types/IPv4Address.php o] Il4vendor/daverandom/libdns/src/Records/Types/Types.phpo]P9vendor/daverandom/libdns/src/Records/ResourceQClasses.phpo]5vendor/daverandom/libdns/src/Records/RDataFactory.phpno]n.j5vendor/daverandom/libdns/src/Records/RDataBuilder.phpto]t|?vendor/daverandom/libdns/src/Records/ResourceBuilderFactory.phpo]hL9vendor/daverandom/libdns/src/Records/RecordCollection.php o] ʲ4vendor/daverandom/libdns/src/Records/RecordTypes.phpo]0/vendor/daverandom/libdns/src/Records/Record.php! o]! @vendor/daverandom/libdns/src/Records/RecordCollectionFactory.phpo]M )*vendor/daverandom/libdns/src/functions.phpo]M?vendor/daverandom/libdns/src/Encoder/EncodingContextFactory.phpo]n϶7vendor/daverandom/libdns/src/Encoder/EncoderFactory.phpo] ζ0vendor/daverandom/libdns/src/Encoder/Encoder.php+o]+qH8vendor/daverandom/libdns/src/Encoder/EncodingContext.phpo]146vendor/daverandom/libdns/src/Packets/LabelRegistry.phpAo]Auf/vendor/daverandom/libdns/src/Packets/Packet.php o] GP6vendor/daverandom/libdns/src/Packets/PacketFactory.phpo]i@0vendor/daverandom/libdns/src/Decoder/Decoder.phpIo]I-U8vendor/daverandom/libdns/src/Decoder/DecodingContext.phpo]$W:A?vendor/daverandom/libdns/src/Decoder/DecodingContextFactory.phpo]Y)7vendor/daverandom/libdns/src/Decoder/DecoderFactory.phpao]a/o6vendor/daverandom/libdns/src/Messages/MessageTypes.phpo]T+8vendor/daverandom/libdns/src/Messages/MessageOpCodes.phpo]`iB1vendor/daverandom/libdns/src/Messages/Message.phppo]p&7>vendor/daverandom/libdns/src/Messages/MessageResponseCodes.php o] b7'8vendor/daverandom/libdns/src/Messages/MessageFactory.phpo]Oٳ',vendor/daverandom/libdns/src/Enumeration.phpo]{ %vendor/erusev/parsedown/Parsedown.phpo]%vendor/erusev/parsedown/composer.jsono]4%vendor/psr/http-message/composer.jsonmo]m,vendor/psr/http-message/src/UriInterface.php?1o]?1?.5vendor/psr/http-message/src/UploadedFileInterface.phpQo]Q㭢v/vendor/psr/http-message/src/StreamInterface.phpo]=fbr6vendor/psr/http-message/src/ServerRequestInterface.phpr'o]r'_1vendor/psr/http-message/src/ResponseInterface.php o] -{0vendor/psr/http-message/src/MessageInterface.phpo]z /0vendor/psr/http-message/src/RequestInterface.phpo]Զ)vendor/danog/dns-over-https/composer.jsono] 3vendor/danog/dns-over-https/lib/Internal/Socket.phppo]p2}8vendor/danog/dns-over-https/lib/Internal/HttpsSocket.php o] "ED0vendor/danog/dns-over-https/lib/DoHException.phpqo]qg7vendor/danog/dns-over-https/lib/Rfc8484StubResolver.php;o];nÍ.vendor/danog/dns-over-https/lib/Nameserver.phpo]Bk2-vendor/danog/dns-over-https/lib/DoHConfig.phpo]5&vendor/danog/libdns-json/composer.json:o]:9K2vendor/danog/libdns-json/test/QueryEncoderTest.phpo]R8vendor/danog/libdns-json/test/JsonDecoderFactoryTest.php^o]^q@1vendor/danog/libdns-json/test/JsonDecoderTest.phpdo]d^9vendor/danog/libdns-json/test/QueryEncoderFactoryTest.phpdo]dL[L,vendor/danog/libdns-json/lib/JsonDecoder.phpp2o]p2ȢV3vendor/danog/libdns-json/lib/JsonDecoderFactory.phpo]&4vendor/danog/libdns-json/lib/QueryEncoderFactory.php4o]4lY ȶ-vendor/danog/libdns-json/lib/QueryEncoder.phpo]hY9'vendor/danog/madelineproto/makephar.phpYo]YOa)vendor/danog/madelineproto/build_docs.phpo]/9m'vendor/danog/madelineproto/asyncify.phpo]=$vendor/danog/madelineproto/index.phpo]23+vendor/danog/madelineproto/combined_bot.php^ o]^ /])vendor/danog/madelineproto/secret_bot.php5 o]5 2xͶ"vendor/danog/madelineproto/bot.php o] F])vendor/danog/madelineproto/translator.phpo]6Qo=vendor/danog/madelineproto/userbots/pwrtelegram_debug_bot.php0,o]0,H׶9vendor/danog/madelineproto/userbots/MadelineProto_bot.phps#o]s#lݶ0vendor/danog/madelineproto/userbots/pipesbot.php96o]96 (vendor/danog/madelineproto/composer.json.o].6Ķ#vendor/danog/madelineproto/phar.php o] ׿Ӷ(vendor/danog/madelineproto/layerdiff.phpo]͖+vendor/danog/madelineproto/lua/madeline.phpSo]S5%vendor/danog/madelineproto/lua/td.phpOo]O֦S/vendor/danog/madelineproto/multiprocess_bot.phpa o]a я6$vendor/danog/madelineproto/songs.phpo]W:vendor/danog/madelineproto/src/danog/MadelineProto/API.php'Bo]'B=?Ovendor/danog/madelineproto/src/danog/MadelineProto/SecretChats/SeqNoHandler.php>o]>UQvendor/danog/madelineproto/src/danog/MadelineProto/SecretChats/AuthKeyHandler.phpr<o]r<]!Qvendor/danog/madelineproto/src/danog/MadelineProto/SecretChats/MessageHandler.php,o],N]Rvendor/danog/madelineproto/src/danog/MadelineProto/SecretChats/ResponseHandler.phpvo]vYѶGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v41.jsono]aBvendor/danog/madelineproto/src/danog/MadelineProto/InternalDoc.phpo]KEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v86.tl8]o]8]`?vendor/danog/madelineproto/src/danog/MadelineProto/TL_socket.tlZo]ZGbGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v55.json'o]' ZBAvendor/danog/madelineproto/src/danog/MadelineProto/Conversion.phpSo]Sm@Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v89.tldjo]dj=8Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v68.tl6o]6`DGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v51.jsono])ĶPvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Connection/WriteLoop.phpDo]DoXPvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Connection/CheckLoop.php$o]$ ASvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Connection/HttpWaitLoop.php o] F¸Ovendor/danog/madelineproto/src/danog/MadelineProto/Loop/Connection/ReadLoop.phpz'o]z'KOvendor/danog/madelineproto/src/danog/MadelineProto/Loop/SignalLoopInterface.php o] 9"Ivendor/danog/madelineproto/src/danog/MadelineProto/Loop/LoopInterface.phpo]cMRvendor/danog/madelineproto/src/danog/MadelineProto/Loop/ResumableLoopInterface.phpo]N'$Evendor/danog/madelineproto/src/danog/MadelineProto/Loop/Impl/Loop.php o] LTvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.phpT o]T e.Kvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Impl/SignalLoop.phpo]6N߶Mvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Update/UpdateLoop.php(o](d޶Kvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Update/FeedLoop.php*o]*Jvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Update/SeqLoop.phpo]4AOvendor/danog/madelineproto/src/danog/MadelineProto/Loop/Generic/GenericLoop.php o] Y<vendor/danog/madelineproto/src/danog/MadelineProto/Tools.php1o]1LEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v72.tlCo]C?aEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v97.tlh|o]h|4 >vendor/danog/madelineproto/src/danog/MadelineProto/MTProto.phpo]AжEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v91.tlpo]plJ?Cvendor/danog/madelineproto/src/danog/MadelineProto/TL_mtproto_v1.tlWo]WrnֶFvendor/danog/madelineproto/src/danog/MadelineProto/ProxySocketPool.phpo]@.Gvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v38.json [o] [Y;?vendor/danog/madelineproto/src/danog/MadelineProto/TL_secret.tlo]7Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v95.tlKvo]Kv#BZvendor/danog/madelineproto/src/danog/MadelineProto/Stream/BufferedProxyStreamInterface.phpo]ؿMvendor/danog/madelineproto/src/danog/MadelineProto/Stream/StreamInterface.phpqo]qTUvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Transport/DefaultStream.php_o]_.bA¶Pvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Transport/WsStream.phpo]cĶQvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Transport/WssStream.phpGo]GY3Rvendor/danog/madelineproto/src/danog/MadelineProto/Stream/ProxyStreamInterface.php o] ,JVvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Common/BufferedRawStream.phpyo]yYvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Common/HashedBufferedStream.php#o]#VPvendor/danog/madelineproto/src/danog/MadelineProto/Stream/RawStreamInterface.phpo]OfUvendor/danog/madelineproto/src/danog/MadelineProto/Stream/BufferedStreamInterface.phpo]ND Rvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Async/BufferedStream.phpo]hJvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Async/Buffer.phpo]K Mvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Async/RawStream.php.o].*MJvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Async/Stream.phpo]ns)Mvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Proxy/HttpProxy.phpo]*]$ʶNvendor/danog/madelineproto/src/danog/MadelineProto/Stream/Proxy/SocksProxy.phpo]TTavendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediateStream.php/ o]/ Ql-_vendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/ObfuscatedStream.phpo]6Yvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.phpo]Zvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/HttpsStream.phpUo]UWZ=]vendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/AbridgedStream.phpO o]O 0x%Yvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/FullStream.phpo]Fjgvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTransport/IntermediatePaddedStream.php o] ?Uvendor/danog/madelineproto/src/danog/MadelineProto/Stream/RawProxyStreamInterface.phpo]XsdTvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoBufferInterface.phpo]AM}Wvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTools/MsgIdHandler.php"o]"Wvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTools/SeqNoHandler.phpz o]z VVvendor/danog/madelineproto/src/danog/MadelineProto/Stream/MTProtoTools/SaltHandler.phpo]Q<Mvendor/danog/madelineproto/src/danog/MadelineProto/Stream/BufferInterface.phpo]M?|Ovendor/danog/madelineproto/src/danog/MadelineProto/Stream/ConnectionContext.php'o]'GrJvendor/danog/madelineproto/src/danog/MadelineProto/VoIP/AuthKeyHandler.phpq?o]q?'Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v71.tl=o]=1>vendor/danog/madelineproto/src/danog/MadelineProto/TL_calls.tljo]jp=ĶRvendor/danog/madelineproto/src/danog/MadelineProto/NothingInTheSocketException.php1o]1h=vendor/danog/madelineproto/src/danog/MadelineProto/Logger.phpo]5lKvendor/danog/madelineproto/src/danog/MadelineProto/CombinedEventHandler.phpo]gJȶEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v65.tlo]<ɶGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v44.jsono]B@Gvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v40.json'o]'$ 0Avendor/danog/madelineproto/src/danog/MadelineProto/Connection.php(o](sGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v45.jsono]*0!Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v81.tlTRo]TR4?vendor/danog/madelineproto/src/danog/MadelineProto/Absolute.php+o]+>oҶ;vendor/danog/madelineproto/src/danog/MadelineProto/TL_td.tlo]?tͶGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v25.jsono]c]ǶEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v46.tlo]m'ڶGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v27.jsono]՗U<vendor/danog/madelineproto/src/danog/MadelineProto/Proxy.phpko]kGvendor/danog/madelineproto/src/danog/MadelineProto/Async/Parameters.phpo]eEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v70.tl8o]8yaHvendor/danog/madelineproto/src/danog/MadelineProto/SecurityException.phpo]tEICvendor/danog/madelineproto/src/danog/MadelineProto/EventHandler.phpo]Hvendor/danog/madelineproto/src/danog/MadelineProto/RPCErrorException.php>#o]>#/ 뻶Avendor/danog/madelineproto/src/danog/MadelineProto/APIFactory.php"o]"'Q{:vendor/danog/madelineproto/src/danog/MadelineProto/RSA.php o] x(Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v62.tlo]o$:vendor/danog/madelineproto/src/danog/MadelineProto/Lua.phpo]?vendor/danog/madelineproto/src/danog/MadelineProto/Shutdown.phpA o]A [KGvendor/danog/madelineproto/src/danog/MadelineProto/VoIPServerConfig.php o] 7Iȶ<vendor/danog/madelineproto/src/danog/MadelineProto/Magic.php@>o]@>&tGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v42.jsonjo]j&ŶCvendor/danog/madelineproto/src/danog/MadelineProto/Wrappers/TOS.php o] IJDvendor/danog/madelineproto/src/danog/MadelineProto/Wrappers/Loop.phpo]3yHvendor/danog/madelineproto/src/danog/MadelineProto/Wrappers/Callback.php7o]7sHvendor/danog/madelineproto/src/danog/MadelineProto/Wrappers/ApiStart.phpo]Dvendor/danog/madelineproto/src/danog/MadelineProto/Wrappers/Noop.php*o]*MEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v75.tl5o]5H@vendor/danog/madelineproto/src/danog/MadelineProto/Coroutine.phpXo]XO,Xvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/CombinedUpdatesState.php o] Pvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/UpdatesState.php0o]0běIvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/Files.phpyo]yvmOvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/CallHandler.phpl&o]l&JUvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.phpN^o]N^9Pvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/SeqNoHandler.php?o]?Ivendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/Crypt.php, o], rOvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/PeerHandler.phpo]?Rvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.phpo]!-@Qvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php8o]8Svendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/ResponseHandler.phpxo]xUH:Vvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/PasswordCalculator.php!o]!nNvendor/danog/madelineproto/src/danog/MadelineProto/MTProtoTools/AckHandler.phpo]XvGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v23.jsono]8RAvendor/danog/madelineproto/src/danog/MadelineProto/DataCenter.phpmo]mP ?vendor/danog/madelineproto/src/danog/MadelineProto/TL_botAPI.tlKo]K&^KKvendor/danog/madelineproto/src/danog/MadelineProto/MyTelegramOrgWrapper.php0o]0O'pCvendor/danog/madelineproto/src/danog/MadelineProto/FileCallback.phpo]^a Evendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v82.tlUo]U%GEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v66.tl"o]"-_Cvendor/danog/madelineproto/src/danog/MadelineProto/PTSException.php~o]~@Lvendor/danog/madelineproto/src/danog/MadelineProto/FileCallbackInterface.php^o]^d UEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v73.tlS2o]S2Ѭ[Hvendor/danog/madelineproto/src/danog/MadelineProto/Bug74586Exception.phpo]&sejDvendor/danog/madelineproto/src/danog/MadelineProto/Serialization.phpmo]mCEvendor/danog/madelineproto/src/danog/MadelineProto/TL_mtproto_v1.jsono]1x2-Ivendor/danog/madelineproto/src/danog/MadelineProto/AnnotationsBuilder.phpo] uy @vendor/danog/madelineproto/src/danog/MadelineProto/Exception.phpo]j2Gvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v33.jsono]TߙBvendor/danog/madelineproto/src/danog/MadelineProto/CombinedAPI.php$o]$O[AEvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v98.tl~o]~RPGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v53.json;o];xbGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v18.json o]  RFvendor/danog/madelineproto/src/danog/MadelineProto/TL_MadelineProto.tlo]ԶHvendor/danog/madelineproto/src/danog/MadelineProto/ResponseException.phpo]IζJvendor/danog/madelineproto/src/danog/MadelineProto/DocsBuilder/Methods.phpTKo]TK)Ovendor/danog/madelineproto/src/danog/MadelineProto/DocsBuilder/Constructors.php8o]8_Dvendor/danog/madelineproto/src/danog/MadelineProto/TL/TLCallback.phpAo]Ae&<vendor/danog/madelineproto/src/danog/MadelineProto/TL/TL.phpo]cFvendor/danog/madelineproto/src/danog/MadelineProto/TL/Types/Button.phpo] 8Evendor/danog/madelineproto/src/danog/MadelineProto/TL/Types/Bytes.phpo] Bvendor/danog/madelineproto/src/danog/MadelineProto/TL/TLParams.phpo]B5yIvendor/danog/madelineproto/src/danog/MadelineProto/TL/PrettyException.phpv o]v  yVGvendor/danog/madelineproto/src/danog/MadelineProto/TL/TLConstructor.phpo]ntGvendor/danog/madelineproto/src/danog/MadelineProto/TL/Conversion/TD.phpo]#ɶPvendor/danog/madelineproto/src/danog/MadelineProto/TL/Conversion/BotAPIFiles.phpo]^|bKvendor/danog/madelineproto/src/danog/MadelineProto/TL/Conversion/BotAPI.phpcyo]cy+9Nvendor/danog/madelineproto/src/danog/MadelineProto/TL/Conversion/Extension.php3 o]3 j`Nvendor/danog/madelineproto/src/danog/MadelineProto/TL/Conversion/Exception.phpo]c"`Cvendor/danog/madelineproto/src/danog/MadelineProto/TL/Exception.phpdo]dqtBvendor/danog/madelineproto/src/danog/MadelineProto/TL/TLMethod.phpo]e.Evendor/danog/madelineproto/src/danog/MadelineProto/Server/Handler.php0o]0WCvendor/danog/madelineproto/src/danog/MadelineProto/Server/Proxy.phpo]yDvendor/danog/madelineproto/src/danog/MadelineProto/Server/Stream.phpo]+X0=vendor/danog/madelineproto/src/danog/MadelineProto/Server.phpo]AGvendor/danog/madelineproto/src/danog/MadelineProto/TL_telegram_v57.jsono]8;vendor/danog/madelineproto/src/danog/MadelineProto/Lang.php$ o]$ iE Bvendor/danog/madelineproto/src/danog/MadelineProto/DocsBuilder.phpgfo]gfo#3vendor/danog/madelineproto/src/YieldReturnValue.phpo];[m-vendor/danog/madelineproto/src/BigIntegor.php/o]/EyԶ$vendor/danog/madelineproto/magna.php<;o]<;%{$vendor/danog/magicalserializer/b.phpo]Ž&{,vendor/danog/magicalserializer/composer.jsono]އ$vendor/danog/magicalserializer/a.phpNo]N]9vendor/danog/magicalserializer/src/danog/Serializable.phpo]Y:vendor/danog/magicalserializer/src/danog/Serialization.phpo]V8vendor/danog/magicalserializer/src/danog/PlaceHolder.phpto]t't&vendor/danog/primemodule/composer.jsonFo]F0Su/vendor/danog/primemodule/lib/danog/alt_prime.pyo]_3{+vendor/danog/primemodule/lib/danog/prime.pyI/o]I/2vendor/danog/primemodule/lib/danog/PrimeModule.php 9o] 9o,SҶ"vendor/composer/autoload_files.phpao]a Զ#vendor/composer/autoload_static.phpn o]n #)uݶ!vendor/composer/autoload_real.phpn o]n ̥>!vendor/composer/autoload_psr4.phpo]Sgvendor/composer/ClassLoader.php4o]4zvendor/composer/installed.jsono]h%vendor/composer/autoload_classmap.phpo]b'vendor/composer/autoload_namespaces.php o] avendor/amphp/amp/composer.json.o]. 9%1vendor/amphp/amp/lib/TimeoutCancellationToken.phpo]U +vendor/amphp/amp/lib/CancelledException.phpTo]T& vendor/amphp/amp/lib/Emitter.php1o]1f!vendor/amphp/amp/lib/Iterator.phpo]ı@޶)vendor/amphp/amp/lib/TimeoutException.phpto]tPMS!vendor/amphp/amp/lib/Producer.phpuo]u$~Ƕvendor/amphp/amp/lib/Loop.phpDo]D]а1vendor/amphp/amp/lib/Internal/ResolutionQueue.php?o]?BvB*vendor/amphp/amp/lib/Internal/Producer.phpo]aݶ0vendor/amphp/amp/lib/Internal/PrivatePromise.phpo]vJ +vendor/amphp/amp/lib/Internal/functions.php o] ]~-vendor/amphp/amp/lib/Internal/Placeholder.phpo]k41vendor/amphp/amp/lib/Internal/PrivateIterator.phpgo]g.Y%vendor/amphp/amp/lib/Loop/Watcher.phpJo]Jsy1vendor/amphp/amp/lib/Loop/InvalidWatcherError.phpo]#4&vendor/amphp/amp/lib/Loop/EvDriver.phpo]h T#1vendor/amphp/amp/lib/Loop/Internal/TimerQueue.php o] Q6vendor/amphp/amp/lib/Loop/Internal/TimerQueueEntry.phpo]JS*vendor/amphp/amp/lib/Loop/NativeDriver.php0o]0Vr&vendor/amphp/amp/lib/Loop/UvDriver.php$o]$_+vendor/amphp/amp/lib/Loop/DriverFactory.phpAo]A9vendor/amphp/amp/lib/Loop/UnsupportedFeatureException.phpo]0`$vendor/amphp/amp/lib/Loop/Driver.phpdo]dB9)vendor/amphp/amp/lib/Loop/EventDriver.php"o]"[*vendor/amphp/amp/lib/CancellationToken.phpo]V"vendor/amphp/amp/lib/functions.phpYo]Yq3 vendor/amphp/amp/lib/Failure.php?o]?L!vendor/amphp/amp/lib/Deferred.php7o]7|À.vendor/amphp/amp/lib/NullCancellationToken.phpo]u8-vendor/amphp/amp/lib/MultiReasonException.phpo]{I$vendor/amphp/amp/lib/LazyPromise.php[o][ѳ vendor/amphp/amp/lib/Success.phplo]l8 vendor/amphp/amp/lib/Promise.phpKo]K鹗vendor/amphp/amp/lib/Struct.phpo]"vendor/amphp/amp/lib/Coroutine.php5o]5|7J&vendor/amphp/amp/lib/CallableMaker.php o] h vendor/amphp/amp/lib/Delayed.phpOo]ONR*vendor/amphp/amp/lib/InvalidYieldError.phpdo]dKƭ0vendor/amphp/amp/lib/CancellationTokenSource.php|o]|Y/:vendor/amphp/byte-stream/examples/benchmark-throughput.phpo]6Pc5vendor/amphp/byte-stream/examples/gzip-decompress.phpo]˱k϶3vendor/amphp/byte-stream/examples/gzip-compress.phpo]&vendor/amphp/byte-stream/composer.jsono]=/vendor/amphp/byte-stream/lib/IteratorStream.phpo]U>T*vendor/amphp/byte-stream/lib/functions.php o] Tp1vendor/amphp/byte-stream/lib/PendingReadError.phpo]^0vendor/amphp/byte-stream/lib/ZlibInputStream.phpc o]c m-vendor/amphp/byte-stream/lib/OutputStream.phpo]+Xb0vendor/amphp/byte-stream/lib/ClosedException.phpZo]Z -vendor/amphp/byte-stream/lib/OutputBuffer.phpro]rL,vendor/amphp/byte-stream/lib/InputStream.phpo]Iж4vendor/amphp/byte-stream/lib/ResourceInputStream.phpo]²(vendor/amphp/byte-stream/lib/Message.phpo]<1vendor/amphp/byte-stream/lib/ZlibOutputStream.php\ o]\ /vendor/amphp/byte-stream/lib/InMemoryStream.php5o]5z$0vendor/amphp/byte-stream/lib/StreamException.phpOo]Oکݶ(vendor/amphp/byte-stream/lib/Payload.php o] ڶ5vendor/amphp/byte-stream/lib/ResourceOutputStream.php#o]#ζ3vendor/amphp/socket/examples/simple-http-server.phpo]&3vendor/amphp/socket/examples/simple-http-client.php_o]_I-!vendor/amphp/socket/composer.json0o]0XYy3vendor/amphp/socket/test/Internal/functionsTest.php o] ~"-Ƕ1vendor/amphp/socket/test/TlsFragmentationTest.php o] 3*vendor/amphp/socket/test/functionsTest.php=o]=ڶ3vendor/amphp/socket/test/PendingAcceptErrorTest.phpWo]Wt'vendor/amphp/socket/test/SocketTest.phpo]l4vendor/amphp/socket/test/ServerListenContextTest.php o] V1vendor/amphp/socket/test/ServerTlsContextTest.php!o]!0"5vendor/amphp/socket/test/ClientConnectContextTest.phpo]"-,vendor/amphp/socket/test/IntegrationTest.php o] ?1vendor/amphp/socket/test/StaticSocketPoolTest.phpo]">1vendor/amphp/socket/test/ClientTlsContextTest.php"o]"M'vendor/amphp/socket/test/ServerTest.php$o]$a.g.vendor/amphp/socket/src/Internal/functions.phpo]jV%vendor/amphp/socket/src/functions.phpP%o]P%!ֶ+vendor/amphp/socket/src/BasicSocketPool.phpo]Hi(vendor/amphp/socket/src/ServerSocket.phpRo]RlU.vendor/amphp/socket/src/PendingAcceptError.phpo]Vg"vendor/amphp/socket/src/Socket.php o] )3%/vendor/amphp/socket/src/ServerListenContext.phpU o]U Cw'vendor/amphp/socket/src/Certificate.phpBo]B?+vendor/amphp/socket/src/CryptoException.phpPo]Ps ,vendor/amphp/socket/src/ServerTlsContext.php-o]-OQζ,vendor/amphp/socket/src/ConnectException.phpQo]Q {F+vendor/amphp/socket/src/SocketException.phpuo]u (vendor/amphp/socket/src/ClientSocket.phpio]iv,vendor/amphp/socket/src/ClientTlsContext.php&o]&,vendor/amphp/socket/src/StaticSocketPool.php o] YC\&vendor/amphp/socket/src/SocketPool.phpo]"vendor/amphp/socket/src/Server.php)o])D0vendor/amphp/socket/src/ClientConnectContext.php o] dsvendor/amphp/dns/composer.jsongo]gWY)vendor/amphp/dns/lib/TimeoutException.phpKo]Kt%vendor/amphp/dns/lib/DnsException.phpEo]EkLC+vendor/amphp/dns/lib/Internal/UdpSocket.php&o]& 9(vendor/amphp/dns/lib/Internal/Socket.phpo]ᅶ+vendor/amphp/dns/lib/Internal/TcpSocket.php o] O )vendor/amphp/dns/lib/UnixConfigLoader.php o] R,vendor/amphp/dns/lib/Rfc1035StubResolver.php Eo] E-۶"vendor/amphp/dns/lib/functions.phpc o]c c(˶(vendor/amphp/dns/lib/ConfigException.phpAo]A%vendor/amphp/dns/lib/ConfigLoader.phpso]ssE!vendor/amphp/dns/lib/Resolver.phpo]G8-vendor/amphp/dns/lib/InvalidNameException.phpOo]O8M#vendor/amphp/dns/lib/HostLoader.php o] C*vendor/amphp/dns/lib/NoRecordException.phpLo]Lpavendor/amphp/dns/lib/Record.php o] )vendor/amphp/dns/lib/Config.php o] u|,vendor/amphp/dns/lib/WindowsConfigLoader.php o] ,yRvendor/amphp/uri/composer.jsono]l0vendor/amphp/uri/src/InvalidDnsNameException.phpPo]PEm"vendor/amphp/uri/src/functions.phpto]tcNvendor/amphp/uri/src/Uri.php2o]2XR,vendor/amphp/uri/src/InvalidUriException.phpLo]LGvendor/amphp/sync/composer.jsono]Ƕ/vendor/amphp/sync/lib/Internal/MutexStorage.php5o]5ڶ3vendor/amphp/sync/lib/Internal/SemaphoreStorage.php3o]3#l̶#vendor/amphp/sync/lib/functions.phpro]rG#vendor/amphp/sync/lib/Semaphore.phpo] Kɶ(vendor/amphp/sync/lib/PosixSemaphore.phpo]z#vendor/amphp/sync/lib/FileMutex.phpo] y$vendor/amphp/sync/lib/LocalMutex.phpo]f>W+vendor/amphp/sync/lib/ThreadedSemaphore.php6o]6L-'vendor/amphp/sync/lib/SyncException.phpGo]GU8vendor/amphp/sync/lib/Lock.phpo]Q'övendor/amphp/sync/lib/Mutex.phpo]X(vendor/amphp/sync/lib/LocalSemaphore.phpo] 'vendor/amphp/sync/lib/ThreadedMutex.php.o].(vendor/amphp/sync/lib/SemaphoreMutex.phpo]5K!vendor/amphp/parser/composer.jsono]r1vendor/amphp/parser/lib/InvalidDelimiterError.phpko]kaNe"vendor/amphp/parser/lib/Parser.php]o]]f੶#vendor/amphp/parallel/composer.jsongo]g߸ 32vendor/amphp/parallel/lib/Worker/WorkerProcess.phpWo]WqD9vendor/amphp/parallel/lib/Worker/DefaultWorkerFactory.phpo]},)vendor/amphp/parallel/lib/Worker/Task.phpo]Zs/vendor/amphp/parallel/lib/Worker/TaskWorker.phpo]Q5vendor/amphp/parallel/lib/Worker/BasicEnvironment.phpo]l|);vendor/amphp/parallel/lib/Worker/Internal/WorkerProcess.phpo]SŶ:vendor/amphp/parallel/lib/Worker/Internal/PooledWorker.phpjo]j8u<vendor/amphp/parallel/lib/Worker/Internal/worker-process.phpxo]xbh9vendor/amphp/parallel/lib/Worker/Internal/TaskSuccess.phpo]\8vendor/amphp/parallel/lib/Worker/Internal/TaskResult.phpNo]NrU1vendor/amphp/parallel/lib/Worker/Internal/Job.php3o]3ۗ9vendor/amphp/parallel/lib/Worker/Internal/TaskFailure.php_o]_Y:)vendor/amphp/parallel/lib/Worker/Pool.phpo]ojG.vendor/amphp/parallel/lib/Worker/functions.phpo]4vendor/amphp/parallel/lib/Worker/WorkerException.phpTo]T G2vendor/amphp/parallel/lib/Worker/TaskException.php o] WR;0vendor/amphp/parallel/lib/Worker/Environment.phpo]ƶ2vendor/amphp/parallel/lib/Worker/WorkerFactory.phpo]KR.vendor/amphp/parallel/lib/Worker/TaskError.phpo]gG-1vendor/amphp/parallel/lib/Worker/WorkerThread.phpo]R~ٶ1vendor/amphp/parallel/lib/Worker/CallableTask.php3o]3q_u/vendor/amphp/parallel/lib/Worker/TaskRunner.phpo] ?00vendor/amphp/parallel/lib/Worker/DefaultPool.phpIo]I|W"+vendor/amphp/parallel/lib/Worker/Worker.phpo]Sa9vendor/amphp/parallel/lib/Context/Internal/ProcessHub.phpo]+x=vendor/amphp/parallel/lib/Context/Internal/process-runner.php o] Q3eG5vendor/amphp/parallel/lib/Context/Internal/Thread.phpo]!o6vendor/amphp/parallel/lib/Context/ContextException.phpVo]Vͺ,vendor/amphp/parallel/lib/Context/Thread.php#o]#d<-vendor/amphp/parallel/lib/Context/Context.phpo]6-vendor/amphp/parallel/lib/Context/Process.php+o]+1 >1vendor/amphp/parallel/lib/Context/StatusError.phpMo]Mr9vendor/amphp/parallel/lib/Sync/SerializationException.phpYo]YZ+w7vendor/amphp/parallel/lib/Sync/SynchronizationError.phpSo]S\7|9vendor/amphp/parallel/lib/Sync/Internal/ParcelStorage.phpo]Y50vendor/amphp/parallel/lib/Sync/ChannelParser.php o] qŇ*vendor/amphp/parallel/lib/Sync/Channel.phpo]AiL-vendor/amphp/parallel/lib/Sync/ExitResult.php'o]'| 8vendor/amphp/parallel/lib/Sync/SharedMemoryException.phpXo]X,y)vendor/amphp/parallel/lib/Sync/Parcel.phpo]G3vendor/amphp/parallel/lib/Sync/ChannelledSocket.phpo]T5vendor/amphp/parallel/lib/Sync/SharedMemoryParcel.php0o]0].vendor/amphp/parallel/lib/Sync/ExitSuccess.phpIo]I^Ƕ.vendor/amphp/parallel/lib/Sync/ExitFailure.phpo]}l-vendor/amphp/parallel/lib/Sync/PanicError.phpo]h=K'3vendor/amphp/parallel/lib/Sync/ChannelException.phpSo]S1vendor/amphp/parallel/lib/Sync/ThreadedParcel.phpXo]XC}3vendor/amphp/parallel/lib/Sync/ChannelledStream.phpo]H<vendor/amphp/websocket-client/examples/kaazing-echo-demo.phpVo]V'.vendor/amphp/websocket-client/examples/amp.phpo]m!26vendor/amphp/websocket-client/test-autobahn/runner.php< o]< ũEvendor/amphp/websocket-client/test-autobahn/config/fuzzingserver.jsono]tB+vendor/amphp/websocket-client/composer.jsono]kp>vendor/amphp/websocket-client/test/Helper/WebsocketAdapter.phpo]X4k4vendor/amphp/websocket-client/test/WebSocketTest.phpo]U9vendor/amphp/websocket-client/src/ConnectionException.php_o]_%/vendor/amphp/websocket-client/src/Handshake.phpo]|e*.;vendor/amphp/websocket-client/src/Internal/ClientSocket.phpo]m/vendor/amphp/websocket-client/src/functions.phpo]CX/vendor/amphp/websocket-client/src/Connector.phpo]Q@w0vendor/amphp/websocket-client/src/Connection.phpo]Ķ7vendor/amphp/websocket-client/src/Rfc6455Connection.php o] v6vendor/amphp/websocket-client/src/Rfc6455Connector.phpo]U4#Mvendor/amphp/file/composer.json2o]2d *vendor/amphp/file/test/AsyncHandleTest.phpo]O[u"vendor/amphp/file/test/Fixture.phpo]q!-vendor/amphp/file/test/ParallelDriverTest.phpo]'vendor/amphp/file/test/UvDriverTest.phpo]JXȶ%vendor/amphp/file/test/DriverTest.php/o]/-vendor/amphp/file/test/BlockingDriverTest.phpKo]K^&i(vendor/amphp/file/test/EioHandleTest.phpo])'vendor/amphp/file/test/UvHandleTest.php$o]$,@%vendor/amphp/file/test/HandleTest.php/o]/n-vendor/amphp/file/test/BlockingHandleTest.phpKo]KC(vendor/amphp/file/test/EioDriverTest.phpo]9-vendor/amphp/file/test/ParallelHandleTest.phpo]*^ٶ#vendor/amphp/file/lib/StatCache.phpo]")vendor/amphp/file/lib/Internal/UvPoll.phpo].*vendor/amphp/file/lib/Internal/EioPoll.phpo]h +vendor/amphp/file/lib/Internal/FileTask.phpo]#vendor/amphp/file/lib/EioHandle.php o] ^#vendor/amphp/file/lib/functions.php o] ?ŗ(vendor/amphp/file/lib/BlockingHandle.phpo]—"vendor/amphp/file/lib/UvDriver.php;Ho];H Ӷ vendor/amphp/file/lib/Handle.phpo]V`f(vendor/amphp/file/lib/ParallelHandle.phpMo]M3RyѶ/vendor/amphp/file/lib/PendingOperationError.phpSo]Sxͺ"vendor/amphp/file/lib/UvHandle.phpo]R vendor/amphp/file/lib/Driver.phpo]Ò#vendor/amphp/file/lib/EioDriver.phpDo]D}Ҁ(vendor/amphp/file/lib/BlockingDriver.php[$o][$ ܿ-vendor/amphp/file/lib/FilesystemException.phpo](vendor/amphp/file/lib/ParallelDriver.phpo]<$vendor/amphp/websocket/composer.jsono]Ӿ")vendor/amphp/websocket/test/functions.phpo]'3*vendor/amphp/websocket/test/ClientTest.phpo]>;*vendor/amphp/websocket/test/ParserTest.php(o](y1vendor/amphp/websocket/src/CompressionContext.php4o]4Hs!%vendor/amphp/websocket/src/Opcode.phpo]l98vendor/amphp/websocket/src/Rfc7692CompressionFactory.php7o]7{(vendor/amphp/websocket/src/functions.phpo]4--vendor/amphp/websocket/src/ClientMetadata.php: o]: 8vendor/amphp/websocket/src/CompressionContextFactory.phpuo]u/X%vendor/amphp/websocket/src/Client.phpQo]Q}.vendor/amphp/websocket/src/ClosedException.php{o]{0!#vendor/amphp/websocket/src/Code.phpjo]j5z&vendor/amphp/websocket/src/Options.php.o].J\&vendor/amphp/websocket/src/Message.phpWo]WDY,vendor/amphp/websocket/src/Rfc6455Client.php{zo]{zA{1vendor/amphp/websocket/src/Rfc7692Compression.phpKo]Khڶ"vendor/amphp/process/composer.jsonso]s#M3vendor/amphp/process/lib/Internal/ProcessRunner.phpo]So62vendor/amphp/process/lib/Internal/Posix/Runner.php= o]= }D2vendor/amphp/process/lib/Internal/Posix/Handle.phpo]x.Y4vendor/amphp/process/lib/Internal/Windows/Runner.phpo])Avendor/amphp/process/lib/Internal/Windows/PendingSocketClient.php1o]1+^4vendor/amphp/process/lib/Internal/Windows/Handle.phpo]T=vendor/amphp/process/lib/Internal/Windows/HandshakeStatus.phpo]aض8vendor/amphp/process/lib/Internal/Windows/SignalCode.php]o]]TZ/=vendor/amphp/process/lib/Internal/Windows/SocketConnector.php1o]17\d3vendor/amphp/process/lib/Internal/ProcessHandle.phpo]>f3vendor/amphp/process/lib/Internal/ProcessStatus.phpo]ʍ &vendor/amphp/process/lib/functions.phpgo]gl980vendor/amphp/process/lib/ProcessOutputStream.php: o]: $/vendor/amphp/process/lib/ProcessInputStream.php) o]) U-vendor/amphp/process/lib/ProcessException.phpMo]M$vendor/amphp/process/lib/Process.phpo]4(vendor/amphp/process/lib/StatusError.phpDo]DT9+vendor/amphp/windows-registry/composer.jsonto]tJ;5vendor/amphp/windows-registry/lib/WindowsRegistry.php3o]3K}:vendor/amphp/windows-registry/lib/KeyNotFoundException.phpYo]Y4]-vendor/amphp/http/examples/header-parsing.php&o]&839vendor/amphp/http/examples/benchmark/parser-primitive.phpco]c&7vendor/amphp/http/examples/benchmark/format-rfc7230.phpo] <7vendor/amphp/http/examples/benchmark/parser-rfc7230.php\o]\- ,vendor/amphp/http/examples/header-format.phpo]ߥ%vendor/amphp/http/examples/cookie.phpo]{hZvendor/amphp/http/composer.jsono]k%vendor/amphp/http/test/StatusTest.php7o]7g9&vendor/amphp/http/test/Rfc7230Test.phpo]'Ha6vendor/amphp/http/test/Cookie/CookieAttributesTest.phpo]^g4vendor/amphp/http/test/Cookie/ResponseCookieTest.php#o]#t3vendor/amphp/http/test/Cookie/RequestCookieTest.php o] &vendor/amphp/http/test/MessageTest.php o] /vendor/amphp/http/src/Cookie/ResponseCookie.php%o]%*.vendor/amphp/http/src/Cookie/RequestCookie.php o] 27vendor/amphp/http/src/Cookie/InvalidCookieException.phpo]GB1vendor/amphp/http/src/Cookie/CookieAttributes.phpo]>!vendor/amphp/http/src/Rfc7230.phpAo]AG.h vendor/amphp/http/src/Status.php\o]\ˡ_!vendor/amphp/http/src/Message.phpAo]A0vendor/amphp/http/src/InvalidHeaderException.phpIo]I3vendor/amphp/artax/examples/6-parallel-requests.php?o]?߶/vendor/amphp/artax/examples/2-custom-header.phpo]!R-vendor/amphp/artax/examples/1-get-request.phpo]័5vendor/amphp/artax/examples/5-streaming-responses.php o] .vendor/amphp/artax/examples/7-unix-sockets.phpo]BVc+vendor/amphp/artax/examples/8-benchmark.phpo]~9'vendor/amphp/artax/examples/4-forms.phpo]Eo+vendor/amphp/artax/examples/3-post-body.php o] 6 vendor/amphp/artax/composer.jsono]5vendor/amphp/artax/test/Cookie/ArrayCookieJarTest.phpo]>{#-vendor/amphp/artax/test/Cookie/CookieTest.php|o]|$3vendor/amphp/artax/test/Cookie/ClientCookieTest.phpo]L}X'vendor/amphp/artax/test/RequestTest.phpo]P:2O&vendor/amphp/artax/test/ParserTest.phpo].0vendor/amphp/artax/test/PublicSuffixListTest.php~o]~rA'vendor/amphp/artax/test/TimeoutTest.phpno]n"D8vendor/amphp/artax/test/ClientHttpBinIntegrationTest.phpCo]C{(vendor/amphp/artax/test/FormBodyTest.php o] {&vendor/amphp/artax/lib/RequestBody.phpao]a-+vendor/amphp/artax/lib/TimeoutException.phpNo]N!;#vendor/amphp/artax/lib/Response.php o] v\ }'vendor/amphp/artax/lib/DnsException.phpJo]J?Ͷ0vendor/amphp/artax/lib/Internal/RequestCycle.phpRo]R膂=vendor/amphp/artax/lib/Internal/CombinedCancellationToken.phpo]ȧ*vendor/amphp/artax/lib/Internal/Parser.phpDo]Dg54vendor/amphp/artax/lib/Internal/PublicSuffixList.php o] ϶(vendor/amphp/artax/lib/HttpException.phpHo]HZ/7B"vendor/amphp/artax/lib/TlsInfo.phpo]G5</vendor/amphp/artax/lib/Cookie/NullCookieJar.phpo]!1P 0vendor/amphp/artax/lib/Cookie/ArrayCookieJar.phpo]/vendor/amphp/artax/lib/Cookie/FileCookieJar.phpo]뜶7vendor/amphp/artax/lib/Cookie/CookieFormatException.php2o]2,mV+vendor/amphp/artax/lib/Cookie/CookieJar.php1o]1@T(vendor/amphp/artax/lib/Cookie/Cookie.phpo]bR)vendor/amphp/artax/lib/ConnectionInfo.phpo]v!vendor/amphp/artax/lib/Client.phpeo]eaDL)vendor/amphp/artax/lib/ParseException.phpGo]Gt. #vendor/amphp/artax/lib/MetaInfo.phpo]J(vendor/amphp/artax/lib/DefaultClient.phpo]Pw)vendor/amphp/artax/lib/HttpSocketPool.phpo])4vendor/amphp/artax/lib/TooManyRedirectsException.phpdo]dp%vendor/amphp/artax/lib/StringBody.phpDo]D@#vendor/amphp/artax/lib/FormBody.phpo]]*vendor/amphp/artax/lib/SocketException.phpMo]MIP"vendor/amphp/artax/lib/Request.php o] 8'vendor/amphp/artax/lib/HttpTunneler.php o] #vendor/amphp/artax/lib/FileBody.phpo]@-vendor/amphp/artax/res/public_suffix_list.dato] vendor/amphp/cache/composer.jsonuo]u%)vendor/amphp/cache/lib/CacheException.phpo]ŭ &vendor/amphp/cache/lib/PrefixCache.phpo]C7%vendor/amphp/cache/lib/ArrayCache.php o] l2b vendor/amphp/cache/lib/Cache.phpFo]Fh$vendor/amphp/cache/lib/NullCache.php,o],!ւն6vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php.o]."C92vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.phpo]je8vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php5o]56vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php8o]8D]=vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.phpCo]C )>vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/MSBLOB.phpo];vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/Raw.php o] q";vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/XML.phpo] ?vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/OpenSSH.phpo]M\=vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/PKCS8.phpo]1mǶ;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/PSS.phpo]F=vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/PKCS1.php*o]*x}=vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Keys/PuTTY.phpo]۶<vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php<o]<e`3vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.phpzo]z ?vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/PrivateKey.php o] OEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect571k1.phpZo]Z*EKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP320t1.php=o]=FU/iEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect283r1.phpo]UIEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp224r1.phpo]h)Fvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime192v3.phpgo]gE+Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistp192.phpo]cDvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistp384.phpo]LEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect239k1.php?o]?aBEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect409k1.phpBo]BMq_Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect193r2.php o] HKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP256t1.phpo]1nEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect163r2.phpo])փDvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistp256.phpo]vEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp224k1.phpo]n Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP160r1.phpdo]d}._Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistt571.phpo]YV$kEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect113r2.phpo]טDvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistb233.phpo]uFvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime256v1.phpo]PpDvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistk283.phpo]4#gEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp192r1.php o] Z⹶Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp256k1.phpmo]mmSdEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect571r1.phpZo]Ze?Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistk409.phpo]նAvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/Ed448.phpo] Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistk233.phpo],Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP256r1.phpo]"ahKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP512t1.php^o]^* Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp192k1.phpho]hO2Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistp521.phpo]XkʶKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP512r1.phpTo]T)Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect163k1.phpo]IݶEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp160r2.phpTo]TڽDvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistp224.phpo]Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistk163.phpo]MJ'Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect409r1.phpDo]DFDvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/nistb409.phpo]vUKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP160t1.phpEo]Ef,fEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp112r1.phpo] Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP384t1.phpoo]oz ŶKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP224t1.phpo]UEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect131r2.phpo]1vYEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp384r1.phpo] ͻEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp128r2.php"o]"z\Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp160r1.php7o]7[I@VEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp160k1.phpAo]A3Fvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime192v1.phpo]`$Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp256r1.phpo]5O)Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP224r1.phpo]iչJFvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime239v2.phpo]onHEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp128r1.phpo]UEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp112r2.phpo]GEvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect193r1.php o] 帶Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect131r1.phpo]̓Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect233r1.php<o]<4ŶCvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/Ed25519.php(o](KǶFvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime239v3.phpo]+X۶Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect113r1.phpo](_Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP192t1.phpo]ޑRKvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP192r1.phpo]!Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP320r1.php3o]3 !Kvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/brainpoolP384r1.phpo]f Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect163r1.phpo]=w0Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect233k1.php:o]:?Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/sect283k1.phpo]~B^Fvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime192v2.phpgo]gFvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/prime239v1.phpo]'p*Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Curves/secp521r1.phpo]S+'Cvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/libsodium.phpl o]l S0=vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/XML.phpDo]D=Avendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/OpenSSH.phpko]kt;?vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/PKCS8.phpYo]YI?vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/PKCS1.phpo]5}:@vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/Common.phpK\o]K\޶?vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Keys/PuTTY.php o] Lvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/BaseCurves/KoblitzPrime.php='o]='1Fvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/BaseCurves/Binary.php&o]&;)Dvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/BaseCurves/Base.phpo]=Evendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/BaseCurves/Prime.phpRo]R2MNvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/BaseCurves/TwistedEdwards.phpTo]T?vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Parameters.phpVo]VPs+>vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/PublicKey.phpo];XCvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Signature/SSH2.php o] Bvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Signature/Raw.phpGo]G Cvendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA/Signature/ASN1.phpo]'s2vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.phpa o]a Xl 2vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php`Uo]`U*5vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.phpE$o]E$F)Avendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Fingerprint.php o] R#Gvendor/phpseclib/phpseclib/phpseclib/Crypt/Common/PasswordProtected.phpo][@vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/PrivateKey.phpo]PXiBvendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.phpo]V`Avendor/phpseclib/phpseclib/phpseclib/Crypt/Common/BlockCipher.php[o][Bvendor/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php`o]`ô_Bvendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Keys/OpenSSH.php "o] ";}@vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Keys/PKCS8.phpjao]ja5@vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Keys/PKCS1.phpo]ɔ?vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Keys/PKCS.phpo]x[n@vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Keys/PuTTY.php%o]%ˆ7BCvendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.phpm,o]m,z?vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/PublicKey.phpo]\Cvendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Signature/Raw.phpzo]zBn̶=vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.phpo]z;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Keys/Raw.phpu o]u q;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Keys/XML.phpqo]q'ln&?vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Keys/OpenSSH.php o] ϧ=vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Keys/PKCS8.phpo]7%<=vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Keys/PKCS1.phpoo]o՝=vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Keys/PuTTY.phpo]ޡ=vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Parameters.phpXo]XKn-<vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php o] oAvendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Signature/SSH2.php o] JK@vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Signature/Raw.phpAo]A"Avendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Signature/ASN1.phpo]bgM7vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.phpco]chr2vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.phppWo]pWVm7vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.phpo]͗2vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php$o]$x[̶4vendor/phpseclib/phpseclib/phpseclib/Crypt/ECDSA.php*o]*o7vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.phpzo]zqꅸ2vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php!o]!u>vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.phpo]89vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php!o]!sBvendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php#o]#8ɶ8vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField.php2 o]2 gO9vendor/phpseclib/phpseclib/phpseclib/Math/BinaryField.php&o]&Avendor/phpseclib/phpseclib/phpseclib/Math/BinaryField/Integer.php5o]5PD8vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.phpSo]Sa޶@vendor/phpseclib/phpseclib/phpseclib/Math/Common/FiniteField.phpo]mHvendor/phpseclib/phpseclib/phpseclib/Math/Common/FiniteField/Integer.phpo]b)}Rvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP/DefaultEngine.phpo]$7Wvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php+o]+0ёWvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Classic.phpo]'^vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/MontgomeryMult.php o] t?Zvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Montgomery.php`o]`=$3[vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php=o]=^Zvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/PowerOfTwo.phpo]pJ3Lvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/OpenSSL.phpo]d{Ivendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Base.phpo]DѶRvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/DefaultEngine.phpo]f![Ovendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Montgomery.phpC o]C w Hvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/OpenSSL.phpo]@MDvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php”o]”㙹Zvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.phpo]7V^vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php o] 7Ovendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.phpo]sOvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/OpenSSL.phpo]fAضLvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.phpg o]g ׶Uvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/DefaultEngine.phpo] .#Fvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php&o]&oe׶Dvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.phpQDo]QDT fGvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php Ho] H;~Gvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.phpo]m)Fvendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php&o]&_Z @vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php&o]&½Avendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php,o],!r2vendor/phpseclib/phpseclib/phpseclib/bootstrap.phpho]hUA2vendor/phpseclib/phpseclib/phpseclib/File/X509.php!o]!62vendor/phpseclib/phpseclib/phpseclib/File/ANSI.phpOo]O*x:vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.phpo] ̸Hvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OrganizationName.php?o]?2Ivendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateDomainName.phpo]fDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBKDF2params.phpio]iq-Cvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralName.phpo]8Cvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBES2params.phpo]T< Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RSAPrivateKey.phpo]ʏڶDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EDIPartyName.phpo]KRvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectDirectoryAttributes.phpo]ZEvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EcdsaSigValue.phpo])Bvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/UserNotice.phpo]QJ?vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ECPoint.php o] eNdEvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PostalAddress.phpo]Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ECParameters.phpo] Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NetworkAddress.php7o]7w#Kvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AlgorithmIdentifier.php5o]5FgKvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyQualifierInfo.phpo]7Mvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKeyAndChallenge.phpo]|MMvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateKeyUsagePeriod.phpo](!<vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Name.phpto]t[Gvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NameConstraints.phpo]伡?vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Prime_p.phpo]8螶Mvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DistributionPointName.phpo]e~Hvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/MaskGenAlgorithm.php/o]/UVDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertPolicyId.php4o]4u?vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/FieldID.php o] ܶNvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/netscape_ca_policy_url.phpKo]KewJCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DssSigValue.phpo]aE<vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Time.phpo]жJvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/netscape_cert_type.phpo] ĤJvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Characteristic_two.phpmo]mg"uDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/FieldElement.php/o]/ݶIvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SpecifiedECDomain.phpo]9Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateKeyInfo.phpo]#@Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKeyInfo.phpxo]xLq\Bvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Extensions.php$o]$9XfAvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Trinomial.php o] ?ZCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AnotherName.phpo]OFvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AttributeValue.php,o],7ԝIvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DistributionPoint.phpo]d9QBvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Attributes.phpo]e7ζGvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NoticeReference.phpo]Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/TBSCertificate.php o] ӝJvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RevokedCertificate.phpo]"JVvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BuiltInDomainDefinedAttributes.phpo]dCȶBvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateKey.php)o])#WCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DisplayText.phpgo]g-x5Qvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RelativeDistinguishedName.php(o](P0Mvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CRLDistributionPoints.phpo]0߶Nvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AuthorityKeyIdentifier.phpo]f 6Avendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CRLReason.php.o].'9Bvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DigestInfo.php o] sC|Kvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificatePolicies.phpo][yἶIvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyInformation.php+o]+,Qvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BuiltInStandardAttributes.php o] 5?'Svendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SignedPublicKeyAndChallenge.phpZo]Zl}Ovendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EncryptedPrivateKeyInfo.phpo]q1wAvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CRLNumber.php!o]!o3`=vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Curve.php o] ]Ivendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RSASSA_PSS_params.phpZo]ZޠMvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NumericUserIdentifier.phpLo]L;XKvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ExtensionAttributes.phpo]cmǹCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PKCS9String.phpo]7Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyMappings.phpo]Gvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificateList.php#o]#mLvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificationRequest.phpQo]QO|ж@vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/KeyUsage.phpVo]V۹=Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ECPrivateKey.phpo]4YlJvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ExtensionAttribute.php\o]\Ivendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ExtKeyUsageSyntax.phpo]Ovendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificateSerialNumber.phpKo]KyfoӶGvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DirectoryString.phpo]ևCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Certificate.phpo]¢8{Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EncryptedData.php2o]2kz Kvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/HoldInstructionCode.phpIo]I&Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OtherPrimeInfo.phpco]cbiSDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RSAPublicKey.phpo]Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBEParameter.phpo];3"Cvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/TBSCertList.phpo]Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BaseDistance.php*o]*lLCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Pentanomial.phpo] \Gvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralSubtrees.phpo]gAvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DSAParams.phpo]i[Gvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OtherPrimeInfos.phpo]ꂶCvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ReasonFlags.phpho]h$P6@vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Validity.phpo]Qvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AuthorityInfoAccessSyntax.phpo]nIvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AccessDescription.phpo]>Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DSAPublicKey.php*o]*cOvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OrganizationalUnitNames.phpo] Pvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AdministrationDomainName.phpo] Avendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ORAddress.phpo].?Uvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BuiltInDomainDefinedAttribute.phpo]k^Ivendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyQualifierId.phpCo]CAvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Extension.phpo]A~7Hvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BasicConstraints.php]o]]b Z[Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectAltName.php#o]#0 RMvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AttributeTypeAndValue.phpo]̶Ivendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificateIssuer.php,o],%Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/HashAlgorithm.php&o]&&1zEvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AttributeType.php7o]7"aCFvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralSubtree.phpto]tX#Fvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/InvalidityDate.php9o]9K}Jvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/TerminalIdentifier.phpEo]ENGvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RC2CBCParameter.phpgo]gqCDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/KeyPurposeId.php4o]4%௶Pvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/IssuingDistributionPoint.php o] צPvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificationRequestInfo.phpo](+Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralNames.phpo]9Avendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKey.php$o]$kDvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PersonalName.phpo]s!9Cvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RDNSequence.php^o]^Hvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OneAsymmetricKey.phpo] Lvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectPublicKeyInfo.phpo]nuHvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/netscape_comment.php9o]9>vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CPSuri.phpo]0Hvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/UniqueIdentifier.php9o]9754Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/KeyIdentifier.php2o]2߮Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/IssuerAltName.php o] c^4Cvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CountryName.phpo]Avendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Attribute.phpRo]R]Evendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DSAPrivateKey.phpo]O]Dvendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBMAC1params.phpo] 2vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php&o]&xjNIvendor/phpseclib/phpseclib/phpseclib/Exception/BadDecryptionException.php o] uMvendor/phpseclib/phpseclib/phpseclib/Exception/InconsistentSetupException.php4o]4*%Qvendor/phpseclib/phpseclib/phpseclib/Exception/NoSupportedAlgorithmsException.phpHo]HnPvendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedAlgorithmException.phpCo]C_/Mvendor/phpseclib/phpseclib/phpseclib/Exception/InsufficientSetupException.php4o]4DNLvendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedCurveException.php/o]/,9@Cvendor/phpseclib/phpseclib/phpseclib/Exception/BadModeException.phpo]ϔLvendor/phpseclib/phpseclib/phpseclib/Exception/BadConfigurationException.php/o]/.Gvendor/phpseclib/phpseclib/phpseclib/Exception/NoKeyLoadedException.phpo],Mvendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedFormatException.php4o]4Hvendor/phpseclib/phpseclib/phpseclib/Exception/FileNotFoundException.phpo]GPvendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedOperationException.phpCo]CF|1vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.phpHo]H1vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.phpo]|o]>'*vendor/league/uri-parser/src/functions.php4 o]4 >X'vendor/league/uri-parser/src/Parser.phpzZo]zZ*vendor/league/uri-parser/src/Exception.php o] 3~2vendor/league/uri-parser/src/MissingIdnSupport.phpo]Z?2vendor/league/uri-parser/src/functions_include.phpo]a]l'vendor/league/uri-schemes/composer.jsono]wE2Cvendor/league/uri-schemes/benchmark/http-create-from-components.phpo]9$vendor/league/uri-schemes/src/Ws.php[o][15+vendor/league/uri-schemes/src/functions.phpUo]U"e!&vendor/league/uri-schemes/src/Http.phpCo]CtU%vendor/league/uri-schemes/src/Uri.phpo]Pm%&vendor/league/uri-schemes/src/Data.phpo]ض%vendor/league/uri-schemes/src/Ftp.phpJo]J4-vendor/league/uri-schemes/src/AbstractUri.php!o]! &vendor/league/uri-schemes/src/File.phpo]IS,vendor/league/uri-schemes/src/Schemes/Ws.phpPo]PR4vendor/league/uri-schemes/src/Schemes/deprecated.phpHo]Hr.vendor/league/uri-schemes/src/Schemes/Http.phpRo]Rbpz-vendor/league/uri-schemes/src/Schemes/Uri.phpIo]I#.vendor/league/uri-schemes/src/Schemes/Data.phpRo]RqՖ-vendor/league/uri-schemes/src/Schemes/Ftp.phpQo]QK:k5vendor/league/uri-schemes/src/Schemes/AbstractUri.phpYo]Y.T޶.vendor/league/uri-schemes/src/Schemes/File.phpRo]R1u6vendor/league/uri-schemes/src/Schemes/UriException.phpZo]ZH8fk.vendor/league/uri-schemes/src/UriException.phpo]iD)vendor/league/uri-schemes/src/Factory.php'o]'M3vendor/league/uri-schemes/src/functions_include.phpko]kt'vendor/symfony/polyfill-ctype/Ctype.php}o]}\谶+vendor/symfony/polyfill-ctype/composer.json\o]\ն+vendor/symfony/polyfill-ctype/bootstrap.phpSo]S7%vendor/vlucas/phpdotenv/composer.json$o]$|Dvendor/vlucas/phpdotenv/src/Environment/Adapter/AdapterInterface.phpo]"Avendor/vlucas/phpdotenv/src/Environment/Adapter/ApacheAdapter.phpQo]Q @vendor/vlucas/phpdotenv/src/Environment/Adapter/ArrayAdapter.phpo]MOCvendor/vlucas/phpdotenv/src/Environment/Adapter/EnvConstAdapter.phpo]|˶Fvendor/vlucas/phpdotenv/src/Environment/Adapter/ServerConstAdapter.php'o]'+Avendor/vlucas/phpdotenv/src/Environment/Adapter/PutenvAdapter.phpo]ƶ9vendor/vlucas/phpdotenv/src/Environment/DotenvFactory.phpZo]Z\C=vendor/vlucas/phpdotenv/src/Environment/AbstractVariables.phpBo]B{ڶ<vendor/vlucas/phpdotenv/src/Environment/FactoryInterface.php]o]]58>vendor/vlucas/phpdotenv/src/Environment/VariablesInterface.phpNo]NS>E;vendor/vlucas/phpdotenv/src/Environment/DotenvVariables.phpo]6 &%vendor/vlucas/phpdotenv/src/Lines.php o] SV&vendor/vlucas/phpdotenv/src/Parser.php;o];|)vendor/vlucas/phpdotenv/src/Validator.php3o]3N8+vendor/vlucas/phpdotenv/src/Regex/Error.phpeo]e`-vendor/vlucas/phpdotenv/src/Regex/Success.phpjo]jO+,vendor/vlucas/phpdotenv/src/Regex/Result.phpo]%+vendor/vlucas/phpdotenv/src/Regex/Regex.phpB o]B Q&vendor/vlucas/phpdotenv/src/Loader.phpo]a&vendor/vlucas/phpdotenv/src/Dotenv.php o] q8h<vendor/vlucas/phpdotenv/src/Exception/ExceptionInterface.phpxo]xlO>vendor/vlucas/phpdotenv/src/Exception/InvalidFileException.phpo]u9¶>vendor/vlucas/phpdotenv/src/Exception/InvalidPathException.phpo]=vendor/vlucas/phpdotenv/src/Exception/ValidationException.phpo] (vendor/phpoption/phpoption/composer.jsonJo]JWk7vendor/phpoption/phpoption/src/PhpOption/LazyOption.phpo]b3vendor/phpoption/phpoption/src/PhpOption/Option.php*+o]*+6h1vendor/phpoption/phpoption/src/PhpOption/Some.php~ o]~ ϕ 1vendor/phpoption/phpoption/src/PhpOption/None.php o] hi,vendor/paragonie/random_compat/composer.jsono];ǻ1vendor/paragonie/random_compat/lib/random_int.php;o];dM=vendor/paragonie/random_compat/lib/random_bytes_libsodium.php o] iᦶDvendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.phpl o]l bZ >vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php o] ?vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php6o]6!Kw-vendor/paragonie/random_compat/lib/random.php o]  ö5vendor/paragonie/random_compat/lib/error_polyfill.php~o]~bi:vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php- o]- ?Ӷ2vendor/paragonie/random_compat/lib/cast_to_int.php o] "0R8vendor/paragonie/random_compat/lib/byte_safe_strings.phpo];5vendor/paragonie/constant_time_encoding/composer.jsono]8vendor/paragonie/constant_time_encoding/src/Encoding.phpo],9Ķ@vendor/paragonie/constant_time_encoding/src/EncoderInterface.php5o]5i'6vendor/paragonie/constant_time_encoding/src/Binary.php o] @9_3vendor/paragonie/constant_time_encoding/src/Hex.phpTo]T)=vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.phpn o]n m~B7vendor/paragonie/constant_time_encoding/src/RFC4648.phpo]<>vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php o] oN89vendor/paragonie/constant_time_encoding/src/Base32Hex.php o] s36vendor/paragonie/constant_time_encoding/src/Base32.phpN8o]N8r6vendor/paragonie/constant_time_encoding/src/Base64.php o] REvendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php o] oz/(vendor/kelunik/certificate/composer.jsonSo]SR=vendor/kelunik/certificate/lib/FieldNotSupportedException.php`o]`\*vendor/kelunik/certificate/lib/Profile.php<o]<ƗBŶ>vendor/kelunik/certificate/lib/InvalidCertificateException.phpao]aWZֶ.vendor/kelunik/certificate/lib/Certificate.phpo]lf%׶"vendor/cash/lrucache/composer.jsono]>8Ѷ*vendor/cash/lrucache/src/cash/LRUCache.php o] dܶvendor/autoload.phpo]vv} composer.jsonuo]uȚ1vendor/danog/madelineproto/.git/refs/heads/master(o](15N.git/refs/heads/master(o](15N * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 1.0.0 */ namespace LibDNS\Examples; use \LibDNS\Messages\MessageFactory; use \LibDNS\Messages\MessageTypes; use \LibDNS\Records\QuestionFactory; use \LibDNS\Records\ResourceTypes; use \LibDNS\Records\ResourceQTypes; use \LibDNS\Encoder\EncoderFactory; use \LibDNS\Decoder\DecoderFactory; use \LibDNS\Records\TypeDefinitions\TypeDefinitionManagerFactory; // Config $queryName = 'google.com'; $serverIP = '8.8.8.8'; $requestTimeout = 3; require __DIR__ . '/autoload.php'; // Create question record $question = (new QuestionFactory)->create(ResourceQTypes::SOA); $question->setName($queryName); // Create request message $request = (new MessageFactory)->create(MessageTypes::QUERY); $request->getQuestionRecords()->add($question); $request->isRecursionDesired(true); // Encode request message $encoder = (new EncoderFactory)->create(); $requestPacket = $encoder->encode($request); echo "\n" . $queryName . ":\n"; // Send request $socket = stream_socket_client("udp://$serverIP:53"); stream_socket_sendto($socket, $requestPacket); $r = [$socket]; $w = $e = []; if (!stream_select($r, $w, $e, $requestTimeout)) { echo " Request timeout.\n"; exit; } // Create type definition manager for custom manipulation $typeDefs = (new TypeDefinitionManagerFactory)->create(); $typeDefs->getTypeDefinition(ResourceTypes::SOA)->setToStringFunction(function($mname, $rname, $serial, $refresh, $retry, $expire, $minimum) { return <<create($typeDefs); $responsePacket = fread($socket, 512); $response = $decoder->decode($responsePacket); // Handle response if ($response->getResponseCode() !== 0) { echo " Server returned error code " . $response->getResponseCode() . ".\n"; exit; } $answers = $response->getAnswerRecords(); if (count($answers)) { foreach ($response->getAnswerRecords() as $record) { /** @var \LibDNS\Records\Resource $record */ echo " " . $record->getData() . "\n"; } } else { echo " Not found.\n"; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 1.0.0 */ namespace LibDNS\Examples; use \LibDNS\Messages\MessageFactory; use \LibDNS\Messages\MessageTypes; use \LibDNS\Records\QuestionFactory; use \LibDNS\Records\ResourceQTypes; use \LibDNS\Encoder\EncoderFactory; use \LibDNS\Decoder\DecoderFactory; // Config $queryName = 'faß.de'; $serverIP = '8.8.8.8'; $requestTimeout = 3; require __DIR__ . '/autoload.php'; // Create question record $question = (new QuestionFactory)->create(ResourceQTypes::A); $question->setName($queryName); // Create request message $request = (new MessageFactory)->create(MessageTypes::QUERY); $request->getQuestionRecords()->add($question); $request->isRecursionDesired(true); // Encode request message $encoder = (new EncoderFactory)->create(); $requestPacket = $encoder->encode($request); echo "\n" . $queryName . ":\n"; // Send request $socket = stream_socket_client("udp://$serverIP:53"); stream_socket_sendto($socket, $requestPacket); $r = [$socket]; $w = $e = []; if (!stream_select($r, $w, $e, $requestTimeout)) { echo " Request timeout.\n"; exit; } // Decode response message $decoder = (new DecoderFactory)->create(); $responsePacket = fread($socket, 512); $response = $decoder->decode($responsePacket); // Handle response if ($response->getResponseCode() !== 0) { echo " Server returned error code " . $response->getResponseCode() . ".\n"; exit; } $answers = $response->getAnswerRecords(); if (count($answers)) { foreach ($response->getAnswerRecords() as $record) { /** @var \LibDNS\Records\Resource $record */ echo " " . $record->getData() . "\n"; } } else { echo " Not found.\n"; } __DIR__ . '/../src/Decoder/Decoder.php', 'libdns\decoder\decoderfactory' => __DIR__ . '/../src/Decoder/DecoderFactory.php', 'libdns\decoder\decodingcontext' => __DIR__ . '/../src/Decoder/DecodingContext.php', 'libdns\decoder\decodingcontextfactory' => __DIR__ . '/../src/Decoder/DecodingContextFactory.php', 'libdns\encoder\encoder' => __DIR__ . '/../src/Encoder/Encoder.php', 'libdns\encoder\encoderfactory' => __DIR__ . '/../src/Encoder/EncoderFactory.php', 'libdns\encoder\encodingcontext' => __DIR__ . '/../src/Encoder/EncodingContext.php', 'libdns\encoder\encodingcontextfactory' => __DIR__ . '/../src/Encoder/EncodingContextFactory.php', 'libdns\enumeration' => __DIR__ . '/../src/Enumeration.php', 'libdns\messages\message' => __DIR__ . '/../src/Messages/Message.php', 'libdns\messages\messagefactory' => __DIR__ . '/../src/Messages/MessageFactory.php', 'libdns\messages\messageopcodes' => __DIR__ . '/../src/Messages/MessageOpCodes.php', 'libdns\messages\messageresponsecodes' => __DIR__ . '/../src/Messages/MessageResponseCodes.php', 'libdns\messages\messagetypes' => __DIR__ . '/../src/Messages/MessageTypes.php', 'libdns\packets\labelregistry' => __DIR__ . '/../src/Packets/LabelRegistry.php', 'libdns\packets\packet' => __DIR__ . '/../src/Packets/Packet.php', 'libdns\packets\packetfactory' => __DIR__ . '/../src/Packets/PacketFactory.php', 'libdns\records\question' => __DIR__ . '/../src/Records/Question.php', 'libdns\records\questionfactory' => __DIR__ . '/../src/Records/QuestionFactory.php', 'libdns\records\rdata' => __DIR__ . '/../src/Records/RData.php', 'libdns\records\rdatabuilder' => __DIR__ . '/../src/Records/RDataBuilder.php', 'libdns\records\rdatafactory' => __DIR__ . '/../src/Records/RDataFactory.php', 'libdns\records\record' => __DIR__ . '/../src/Records/Record.php', 'libdns\records\recordcollection' => __DIR__ . '/../src/Records/RecordCollection.php', 'libdns\records\recordcollectionfactory' => __DIR__ . '/../src/Records/RecordCollectionFactory.php', 'libdns\records\recordtypes' => __DIR__ . '/../src/Records/RecordTypes.php', 'libdns\records\resource' => __DIR__ . '/../src/Records/Resource.php', 'libdns\records\resourcebuilder' => __DIR__ . '/../src/Records/ResourceBuilder.php', 'libdns\records\resourcebuilderfactory' => __DIR__ . '/../src/Records/ResourceBuilderFactory.php', 'libdns\records\resourceclasses' => __DIR__ . '/../src/Records/ResourceClasses.php', 'libdns\records\resourcefactory' => __DIR__ . '/../src/Records/ResourceFactory.php', 'libdns\records\resourceqclasses' => __DIR__ . '/../src/Records/ResourceQClasses.php', 'libdns\records\resourceqtypes' => __DIR__ . '/../src/Records/ResourceQTypes.php', 'libdns\records\resourcetypes' => __DIR__ . '/../src/Records/ResourceTypes.php', 'libdns\records\typedefinitions\fielddefinition' => __DIR__ . '/../src/Records/TypeDefinitions/FieldDefinition.php', 'libdns\records\typedefinitions\fielddefinitionfactory' => __DIR__ . '/../src/Records/TypeDefinitions/FieldDefinitionFactory.php', 'libdns\records\typedefinitions\typedefinition' => __DIR__ . '/../src/Records/TypeDefinitions/TypeDefinition.php', 'libdns\records\typedefinitions\typedefinitionfactory' => __DIR__ . '/../src/Records/TypeDefinitions/TypeDefinitionFactory.php', 'libdns\records\typedefinitions\typedefinitionmanager' => __DIR__ . '/../src/Records/TypeDefinitions/TypeDefinitionManager.php', 'libdns\records\typedefinitions\typedefinitionmanagerfactory' => __DIR__ . '/../src/Records/TypeDefinitions/TypeDefinitionManagerFactory.php', 'libdns\records\types\anything' => __DIR__ . '/../src/Records/Types/Anything.php', 'libdns\records\types\bitmap' => __DIR__ . '/../src/Records/Types/BitMap.php', 'libdns\records\types\char' => __DIR__ . '/../src/Records/Types/Char.php', 'libdns\records\types\characterstring' => __DIR__ . '/../src/Records/Types/CharacterString.php', 'libdns\records\types\domainname' => __DIR__ . '/../src/Records/Types/DomainName.php', 'libdns\records\types\ipv4address' => __DIR__ . '/../src/Records/Types/IPv4Address.php', 'libdns\records\types\ipv6address' => __DIR__ . '/../src/Records/Types/IPv6Address.php', 'libdns\records\types\long' => __DIR__ . '/../src/Records/Types/Long.php', 'libdns\records\types\short' => __DIR__ . '/../src/Records/Types/Short.php', 'libdns\records\types\type' => __DIR__ . '/../src/Records/Types/Type.php', 'libdns\records\types\typebuilder' => __DIR__ . '/../src/Records/Types/TypeBuilder.php', 'libdns\records\types\typefactory' => __DIR__ . '/../src/Records/Types/TypeFactory.php', 'libdns\records\types\types' => __DIR__ . '/../src/Records/Types/Types.php', ]; } $className = strtolower($className); if (isset($classMap[$className])) { /** @noinspection PhpIncludeInspection */ require $classMap[$className]; } }); { "name": "daverandom/libdns", "description": "DNS protocol implementation written in pure PHP", "license": "MIT", "keywords": ["dns"], "require": { "php": ">=7.0", "ext-ctype": "*" }, "autoload": { "psr-4": { "LibDNS\\": "src/" }, "files": ["src/functions.php"] }, "support": { "issues": "https://github.com/DaveRandom/LibDNS/issues" }, "suggest": { "ext-intl": "Required for IDN support" } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 1.0.0 */ namespace LibDNS\Tools; use \RecursiveIteratorIterator; use \RecursiveDirectoryIterator; use \FilesystemIterator; error_reporting(0); ini_set('display_errors', 0); if (!isset($argv[1])) { $srcDir = getcwd(); } else if (in_array(strtolower($argv[1]), ['--help', '?', '/?'])) { exit("Syntax: " . __FILE__ . " [source directory]\n"); } else if (!is_dir($srcDir = $argv[1])) { exit("Invalid source directory\n\nSyntax: " . __FILE__ . " [source directory]\n"); } $srcDir = str_replace('\\', '/', $srcDir); $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $srcDir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS ) ); $items = []; $stripLength = strlen($srcDir) + 1; $maxLength = 0; foreach ($iterator as $item) { if ($item->isFile() && $item->getFilename() !== 'autoload.php' && strtolower($item->getExtension()) === 'php') { $classPath = substr($item->getPath() . '\\' . $item->getBasename('.' . $item->getExtension()), $stripLength); $lookupName = strtolower(str_replace('/', '\\', $classPath)); $loadPath = "__DIR__ . '/$srcDir/" . str_replace('\\', '/', $classPath) . ".php'"; $length = strlen($classPath); if ($length > $maxLength) { $maxLength = $length; } $items[$lookupName] = $loadPath; } } unset($iterator); $output = <<<'PHP' $loadPath) { $output .= "\n " . str_pad("'" . $lookupName . "'", $maxLength, ' ', STR_PAD_RIGHT) . " => $loadPath,"; } $output .= <<<'PHP' ]; } $className = strtolower($className); if (isset($classMap[$className])) { /** @noinspection PhpIncludeInspection */ require $classMap[$className]; } }); PHP; file_put_contents(getcwd() . '/autoload.php', $output); * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\Type; use \LibDNS\Records\TypeDefinitions\TypeDefinition; /** * Represents a data type comprising multiple simple types * * @category LibDNS * @package Records * @author Chris Wright */ class RData implements \IteratorAggregate, \Countable { /** * @var \LibDNS\Records\Types\Type[] The items that make up the complex type */ private $fields = []; /** * @var \LibDNS\Records\TypeDefinitions\TypeDefinition Structural definition of the fields */ private $typeDef; /** * Constructor * * @param \LibDNS\Records\TypeDefinitions\TypeDefinition $typeDef */ public function __construct(TypeDefinition $typeDef) { $this->typeDef = $typeDef; } /** * Magic method for type coersion to string * * @return string */ public function __toString() { if ($handler = $this->typeDef->getToStringFunction()) { $result = \call_user_func_array($handler, $this->fields); } else { $result = \implode(',', $this->fields); } return $result; } /** * Get the field indicated by the supplied index * * @param int $index * @return \LibDNS\Records\Types\Type * @throws \OutOfBoundsException When the supplied index does not refer to a valid field */ public function getField(int $index) { if (!isset($this->fields[$index])) { throw new \OutOfBoundsException('Index ' . $index . ' does not refer to a valid field'); } return $this->fields[$index]; } /** * Set the field indicated by the supplied index * * @param int $index * @param \LibDNS\Records\Types\Type $value * @throws \InvalidArgumentException When the supplied index/value pair does not match the type definition */ public function setField(int $index, Type $value) { if (!$this->typeDef->getFieldDefinition($index)->assertDataValid($value)) { throw new \InvalidArgumentException('The supplied value is not valid for the specified index'); } $this->fields[$index] = $value; } /** * Get the field indicated by the supplied name * * @param string $name * @return \LibDNS\Records\Types\Type * @throws \OutOfBoundsException When the supplied name does not refer to a valid field */ public function getFieldByName(string $name): Type { return $this->getField($this->typeDef->getFieldIndexByName($name)); } /** * Set the field indicated by the supplied name * * @param string $name * @param \LibDNS\Records\Types\Type $value * @throws \OutOfBoundsException When the supplied name does not refer to a valid field * @throws \InvalidArgumentException When the supplied value does not match the type definition */ public function setFieldByName(string $name, Type $value) { $this->setField($this->typeDef->getFieldIndexByName($name), $value); } /** * Get the structural definition of the fields * * @return \LibDNS\Records\TypeDefinitions\TypeDefinition */ public function getTypeDefinition(): TypeDefinition { return $this->typeDef; } /** * Retrieve an iterator (IteratorAggregate interface) * * @return \Iterator */ public function getIterator(): \Iterator { return new \ArrayIterator($this->fields); } /** * Get the number of fields (Countable interface) * * @return int */ public function count(): int { return \count($this->fields); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; /** * Enumeration of possible resource QTYPE values * * @category LibDNS * @package Records * @author Chris Wright */ final class ResourceQTypes extends ResourceTypes { const AXFR = 252; const MAILB = 253; const MAILA = 254; const ALL = 255; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\TypeFactory; /** * Creates Resource objects * * @category LibDNS * @package Records * @author Chris Wright */ class ResourceFactory { /** * Create a new Resource object * * @param int $type Can be indicated using the ResourceTypes enum * @param \LibDNS\Records\RData $data * @return \LibDNS\Records\Resource */ public function create(int $type, RData $data): Resource { return new Resource(new TypeFactory, $type, $data); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\TypeFactory; /** * Represents a DNS question record * * @category LibDNS * @package Records * @author Chris Wright */ class Question extends Record { /** * Constructor * * @param \LibDNS\Records\Types\TypeFactory $typeFactory * @param int $type Resource type being requested, can be indicated using the ResourceQTypes enum */ public function __construct(TypeFactory $typeFactory, int $type) { $this->typeFactory = $typeFactory; $this->type = $type; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\TypeFactory; /** * Represents a DNS resource record * * @category LibDNS * @package Records * @author Chris Wright */ class Resource extends Record { /** * @var int Value of the resource's time-to-live property */ private $ttl; /** * @var \LibDNS\Records\RData */ private $data; /** * Constructor * * @param \LibDNS\Records\Types\TypeFactory $typeFactory * @param int $type Can be indicated using the ResourceTypes enum * @param \LibDNS\Records\RData $data */ public function __construct(TypeFactory $typeFactory, int $type, RData $data) { $this->typeFactory = $typeFactory; $this->type = $type; $this->data = $data; } /** * Get the value of the record TTL field * * @return int */ public function getTTL(): int { return $this->ttl; } /** * Set the value of the record TTL field * * @param int $ttl The new value * @throws \RangeException When the supplied value is outside the valid range 0 - 4294967296 */ public function setTTL(int $ttl) { if ($ttl < 0 || $ttl > 4294967296) { throw new \RangeException('Record class must be in the range 0 - 4294967296'); } $this->ttl = $ttl; } /** * Get the value of the resource data field * * @return \LibDNS\Records\RData */ public function getData(): RData { return $this->data; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Enumeration; /** * Enumeration of possible resource CLASS values * * @category LibDNS * @package Records * @author Chris Wright */ abstract class ResourceClasses extends Enumeration { const IN = 1; const CS = 2; const CH = 3; const HS = 4; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\TypeDefinitions\TypeDefinitionManager; /** * Builds Resource objects of a specific type * * @category LibDNS * @package Records * @author Chris Wright */ class ResourceBuilder { /** * @var \LibDNS\Records\ResourceFactory */ private $resourceFactory; /** * @var \LibDNS\Records\RDataBuilder */ private $rDataBuilder; /** * @var \LibDNS\Records\TypeDefinitions\TypeDefinitionManager */ private $typeDefinitionManager; /** * Constructor * * @param \LibDNS\Records\ResourceFactory $resourceFactory * @param \LibDNS\Records\RDataBuilder $rDataBuilder * @param \LibDNS\Records\TypeDefinitions\TypeDefinitionManager $typeDefinitionManager */ public function __construct(ResourceFactory $resourceFactory, RDataBuilder $rDataBuilder, TypeDefinitionManager $typeDefinitionManager) { $this->resourceFactory = $resourceFactory; $this->rDataBuilder = $rDataBuilder; $this->typeDefinitionManager = $typeDefinitionManager; } /** * Create a new Resource object * * @param int $type Type of the resource, can be indicated using the ResourceTypes enum * @return \LibDNS\Records\Resource */ public function build(int $type): Resource { $typeDefinition = $this->typeDefinitionManager->getTypeDefinition($type); $rData = $this->rDataBuilder->build($typeDefinition); return $this->resourceFactory->create($type, $rData); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Enumeration; /** * Enumeration of possible resource TYPE values * * @category LibDNS * @package Records * @author Chris Wright */ abstract class ResourceTypes extends Enumeration { const A = 1; const AAAA = 28; const AFSDB = 18; // const APL = 42; const CAA = 257; const CERT = 37; const CNAME = 5; const DHCID = 49; const DLV = 32769; const DNAME = 39; const DNSKEY = 48; const DS = 43; const HINFO = 13; // const HIP = 55; // const IPSECKEY = 45; const KEY = 25; const KX = 36; const ISDN = 20; const LOC = 29; const MB = 7; const MD = 3; const MF = 4; const MG = 8; const MINFO = 14; const MR = 9; const MX = 15; const NAPTR = 35; const NS = 2; // const NSEC = 47; // const NSEC3 = 50; // const NSEC3PARAM = 50; const NULL = 10; const PTR = 12; const RP = 17; // const RRSIG = 46; const RT = 21; const SIG = 24; const SOA = 6; const SPF = 99; const SRV = 33; const TXT = 16; const WKS = 11; const X25 = 19; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\TypeFactory; /** * Creates Question objects * * @category LibDNS * @package Records * @author Chris Wright */ class QuestionFactory { /** * Create a new Question object * * @param int $type The resource type * @return \LibDNS\Records\Question */ public function create(int $type): Question { return new Question(new TypeFactory, $type); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\TypeDefinitions; use \LibDNS\Records\Types\Type; use \LibDNS\Records\Types\Anything; use \LibDNS\Records\Types\BitMap; use \LibDNS\Records\Types\Char; use \LibDNS\Records\Types\CharacterString; use \LibDNS\Records\Types\DomainName; use \LibDNS\Records\Types\IPv4Address; use \LibDNS\Records\Types\IPv6Address; use \LibDNS\Records\Types\Long; use \LibDNS\Records\Types\Short; use \LibDNS\Records\Types\Types; /** * Defines a field in a type * * @category LibDNS * @package TypeDefinitions * @author Chris Wright */ class FieldDefinition { /** * @var int */ private $index; /** * @var string */ private $name; /** * @var int */ private $type; /** * @var bool */ private $allowsMultiple; /** * @var int */ private $minimumValues; /** * Constructor * * @param int $index * @param string $name * @param int $type * @param bool $allowsMultiple * @param int $minimumValues */ public function __construct(int $index, string $name, int $type, bool $allowsMultiple, int $minimumValues) { $this->index = $index; $this->name = $name; $this->type = $type; $this->allowsMultiple = $allowsMultiple; $this->minimumValues = $minimumValues; } /** * Get the index of the field in the containing type * * @return int */ public function getIndex(): int { return $this->index; } /** * Get the name of the field * * @return string */ public function getName(): string { return $this->name; } /** * Get the type of the field * * @return int */ public function getType(): int { return $this->type; } /** * Determine whether the field allows multiple values * * @return bool */ public function allowsMultiple(): bool { return $this->allowsMultiple; } /** * Get the minimum number of values for the field * * @return int */ public function getMinimumValues(): int { return $this->minimumValues; } /** * Assert that a Type object is valid for this field * * @param \LibDNS\Records\Types\Type * @return bool */ public function assertDataValid(Type $value): bool { return (($this->type & Types::ANYTHING) && $value instanceof Anything) || (($this->type & Types::BITMAP) && $value instanceof BitMap) || (($this->type & Types::CHAR) && $value instanceof Char) || (($this->type & Types::CHARACTER_STRING) && $value instanceof CharacterString) || (($this->type & Types::DOMAIN_NAME) && $value instanceof DomainName) || (($this->type & Types::IPV4_ADDRESS) && $value instanceof IPv4Address) || (($this->type & Types::IPV6_ADDRESS) && $value instanceof IPv6Address) || (($this->type & Types::LONG) && $value instanceof Long) || (($this->type & Types::SHORT) && $value instanceof Short); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\TypeDefinitions; /** * Creates TypeDefinition objects * * @category LibDNS * @package TypeDefinitions * @author Chris Wright */ class TypeDefinitionFactory { /** * Create a new TypeDefinition object * * @param FieldDefinitionFactory $fieldDefinitionFactory * @param int[] $definition Structural definition of the fields * @return \LibDNS\Records\TypeDefinitions\TypeDefinition * @throws \InvalidArgumentException When the type definition is invalid */ public function create(FieldDefinitionFactory $fieldDefinitionFactory, array $definition): TypeDefinition { return new TypeDefinition($fieldDefinitionFactory, $definition); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\TypeDefinitions; /** * Creates FieldDefinition objects * * @category LibDNS * @package TypeDefinitions * @author Chris Wright */ class FieldDefinitionFactory { /** * Create a new FieldDefinition object * * @param int $index * @param string $name * @param int $type * @param bool $allowsMultiple * @param int $minimumValues * @return \LibDNS\Records\TypeDefinitions\FieldDefinition */ public function create(int $index, string $name, int $type, bool $allowsMultiple, int $minimumValues): FieldDefinition { return new FieldDefinition($index, $name, $type, $allowsMultiple, $minimumValues); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\TypeDefinitions; /** * Defines a data type comprising multiple fields * * @category LibDNS * @package TypeDefinitions * @author Chris Wright */ class TypeDefinition implements \IteratorAggregate, \Countable { /** * @var FieldDefinitionFactory Creates FieldDefinition objects */ private $fieldDefFactory; /** * @var int Number of fields in the type */ private $fieldCount; /** * @var \LibDNS\Records\TypeDefinitions\FieldDefinition The last field defined by the type */ private $lastField; /** * @var int[] Map of field indexes to type identifiers */ private $fieldDefs = []; /** * @var int[] Map of field names to indexes */ private $fieldNameMap = []; /** * @var callable Custom implementation for __toString() handling */ private $toStringFunction; /** * Constructor * * @param FieldDefinitionFactory $fieldDefFactory * @param array $definition Structural definition of the fields * @throws \InvalidArgumentException When the type definition is invalid */ public function __construct(FieldDefinitionFactory $fieldDefFactory, array $definition) { $this->fieldDefFactory = $fieldDefFactory; if (isset($definition['__toString'])) { if (!\is_callable($definition['__toString'])) { throw new \InvalidArgumentException('Invalid type definition: __toString() implementation is not callable'); } $this->toStringFunction = $definition['__toString']; unset($definition['__toString']); } $this->fieldCount = \count($definition); $index = 0; foreach ($definition as $name => $type) { $this->registerField($index++, $name, $type); } } /** * Register a field from the type definition * * @param int $index * @param string $name * @param int $type * @throws \InvalidArgumentException When the field definition is invalid */ private function registerField(int $index, string $name, int $type) { if (!\preg_match('/^(?P[\w\-]+)(?P\+|\*)?(?P(?<=\+)\d+)?$/', \strtolower($name), $matches)) { throw new \InvalidArgumentException('Invalid field definition ' . $name . ': Syntax error'); } if (isset($matches['quantifier'])) { if ($index !== $this->fieldCount - 1) { throw new \InvalidArgumentException('Invalid field definition ' . $name . ': Quantifiers only allowed in last field'); } if (!isset($matches['minimum'])) { $matches['minimum'] = $matches['quantifier'] === '+' ? 1 : 0; } $allowsMultiple = true; $minimumValues = (int) $matches['minimum']; } else { $allowsMultiple = false; $minimumValues = 0; } $this->fieldDefs[$index] = $this->fieldDefFactory->create($index, $matches['name'], $type, $allowsMultiple, $minimumValues); if ($index === $this->fieldCount - 1) { $this->lastField = $this->fieldDefs[$index]; } $this->fieldNameMap[$matches['name']] = $index; } /** * Get the field definition indicated by the supplied index * * @param int $index * @return \LibDNS\Records\TypeDefinitions\FieldDefinition * @throws \OutOfBoundsException When the supplied index does not refer to a valid field */ public function getFieldDefinition(int $index): FieldDefinition { if (isset($this->fieldDefs[$index])) { $fieldDef = $this->fieldDefs[$index]; } else if ($index >= 0 && $this->lastField->allowsMultiple()) { $fieldDef = $this->lastField; } else { throw new \OutOfBoundsException('Index ' . $index . ' does not refer to a valid field'); } return $fieldDef; } /** * Get the field index indicated by the supplied name * * @param string $name * @return int * @throws \OutOfBoundsException When the supplied name does not refer to a valid field */ public function getFieldIndexByName($name): int { $fieldName = \strtolower($name); if (!isset($this->fieldNameMap[$fieldName])) { throw new \OutOfBoundsException('Name ' . $name . ' does not refer to a valid field'); } return $this->fieldNameMap[$fieldName]; } /** * Get the __toString() implementation * * @return callable|null */ public function getToStringFunction() { return $this->toStringFunction; } /** * Set the __toString() implementation * * @param callable $function */ public function setToStringFunction(callable $function) { $this->toStringFunction = $function; } /** * Retrieve an iterator (IteratorAggregate interface) * * @return \Iterator */ public function getIterator(): \Iterator { return new \ArrayIterator($this->fieldDefs); } /** * Get the number of fields (Countable interface) * * @return int */ public function count(): int { return $this->fieldCount; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\TypeDefinitions; /** * Creates TypeDefinitionManager objects * * @category LibDNS * @package TypeDefinitions * @author Chris Wright */ class TypeDefinitionManagerFactory { /** * Create a new TypeDefinitionManager object * * @return \LibDNS\Records\TypeDefinitions\TypeDefinitionManager */ public function create(): TypeDefinitionManager { return new TypeDefinitionManager(new TypeDefinitionFactory, new FieldDefinitionFactory); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\TypeDefinitions; use \LibDNS\Records\ResourceTypes; use \LibDNS\Records\Types\Types; use \LibDNS\Records\Types\DomainName; /** * Holds data about how the RDATA sections of known resource record types are structured * * @category LibDNS * @package TypeDefinitions * @author Chris Wright */ class TypeDefinitionManager { /** * @var array[] How the RDATA sections of known resource record types are structured */ private $definitions = []; /** * @var array Cache of created definitions */ private $typeDefs = []; /** * @var \LibDNS\Records\TypeDefinitions\TypeDefinitionFactory */ private $typeDefFactory; /** * @var \LibDNS\Records\TypeDefinitions\FieldDefinitionFactory */ private $fieldDefFactory; /** * Constructor * * @param \LibDNS\Records\TypeDefinitions\TypeDefinitionFactory $typeDefFactory * @param \LibDNS\Records\TypeDefinitions\FieldDefinitionFactory $fieldDefFactory */ public function __construct(TypeDefinitionFactory $typeDefFactory, FieldDefinitionFactory $fieldDefFactory) { $this->typeDefFactory = $typeDefFactory; $this->fieldDefFactory = $fieldDefFactory; $this->setDefinitions(); } /** * Set the internal definitions structure */ private function setDefinitions() { // This is defined in a method because PHP doesn't let you define properties with // expressions at the class level. If anyone has a better way to do this I am open // to any and all suggestions. $this->definitions = [ ResourceTypes::A => [ // RFC 1035 'address' => Types::IPV4_ADDRESS, ], ResourceTypes::AAAA => [ // RFC 3596 'address' => Types::IPV6_ADDRESS, ], ResourceTypes::AFSDB => [ // RFC 1183 'subtype' => Types::SHORT, 'hostname' => Types::DOMAIN_NAME, ], ResourceTypes::CAA => [ // RFC 6844 'flags' => Types::DOMAIN_NAME, 'tag' => Types::CHARACTER_STRING, 'value' => Types::ANYTHING, ], ResourceTypes::CERT => [ // RFC 4398 'type' => Types::SHORT, 'key-tag' => Types::SHORT, 'algorithm' => Types::CHAR, 'certificate' => Types::ANYTHING, ], ResourceTypes::CNAME => [ // RFC 1035 'cname' => Types::DOMAIN_NAME, ], ResourceTypes::DHCID => [ // RFC 4701 'identifier-type' => Types::SHORT, 'digest-type' => Types::CHAR, 'digest' => Types::ANYTHING, ], ResourceTypes::DLV => [ // RFC 4034 'key-tag' => Types::SHORT, 'algorithm' => Types::CHAR, 'digest-type' => Types::CHAR, 'digest' => Types::ANYTHING, ], ResourceTypes::DNAME => [ // RFC 4034 'target' => Types::DOMAIN_NAME, ], ResourceTypes::DNSKEY => [ // RFC 6672 'flags' => Types::SHORT, 'protocol' => Types::CHAR, 'algorithm' => Types::CHAR, 'public-key' => Types::ANYTHING, ], ResourceTypes::DS => [ // RFC 4034 'key-tag' => Types::SHORT, 'algorithm' => Types::CHAR, 'digest-type' => Types::CHAR, 'digest' => Types::ANYTHING, ], ResourceTypes::HINFO => [ // RFC 1035 'cpu' => Types::CHARACTER_STRING, 'os' => Types::CHARACTER_STRING, ], ResourceTypes::ISDN => [ // RFC 1183 'isdn-address' => Types::CHARACTER_STRING, 'sa' => Types::CHARACTER_STRING, ], ResourceTypes::KEY => [ // RFC 2535 'flags' => Types::SHORT, 'protocol' => Types::CHAR, 'algorithm' => Types::CHAR, 'public-key' => Types::ANYTHING, ], ResourceTypes::KX => [ // RFC 2230 'preference' => Types::SHORT, 'exchange' => Types::DOMAIN_NAME, ], ResourceTypes::LOC => [ // RFC 1876 'version' => Types::CHAR, 'size' => Types::CHAR, 'horizontal-precision' => Types::CHAR, 'vertical-precision' => Types::CHAR, 'latitude' => Types::LONG, 'longitude' => Types::LONG, 'altitude' => Types::LONG, ], ResourceTypes::MB => [ // RFC 1035 'madname' => Types::DOMAIN_NAME, ], ResourceTypes::MD => [ // RFC 1035 'madname' => Types::DOMAIN_NAME, ], ResourceTypes::MF => [ // RFC 1035 'madname' => Types::DOMAIN_NAME, ], ResourceTypes::MG => [ // RFC 1035 'mgmname' => Types::DOMAIN_NAME, ], ResourceTypes::MINFO => [ // RFC 1035 'rmailbx' => Types::DOMAIN_NAME, 'emailbx' => Types::DOMAIN_NAME, ], ResourceTypes::MR => [ // RFC 1035 'newname' => Types::DOMAIN_NAME, ], ResourceTypes::MX => [ // RFC 1035 'preference' => Types::SHORT, 'exchange' => Types::DOMAIN_NAME, ], ResourceTypes::NAPTR => [ // RFC 3403 'order' => Types::SHORT, 'preference' => Types::SHORT, 'flags' => Types::CHARACTER_STRING, 'services' => Types::CHARACTER_STRING, 'regexp' => Types::CHARACTER_STRING, 'replacement' => Types::DOMAIN_NAME, ], ResourceTypes::NS => [ // RFC 1035 'nsdname' => Types::DOMAIN_NAME, ], ResourceTypes::NULL => [ // RFC 1035 'data' => Types::ANYTHING, ], ResourceTypes::PTR => [ // RFC 1035 'ptrdname' => Types::DOMAIN_NAME, ], ResourceTypes::RP => [ // RFC 1183 'mbox-dname' => Types::DOMAIN_NAME, 'txt-dname' => Types::DOMAIN_NAME, ], ResourceTypes::RT => [ // RFC 1183 'preference' => Types::SHORT, 'intermediate-host' => Types::DOMAIN_NAME, ], ResourceTypes::SIG => [ // RFC 4034 'type-covered' => Types::SHORT, 'algorithm' => Types::CHAR, 'labels' => Types::CHAR, 'original-ttl' => Types::LONG, 'signature-expiration' => Types::LONG, 'signature-inception' => Types::LONG, 'key-tag' => Types::SHORT, 'signers-name' => Types::DOMAIN_NAME, 'signature' => Types::ANYTHING, ], ResourceTypes::SOA => [ // RFC 1035 'mname' => Types::DOMAIN_NAME, 'rname' => Types::DOMAIN_NAME, 'serial' => Types::LONG, 'refresh' => Types::LONG, 'retry' => Types::LONG, 'expire' => Types::LONG, 'minimum' => Types::LONG, ], ResourceTypes::SPF => [ // RFC 4408 'data+' => Types::CHARACTER_STRING, ], ResourceTypes::SRV => [ // RFC 2782 'priority' => Types::SHORT, 'weight' => Types::SHORT, 'port' => Types::SHORT, 'name' => Types::DOMAIN_NAME | DomainName::FLAG_NO_COMPRESSION, ], ResourceTypes::TXT => [ // RFC 1035 'txtdata+' => Types::CHARACTER_STRING, ], ResourceTypes::WKS => [ // RFC 1035 'address' => Types::IPV4_ADDRESS, 'protocol' => Types::SHORT, 'bit-map' => Types::BITMAP, ], ResourceTypes::X25 => [ // RFC 1183 'psdn-address' => Types::CHARACTER_STRING, ], ]; } /** * Get a type definition for a record type if it is known * * @param int $recordType Resource type, can be indicated using the ResourceTypes enum * @return \LibDNS\Records\TypeDefinitions\TypeDefinition */ public function getTypeDefinition(int $recordType) { if (!isset($this->typeDefs[$recordType])) { $definition = isset($this->definitions[$recordType]) ? $this->definitions[$recordType] : ['data' => Types::ANYTHING]; $this->typeDefs[$recordType] = $this->typeDefFactory->create($this->fieldDefFactory, $definition); } return $this->typeDefs[$recordType]; } /** * Register a custom type definition * * @param int $recordType Resource type, can be indicated using the ResourceTypes enum * @param int[]|\LibDNS\Records\TypeDefinitions\TypeDefinition $definition * @throws \InvalidArgumentException When the type definition is invalid */ public function registerTypeDefinition(int $recordType, $definition) { if (!($definition instanceof TypeDefinition)) { if (!\is_array($definition)) { throw new \InvalidArgumentException('Definition must be an array or an instance of ' . __NAMESPACE__ . '\TypeDefinition'); } $definition = $this->typeDefFactory->create($this->fieldDefFactory, $definition); } $this->typeDefs[$recordType] = $definition; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents a binary character string * * @category LibDNS * @package Types * @author Chris Wright */ class CharacterString extends Type { /** * @var string */ protected $value = ''; /** * Set the internal value * * @param string $value The new value * @throws \UnexpectedValueException When the supplied value is outside the valid length range 0 - 255 */ public function setValue($value) { $value = (string)$value; if (\strlen($value) > 255) { throw new \UnexpectedValueException('Character string length must be in the range 0 - 255'); } $this->value = $value; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Creates Type objects * * @category LibDNS * @package Types * @author Chris Wright */ class TypeFactory { /** * Create a new Anything object * * @param string $value * @return \LibDNS\Records\Types\Anything */ public function createAnything(string $value = null) { return new Anything($value); } /** * Create a new BitMap object * * @param string $value * @return \LibDNS\Records\Types\BitMap */ public function createBitMap(string $value = null) { return new BitMap($value); } /** * Create a new Char object * * @param int $value * @return \LibDNS\Records\Types\Char */ public function createChar(int $value = null) { return new Char((string)$value); } /** * Create a new CharacterString object * * @param string $value * @return \LibDNS\Records\Types\CharacterString */ public function createCharacterString(string $value = null) { return new CharacterString($value); } /** * Create a new DomainName object * * @param string|string[] $value * @return \LibDNS\Records\Types\DomainName */ public function createDomainName($value = null) { return new DomainName($value); } /** * Create a new IPv4Address object * * @param string|int[] $value * @return \LibDNS\Records\Types\IPv4Address */ public function createIPv4Address($value = null) { return new IPv4Address($value); } /** * Create a new IPv6Address object * * @param string|int[] $value * @return \LibDNS\Records\Types\IPv6Address */ public function createIPv6Address($value = null) { return new IPv6Address($value); } /** * Create a new Long object * * @param int $value * @return \LibDNS\Records\Types\Long */ public function createLong(int $value = null) { return new Long((string)$value); } /** * Create a new Short object * * @param int $value * @return \LibDNS\Records\Types\Short */ public function createShort(int $value = null) { return new Short((string)$value); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents a bit map * * @category LibDNS * @package Types * @author Chris Wright */ class BitMap extends Type { /** * @var string */ protected $value = ''; /** * Set the internal value * * @param string $value The new value */ public function setValue($value) { $this->value = (string)$value; } /** * Inspect the value of the bit at the specific index and optionally set a new value * * @param int $index * @param bool $newValue The new value * @return bool The old value */ public function isBitSet(int $index, bool $newValue = null): bool { $charIndex = (int)($index / 8); $bitMask = 0b10000000 >> ($index % 8); $result = false; if (isset($this->value[$charIndex])) { $result = (bool) (\ord($this->value[$charIndex]) & $bitMask); } if (isset($newValue) && $newValue != $result) { if (!isset($this->value[$charIndex])) { $this->value = \str_pad($this->value, $charIndex + 1, "\x00", STR_PAD_RIGHT); } $this->value[$charIndex] = \chr((\ord($this->value[$charIndex]) & ~$bitMask) | ($newValue ? $bitMask : 0)); } return $result; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents a generic binary data string * * @category LibDNS * @package Types * @author Chris Wright */ class Anything extends Type { /** * @var string */ protected $value = ''; /** * Set the internal value * * @param string $value The new value * @throws \UnexpectedValueException When the supplied value is outside the valid length range 0 - 65535 */ public function setValue($value) { $value = (string)$value; if (\strlen($value) > 65535) { throw new \UnexpectedValueException('Untyped string length must be in the range 0 - 65535'); } $this->value = $value; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents a 16-bit unsigned integer * * @category LibDNS * @package Types * @author Chris Wright */ class Short extends Type { /** * @var int */ protected $value = 0; /** * Set the internal value * * @param string $value The new value * @throws \UnderflowException When the supplied value is less than 0 * @throws \OverflowException When the supplied value is greater than 65535 */ public function setValue($value) { $value = (int)$value; if ($value < 0) { throw new \UnderflowException('Short integer value must be in the range 0 - 65535'); } else if ($value > 0xffff) { throw new \OverflowException('Short integer value must be in the range 0 - 65535'); } $this->value = $value; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents a fully qualified domain name * * @category LibDNS * @package Types * @author Chris Wright */ class DomainName extends Type { const FLAG_NO_COMPRESSION = 0x80000000; /** * @var string */ protected $value = ''; /** * @var string[] The value as a list of labels */ private $labels = []; /** * Constructor * * @param string|string[] $value * @throws \UnexpectedValueException When the supplied value is not a valid domain name */ public function __construct($value = null) { if (\is_array($value)) { $this->setLabels($value); } else { parent::__construct($value); } } /** * Set the internal value * * @param string $value The new value * @throws \UnexpectedValueException When the supplied value is not a valid domain name */ public function setValue($value) { $this->setLabels(\explode('.', (string)$value)); } /** * Get the domain name labels * * @param bool $tldFirst Whether to return the label list ordered with the TLD label first * @return string[] */ public function getLabels($tldFirst = false): array { return $tldFirst ? \array_reverse($this->labels) : $this->labels; } /** * Set the domain name labels * * @param string[] $labels The new label list * @param bool $tldFirst Whether the supplied label list is ordered with the TLD label first * @throws \UnexpectedValueException When the supplied label list is not a valid domain name */ public function setLabels(array $labels, $tldFirst = false) { if (!$labels) { $this->labels = []; $this->value = ''; return; } $length = $count = 0; foreach ($labels as &$label) { $label = \LibDNS\normalize_name($label); $labelLength = \strlen($label); if ($labelLength > 63) { throw new \InvalidArgumentException('Label list is not a valid domain name: Label ' . $label . ' length exceeds 63 byte limit'); } $length += $labelLength + 1; $count++; } $tld = $tldFirst ? $labels[0] : $labels[$count - 1]; if ($tld === '') { $length--; } if ($length + 1 > 255) { throw new \InvalidArgumentException('Label list is not a valid domain name: Total length exceeds 255 byte limit'); } $this->labels = $tldFirst ? \array_reverse($labels) : $labels; $this->value = \implode('.', $this->labels); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents a 32-bit unsigned integer * * @category LibDNS * @package Types * @author Chris Wright */ class Long extends Type { /** * @var int */ protected $value = 0; /** * Set the internal value * * @param string $value The new value * @throws \UnderflowException When the supplied value is less than 0 * @throws \OverflowException When the supplied value is greater than 4294967296 */ public function setValue($value) { $value = (int)$value; if ($value < 0) { throw new \UnderflowException('Long integer value must be in the range 0 - 4294967296'); } else if ($value > 0xffffffff) { throw new \OverflowException('Long integer value must be in the range 0 - 4294967296'); } $this->value = $value; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Builds Types from type definitions * * @category LibDNS * @package Types * @author Chris Wright */ class TypeBuilder { /** * @var \LibDNS\Records\Types\TypeFactory */ private $typeFactory; /** * Constructor * * @param \LibDNS\Records\Types\TypeFactory $typeFactory */ public function __construct(TypeFactory $typeFactory) { $this->typeFactory = $typeFactory; } /** * Build a new Type object corresponding to a resource record type * * @param int $type Data type, can be indicated using the Types enum * @return \LibDNS\Records\Types\Type */ public function build(int $type): Type { static $typeMap = [ Types::ANYTHING => 'createAnything', Types::BITMAP => 'createBitMap', Types::CHAR => 'createChar', Types::CHARACTER_STRING => 'createCharacterString', Types::DOMAIN_NAME => 'createDomainName', Types::IPV4_ADDRESS => 'createIPv4Address', Types::IPV6_ADDRESS => 'createIPv6Address', Types::LONG => 'createLong', Types::SHORT => 'createShort', ]; if (!isset($typeMap[$type])) { throw new \InvalidArgumentException('Invalid Type identifier ' . $type); } return $this->typeFactory->{$typeMap[$type]}(); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Base class for simple data types * * @category LibDNS * @package Types * @author Chris Wright */ abstract class Type { /** * @var mixed The internal value */ protected $value; /** * Constructor * * @param string $value Internal value * @throws \RuntimeException When the supplied value is invalid */ public function __construct(string $value = null) { if (isset($value)) { $this->setValue($value); } } /** * Magic method for type coercion to string * * @return string */ public function __toString(): string { return (string) $this->value; } /** * Get the internal value * * @return mixed */ public function getValue() { return $this->value; } /** * Set the internal value * * @param string $value The new value * @throws \RuntimeException When the supplied value is invalid */ abstract public function setValue($value); } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents an IPv6 address * * @category LibDNS * @package Types * @author Chris Wright */ class IPv6Address extends Type { /** * @var string */ protected $value = '::'; /** * @var int[] The shorts of the address */ private $shorts = [0, 0, 0, 0, 0, 0, 0, 0]; /** * Create a compressed string representation of an IPv6 address * * @param int[] $shorts Address shorts * @return string */ private function createCompressedString($shorts) { $compressLen = $compressPos = $currentLen = $currentPos = 0; $inBlock = false; for ($i = 0; $i < 8; $i++) { if ($shorts[$i] === 0) { if (!$inBlock) { $inBlock = true; $currentPos = $i; } $currentLen++; } else if ($inBlock) { if ($currentLen > $compressLen) { $compressLen = $currentLen; $compressPos = $currentPos; } $inBlock = false; $currentPos = $currentLen = 0; } $shorts[$i] = \dechex($shorts[$i]); } if ($inBlock) { $compressLen = $currentLen; $compressPos = $currentPos; } if ($compressLen > 1) { if ($compressLen === 8) { $replace = ['', '', '']; } else if ($compressPos === 0 || $compressPos + $compressLen === 8) { $replace = ['', '']; } else { $replace = ['']; } \array_splice($shorts, $compressPos, $compressLen, $replace); } return \implode(':', $shorts); } /** * Constructor * * @param string|int[] $value String representation or shorts list * @throws \UnexpectedValueException When the supplied value is not a valid IPv6 address */ public function __construct($value = null) { if (\is_array($value)) { $this->setShorts($value); } else { parent::__construct($value); } } /** * Set the internal value * * @param string $value The new value * @throws \UnexpectedValueException When the supplied value is outside the valid length range 0 - 65535 */ public function setValue($value) { $shorts = \explode(':', (string)$value); $count = \count($shorts); if ($count < 3 || $count > 8) { throw new \UnexpectedValueException('Value is not a valid IPv6 address: invalid short count'); } else if ($shorts[0] === '' && $shorts[1] === '') { $shorts = \array_pad($shorts, -8, '0'); } else if ($shorts[$count - 2] === '' && $shorts[$count - 1] === '') { $shorts = \array_pad($shorts, 8, '0'); } else if (false !== $pos = \array_search('', $shorts, true)) { \array_splice($shorts, $pos, 1, \array_fill(0, 8 - ($count - 1), '0')); } $this->setShorts(\array_map('hexdec', $shorts)); } /** * Get the address shorts * * @return int[] */ public function getShorts(): array { return $this->shorts; } /** * Set the address shorts * * @param int[] $shorts The new address shorts * @throws \UnexpectedValueException When the supplied short list is not a valid IPv6 address */ public function setShorts(array $shorts) { if (\count($shorts) !== 8) { throw new \UnexpectedValueException('Short list is not a valid IPv6 address: invalid short count'); } foreach ($shorts as &$short) { if ((!\is_int($short) && !\ctype_digit((string)$short)) || $short < 0x0000 || $short > 0xffff) { throw new \UnexpectedValueException('Short list is not a valid IPv6 address: invalid short value ' . $short); } $short = (int) $short; } $this->shorts = \array_values($shorts); $this->value = $this->createCompressedString($this->shorts); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents an 8-bit unsigned integer * * @category LibDNS * @package Types * @author Chris Wright */ class Char extends Type { /** * @var int */ protected $value = 0; /** * Set the internal value * * @param string $value The new value * @throws \UnderflowException When the supplied value is less than 0 * @throws \OverflowException When the supplied value is greater than 255 */ public function setValue($value) { $value = (int) $value; if ($value < 0) { throw new \UnderflowException('Char value must be in the range 0 - 255'); } else if ($value > 255) { throw new \OverflowException('Char value must be in the range 0 - 255'); } $this->value = $value; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; /** * Represents an IPv4 address * * @category LibDNS * @package Types * @author Chris Wright */ class IPv4Address extends Type { /** * @var string */ protected $value = '0.0.0.0'; /** * @var int[] The octets of the address */ private $octets = [0, 0, 0, 0]; /** * Constructor * * @param string|int[] $value String representation or octet list * @throws \UnexpectedValueException When the supplied value is not a valid IPv4 address */ public function __construct($value = null) { if (\is_array($value)) { $this->setOctets($value); } else { parent::__construct($value); } } /** * Set the internal value * * @param string $value The new value * @throws \UnexpectedValueException When the supplied value is outside the valid length range 0 - 65535 */ public function setValue($value) { $this->setOctets(\explode('.', (string)$value)); } /** * Get the address octets * * @return int[] */ public function getOctets(): array { return $this->octets; } /** * Set the address octets * * @param int[] $octets The new address octets * @throws \UnexpectedValueException When the supplied octet list is not a valid IPv4 address */ public function setOctets(array $octets) { if (\count($octets) !== 4) { throw new \UnexpectedValueException('Octet list is not a valid IPv4 address: invalid octet count'); } foreach ($octets as &$octet) { if ((!\is_int($octet) && !\ctype_digit((string)$octet)) || $octet < 0x00 || $octet > 0xff) { throw new \UnexpectedValueException('Octet list is not a valid IPv4 address: invalid octet value ' . $octet); } $octet = (int) $octet; } $this->octets = \array_values($octets); $this->value = \implode('.', $this->octets); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records\Types; use \LibDNS\Enumeration; /** * Enumeration of simple data types * * @category LibDNS * @package Types * @author Chris Wright */ final class Types extends Enumeration { const ANYTHING = 0b000000001; const BITMAP = 0b000000010; const CHAR = 0b000000100; const CHARACTER_STRING = 0b000001000; const DOMAIN_NAME = 0b000010000; const IPV4_ADDRESS = 0b000100000; const IPV6_ADDRESS = 0b001000000; const LONG = 0b010000000; const SHORT = 0b100000000; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; /** * Enumeration of possible resource QCLASS values * * @category LibDNS * @package Records * @author Chris Wright */ final class ResourceQClasses extends ResourceClasses { const ANY = 255; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\TypeDefinitions\TypeDefinition; /** * Creates RData objects * * @category LibDNS * @package Records * @author Chris Wright */ class RDataFactory { /** * Create a new RData object * * @param \LibDNS\Records\TypeDefinitions\TypeDefinition $typeDefinition * @return \LibDNS\Records\RData */ public function create(TypeDefinition $typeDefinition): RData { return new RData($typeDefinition); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\TypeDefinitions\TypeDefinition; use \LibDNS\Records\Types\TypeBuilder; /** * Creates RData objects * * @category LibDNS * @package Records * @author Chris Wright */ class RDataBuilder { /** * @var \LibDNS\Records\RDataFactory */ private $rDataFactory; /** * @var \LibDNS\Records\Types\TypeBuilder */ private $typeBuilder; /** * Constructor * * @param \LibDNS\Records\RDataFactory $rDataFactory * @param \LibDNS\Records\Types\TypeBuilder $typeBuilder */ public function __construct(RDataFactory $rDataFactory, TypeBuilder $typeBuilder) { $this->rDataFactory = $rDataFactory; $this->typeBuilder = $typeBuilder; } /** * Create a new RData object * * @param \LibDNS\Records\TypeDefinitions\TypeDefinition $typeDefinition * @return \LibDNS\Records\RData */ public function build(TypeDefinition $typeDefinition): RData { $rData = $this->rDataFactory->create($typeDefinition); foreach ($typeDefinition as $index => $type) { $rData->setField($index, $this->typeBuilder->build($type->getType())); } return $rData; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\TypeBuilder; use \LibDNS\Records\Types\TypeFactory; use \LibDNS\Records\TypeDefinitions\TypeDefinitionManager; use \LibDNS\Records\TypeDefinitions\TypeDefinitionFactory; use \LibDNS\Records\TypeDefinitions\FieldDefinitionFactory; /** * Creates ResourceBuilder objects * * @category LibDNS * @package Records * @author Chris Wright */ class ResourceBuilderFactory { /** * Create a new ResourceBuilder object * * @param \LibDNS\Records\TypeDefinitions\TypeDefinitionManager $typeDefinitionManager * @return \LibDNS\Records\ResourceBuilder */ public function create(TypeDefinitionManager $typeDefinitionManager = null): ResourceBuilder { return new ResourceBuilder( new ResourceFactory, new RDataBuilder( new RDataFactory, new TypeBuilder(new TypeFactory) ), $typeDefinitionManager ?: new TypeDefinitionManager( new TypeDefinitionFactory, new FieldDefinitionFactory ) ); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; /** * Collection of Record objects * * @category LibDNS * @package Records * @author Chris Wright */ class RecordCollection implements \IteratorAggregate, \Countable { /** * @var \LibDNS\Records\Record[] List of records held in the collection */ private $records = []; /** * @var \LibDNS\Records\Record[][] Map of Records in the collection grouped by record name */ private $nameMap = []; /** * @var int Number of Records in the collection */ private $length = 0; /** * @var int Whether the collection holds question or resource records */ private $type; /** * Constructor * * @param int $type Can be indicated using the RecordTypes enum * @throws \InvalidArgumentException When the specified record type is invalid */ public function __construct($type) { if ($type !== RecordTypes::QUESTION && $type !== RecordTypes::RESOURCE) { throw new \InvalidArgumentException('Record type must be QUESTION or RESOURCE'); } $this->type = $type; } /** * Add a record to the correct bucket in the name map * * @param \LibDNS\Records\Record $record The record to add */ private function addToNameMap(Record $record) { if (!isset($this->nameMap[$name = (string) $record->getName()])) { $this->nameMap[$name] = []; } $this->nameMap[$name][] = $record; } /** * Remove a record from the name map * * @param \LibDNS\Records\Record $record The record to remove */ private function removeFromNameMap(Record $record) { if (!empty($this->nameMap[$name = (string) $record->getName()])) { foreach ($this->nameMap[$name] as $key => $item) { if ($item === $record) { \array_splice($this->nameMap[$name], $key, 1); break; } } } if (empty($this->nameMap[$name])) { unset($this->nameMap[$name]); } } /** * Add a record to the collection * * @param \LibDNS\Records\Record $record The record to add * @throws \InvalidArgumentException When the wrong record type is supplied */ public function add(Record $record) { if (($this->type === RecordTypes::QUESTION && !($record instanceof Question)) || ($this->type === RecordTypes::RESOURCE && !($record instanceof Resource))) { throw new \InvalidArgumentException('Incorrect record type for this collection'); } $this->records[] = $record; $this->addToNameMap($record); $this->length++; } /** * Remove a record from the collection * * @param \LibDNS\Records\Record $record The record to remove */ public function remove(Record $record) { foreach ($this->records as $key => $item) { if ($item === $record) { array_splice($this->records, $key, 1); $this->removeFromNameMap($record); $this->length--; return; } } throw new \InvalidArgumentException('The supplied record is not a member of this collection'); } /** * Test whether the collection contains a specific record * * @param \LibDNS\Records\Record $record The record to search for * @param bool $sameInstance Whether to perform strict comparisons in search * @return bool */ public function contains(Record $record, bool $sameInstance = false): bool { return \in_array($record, $this->records, $sameInstance); } /** * Get all records in the collection that refer to the specified name * * @param string $name The name to match records against * @return \LibDNS\Records\Record[] */ public function getRecordsByName(string $name): array { return $this->nameMap[\strtolower($name)] ?? []; } /** * Get a record from the collection by index * * @param int $index Record index * @return \LibDNS\Records\Record * @throws \OutOfBoundsException When the supplied index does not refer to a valid record */ public function getRecordByIndex(int $index): Record { if (isset($this->records[$index])) { return $this->records[$index]; } throw new \OutOfBoundsException('The specified index ' . $index . ' does not exist in the collection'); } /** * Remove all records in the collection that refer to the specified name * * @param string $name The name to match records against * @return int The number of records removed */ public function clearRecordsByName(string $name): int { $count = 0; if (isset($this->nameMap[$name = \strtolower($name)])) { unset($this->nameMap[$name]); foreach ($this->records as $index => $record) { if ($record->getName() === $name) { unset($this->records[$index]); $count++; } } $this->records = \array_values($this->records); } return $count; } /** * Remove all records from the collection */ public function clear() { $this->records = $this->nameMap = []; $this->length = 0; } /** * Get a list of all names referenced by records in the collection * * @return string[] */ public function getNames(): array { return \array_keys($this->nameMap); } /** * Get whether the collection holds question or resource records * * @return int */ public function getType(): int { return $this->type; } /** * Retrieve an iterator (IteratorAggregate interface) * * @return \Iterator */ public function getIterator(): \Iterator { return new \ArrayIterator($this->records); } /** * Get the number of records in the collection (Countable interface) * * @return int */ public function count(): int { return $this->length; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Enumeration; /** * Enumeration of possible record types * * @category LibDNS * @package Records * @author Chris Wright */ final class RecordTypes extends Enumeration { const QUESTION = 0; const RESOURCE = 1; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; use \LibDNS\Records\Types\DomainName; /** * Represents a DNS record * * @category LibDNS * @package Records * @author Chris Wright */ abstract class Record { /** * @var \LibDNS\Records\Types\TypeFactory */ protected $typeFactory; /** * @var \LibDNS\Records\Types\DomainName */ protected $name; /** * @var int */ protected $type; /** * @var int */ protected $class = ResourceClasses::IN; /** * Get the value of the record name field * * @return \LibDNS\Records\Types\DomainName */ public function getName(): DomainName { return $this->name; } /** * Set the value of the record name field * * @param string|\LibDNS\Records\Types\DomainName $name * @throws \UnexpectedValueException When the supplied value is not a valid domain name */ public function setName($name) { if (!($name instanceof DomainName)) { $name = $this->typeFactory->createDomainName((string)$name); } $this->name = $name; } /** * Get the value of the record type field * * @return int */ public function getType(): int { return $this->type; } /** * Get the value of the record class field * * @return int */ public function getClass(): int { return $this->class; } /** * Set the value of the record class field * * @param int $class The new value, can be indicated using the ResourceClasses/ResourceQClasses enums * @throws \RangeException When the supplied value is outside the valid range 0 - 65535 */ public function setClass(int $class) { if ($class < 0 || $class > 65535) { throw new \RangeException('Record class must be in the range 0 - 65535'); } $this->class = $class; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Records; /** * Creates RecordCollection objects * * @category LibDNS * @package Records * @author Chris Wright */ class RecordCollectionFactory { /** * Create a new RecordCollection object * * @param int $type Can be indicated using the RecordTypes enum * @return \LibDNS\Records\RecordCollection * @throws \InvalidArgumentException When the specified record type is invalid */ public function create(int $type): RecordCollection { return new RecordCollection($type); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Encoder; use \LibDNS\Packets\Packet; use \LibDNS\Packets\LabelRegistry; /** * Creates EncodingContext objects * * @category LibDNS * @package Encoder * @author Chris Wright */ class EncodingContextFactory { /** * Create a new EncodingContext object * * @param \LibDNS\Packets\Packet $packet The packet to be decoded * @param bool $compress Whether message compression is enabled * @return \LibDNS\Encoder\EncodingContext */ public function create(Packet $packet, bool $compress): EncodingContext { return new EncodingContext($packet, new LabelRegistry, $compress); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Encoder; use \LibDNS\Packets\PacketFactory; /** * Creates Encoder objects * * @category LibDNS * @package Encoder * @author Chris Wright */ class EncoderFactory { /** * Create a new Encoder object * * @return \LibDNS\Encoder\Encoder */ public function create(): Encoder { return new Encoder(new PacketFactory, new EncodingContextFactory); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Encoder; use \LibDNS\Packets\PacketFactory; use \LibDNS\Messages\Message; use \LibDNS\Records\Question; use \LibDNS\Records\Resource; use \LibDNS\Records\Types\Type; use \LibDNS\Records\Types\Anything; use \LibDNS\Records\Types\BitMap; use \LibDNS\Records\Types\Char; use \LibDNS\Records\Types\CharacterString; use \LibDNS\Records\Types\DomainName; use \LibDNS\Records\Types\IPv4Address; use \LibDNS\Records\Types\IPv6Address; use \LibDNS\Records\Types\Long; use \LibDNS\Records\Types\Short; /** * Encodes Message objects to raw network data * * @category LibDNS * @package Encoder * @author Chris Wright */ class Encoder { /** * @var \LibDNS\Packets\PacketFactory */ private $packetFactory; /** * @var \LibDNS\Encoder\EncodingContextFactory */ private $encodingContextFactory; /** * Constructor * * @param \LibDNS\Packets\PacketFactory $packetFactory * @param \LibDNS\Encoder\EncodingContextFactory $encodingContextFactory */ public function __construct(PacketFactory $packetFactory, EncodingContextFactory $encodingContextFactory) { $this->packetFactory = $packetFactory; $this->encodingContextFactory = $encodingContextFactory; } /** * Encode the header section of the message * * @param \LibDNS\Encoder\EncodingContext $encodingContext * @param \LibDNS\Messages\Message $message * @return string * @throws \UnexpectedValueException When the header section is invalid */ private function encodeHeader(EncodingContext $encodingContext, Message $message): string { $header = [ 'id' => $message->getID(), 'meta' => 0, 'qd' => $message->getQuestionRecords()->count(), 'an' => $message->getAnswerRecords()->count(), 'ns' => $message->getAuthorityRecords()->count(), 'ar' => $message->getAdditionalRecords()->count() ]; $header['meta'] |= $message->getType() << 15; $header['meta'] |= $message->getOpCode() << 11; $header['meta'] |= ((int) $message->isAuthoritative()) << 10; $header['meta'] |= ((int) $encodingContext->isTruncated()) << 9; $header['meta'] |= ((int) $message->isRecursionDesired()) << 8; $header['meta'] |= ((int) $message->isRecursionAvailable()) << 7; $header['meta'] |= $message->getResponseCode(); return \pack('n*', $header['id'], $header['meta'], $header['qd'], $header['an'], $header['ns'], $header['ar']); } /** * Encode an Anything field * * @param \LibDNS\Records\Types\Anything $anything * @return string */ private function encodeAnything(Anything $anything): string { return $anything->getValue(); } /** * Encode a BitMap field * * @param \LibDNS\Records\Types\BitMap $bitMap * @return string */ private function encodeBitMap(BitMap $bitMap): string { return $bitMap->getValue(); } /** * Encode a Char field * * @param \LibDNS\Records\Types\Char $char * @return string */ private function encodeChar(Char $char): string { return \chr($char->getValue()); } /** * Encode a CharacterString field * * @param \LibDNS\Records\Types\CharacterString $characterString * @return string */ private function encodeCharacterString(CharacterString $characterString): string { $data = $characterString->getValue(); return \chr(\strlen($data)) . $data; } /** * Encode a DomainName field * * @param \LibDNS\Records\Types\DomainName $domainName * @param \LibDNS\Encoder\EncodingContext $encodingContext * @return string */ private function encodeDomainName(DomainName $domainName, EncodingContext $encodingContext): string { $packetIndex = $encodingContext->getPacket()->getLength() + 12; $labelRegistry = $encodingContext->getLabelRegistry(); $result = ''; $labels = $domainName->getLabels(); if ($encodingContext->useCompression()) { do { $part = \implode('.', $labels); $index = $labelRegistry->lookupIndex($part); if ($index === null) { $labelRegistry->register($part, $packetIndex); $label = \array_shift($labels); $length = \strlen($label); $result .= \chr($length) . $label; $packetIndex += $length + 1; } else { $result .= \pack('n', 0b1100000000000000 | $index); break; } } while($labels); if (!$labels) { $result .= "\x00"; } } else { foreach ($labels as $label) { $result .= \chr(\strlen($label)) . $label; } $result .= "\x00"; } return $result; } /** * Encode an IPv4Address field * * @param \LibDNS\Records\Types\IPv4Address $ipv4Address * @return string */ private function encodeIPv4Address(IPv4Address $ipv4Address): string { $octets = $ipv4Address->getOctets(); return \pack('C*', $octets[0], $octets[1], $octets[2], $octets[3]); } /** * Encode an IPv6Address field * * @param \LibDNS\Records\Types\IPv6Address $ipv6Address * @return string */ private function encodeIPv6Address(IPv6Address $ipv6Address): string { $shorts = $ipv6Address->getShorts(); return \pack('n*', $shorts[0], $shorts[1], $shorts[2], $shorts[3], $shorts[4], $shorts[5], $shorts[6], $shorts[7]); } /** * Encode a Long field * * @param \LibDNS\Records\Types\Long $long * @return string */ private function encodeLong(Long $long): string { return \pack('N', $long->getValue()); } /** * Encode a Short field * * @param \LibDNS\Records\Types\Short $short * @return string */ private function encodeShort(Short $short): string { return \pack('n', $short->getValue()); } /** * Encode a type object * * @param \LibDNS\Encoder\EncodingContext $encodingContext * @param \LibDNS\Records\Types\Type $type * @return string */ private function encodeType(EncodingContext $encodingContext, Type $type): string { if ($type instanceof Anything) { $result = $this->encodeAnything($type); } else if ($type instanceof BitMap) { $result = $this->encodeBitMap($type); } else if ($type instanceof Char) { $result = $this->encodeChar($type); } else if ($type instanceof CharacterString) { $result = $this->encodeCharacterString($type); } else if ($type instanceof DomainName) { $result = $this->encodeDomainName($type, $encodingContext); } else if ($type instanceof IPv4Address) { $result = $this->encodeIPv4Address($type); } else if ($type instanceof IPv6Address) { $result = $this->encodeIPv6Address($type); } else if ($type instanceof Long) { $result = $this->encodeLong($type); } else if ($type instanceof Short) { $result = $this->encodeShort($type); } else { throw new \InvalidArgumentException('Unknown Type ' . \get_class($type)); } return $result; } /** * Encode a question record * * @param \LibDNS\Encoder\EncodingContext $encodingContext * @param \LibDNS\Records\Question $record */ private function encodeQuestionRecord(EncodingContext $encodingContext, Question $record) { if (!$encodingContext->isTruncated()) { $packet = $encodingContext->getPacket(); $name = $this->encodeDomainName($record->getName(), $encodingContext); $meta = \pack('n*', $record->getType(), $record->getClass()); if (12 + $packet->getLength() + \strlen($name) + 4 > 512) { $encodingContext->isTruncated(true); } else { $packet->write($name); $packet->write($meta); } } } /** * Encode a resource record * * @param \LibDNS\Encoder\EncodingContext $encodingContext * @param \LibDNS\Records\Resource $record */ private function encodeResourceRecord(EncodingContext $encodingContext, Resource $record) { if (!$encodingContext->isTruncated()) { $packet = $encodingContext->getPacket(); $name = $this->encodeDomainName($record->getName(), $encodingContext); $data = ''; foreach ($record->getData() as $field) { $data .= $this->encodeType($encodingContext, $field); } $meta = \pack('n2Nn', $record->getType(), $record->getClass(), $record->getTTL(), \strlen($data)); if (12 + $packet->getLength() + \strlen($name) + 10 + \strlen($data) > 512) { $encodingContext->isTruncated(true); } else { $packet->write($name); $packet->write($meta); $packet->write($data); } } } /** * Encode a Message to raw network data * * @param \LibDNS\Messages\Message $message The Message to encode * @param bool $compress Enable message compression * @return string */ public function encode(Message $message, $compress = true): string { $packet = $this->packetFactory->create(); $encodingContext = $this->encodingContextFactory->create($packet, $compress); foreach ($message->getQuestionRecords() as $record) { /** @var \LibDNS\Records\Question $record */ $this->encodeQuestionRecord($encodingContext, $record); } foreach ($message->getAnswerRecords() as $record) { /** @var \LibDNS\Records\Resource $record */ $this->encodeResourceRecord($encodingContext, $record); } foreach ($message->getAuthorityRecords() as $record) { /** @var \LibDNS\Records\Resource $record */ $this->encodeResourceRecord($encodingContext, $record); } foreach ($message->getAdditionalRecords() as $record) { /** @var \LibDNS\Records\Resource $record */ $this->encodeResourceRecord($encodingContext, $record); } return $this->encodeHeader($encodingContext, $message) . $packet->read($packet->getLength()); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Encoder; use \LibDNS\Packets\Packet; use \LibDNS\Packets\LabelRegistry; /** * Holds data associated with an encode operation * * @category LibDNS * @package Encoder * @author Chris Wright */ class EncodingContext { /** * @var \LibDNS\Packets\Packet */ private $packet; /** * @var \LibDNS\Packets\LabelRegistry */ private $labelRegistry; /** * @var bool */ private $compress; /** * @var bool */ private $truncate = false; /** * Constructor * * @param \LibDNS\Packets\Packet $packet * @param \LibDNS\Packets\LabelRegistry $labelRegistry * @param bool $compress */ public function __construct(Packet $packet, LabelRegistry $labelRegistry, bool $compress) { $this->packet = $packet; $this->labelRegistry = $labelRegistry; $this->compress = $compress; } /** * Get the packet * * @return \LibDNS\Packets\Packet */ public function getPacket(): Packet { return $this->packet; } /** * Get the label registry * * @return \LibDNS\Packets\LabelRegistry */ public function getLabelRegistry(): LabelRegistry { return $this->labelRegistry; } /** * Determine whether compression is enabled * * @return bool */ public function useCompression(): bool { return $this->compress; } /** * Determine or set whether the message is truncated * * @param bool $truncate * @return bool */ public function isTruncated(bool $truncate = null): bool { $result = $this->truncate; if ($truncate !== null) { $this->truncate = $truncate; } return $result; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Packets; /** * Creates Packet objects * * @category LibDNS * @package Packets * @author Chris Wright */ class LabelRegistry { /** * @var int[] Map of labels to indexes */ private $labels = []; /** * @var string[][] Map of indexes to labels */ private $indexes = []; /** * Register a new relationship * * @param string|string[] $labels * @param int $index */ public function register($labels, int $index) { if (\is_array($labels)) { $labelsArr = $labels; $labelsStr = \implode('.', $labels); } else { $labelsArr = \explode('.', $labels); $labelsStr = (string) $labels; } if (!isset($this->labels[$labelsStr]) || $index < $this->labels[$labelsStr]) { $this->labels[$labelsStr] = $index; } $this->indexes[$index] = $labelsArr; } /** * Lookup the index of a label * * @param string $label * @return int|null */ public function lookupIndex(string $label) { return $this->labels[$label] ?? null; } /** * Lookup the label at an index * * @param int $index * @return string[]|null */ public function lookupLabel(int $index) { return $this->indexes[$index] ?? null; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Packets; /** * Represents a raw network data packet * * @category LibDNS * @package Packets * @author Chris Wright */ class Packet { /** * @var string */ private $data; /** * @var int Data length */ private $length; /** * @var int Read pointer */ private $pointer = 0; /** * Constructor * * @param string $data The initial packet raw data */ public function __construct(string $data = '') { $this->data = $data; $this->length = \strlen($this->data); } /** * Read bytes from the packet data * * @param int $length The number of bytes to read * @return string * @throws \OutOfBoundsException When the pointer position is invalid or the supplied length is negative */ public function read(int $length = null): string { if ($this->pointer > $this->length) { throw new \OutOfBoundsException('Pointer position invalid'); } if ($length === null) { $result = \substr($this->data, $this->pointer); $this->pointer = $this->length; } else { if ($length < 0) { throw new \OutOfBoundsException('Length must be a positive integer'); } $result = \substr($this->data, $this->pointer, $length); $this->pointer += $length; } return $result; } /** * Append data to the packet * * @param string $data The data to append * @return int The number of bytes written */ public function write(string $data): int { $length = \strlen($data); $this->data .= $data; $this->length += $length; return $length; } /** * Reset the read pointer */ public function reset() { $this->pointer = 0; } /** * Get the pointer index * * @return int */ public function getPointer(): int { return $this->pointer; } /** * Get the data length * * @return int */ public function getLength(): int { return $this->length; } /** * Get the number of remaining bytes from the pointer position * * @return int */ public function getBytesRemaining(): int { return $this->length - $this->pointer; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Packets; /** * Creates Packet objects * * @category LibDNS * @package Packets * @author Chris Wright */ class PacketFactory { /** * Create a new Packet object * * @param string $data * @return \LibDNS\Packets\Packet */ public function create(string $data = ''): Packet { return new Packet($data); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Decoder; use LibDNS\Messages\Message; use LibDNS\Messages\MessageFactory; use LibDNS\Packets\Packet; use LibDNS\Packets\PacketFactory; use LibDNS\Records\Question; use LibDNS\Records\QuestionFactory; use LibDNS\Records\Resource; use LibDNS\Records\ResourceBuilder; use LibDNS\Records\Types\Anything; use LibDNS\Records\Types\BitMap; use LibDNS\Records\Types\Char; use LibDNS\Records\Types\CharacterString; use LibDNS\Records\Types\DomainName; use LibDNS\Records\Types\IPv4Address; use LibDNS\Records\Types\IPv6Address; use LibDNS\Records\Types\Long; use LibDNS\Records\Types\Short; use LibDNS\Records\Types\Type; use LibDNS\Records\Types\TypeBuilder; use LibDNS\Records\Types\Types; /** * Decodes raw network data to Message objects * * @category LibDNS * @package Decoder * @author Chris Wright */ class Decoder { /** * @var \LibDNS\Packets\PacketFactory */ private $packetFactory; /** * @var \LibDNS\Messages\MessageFactory */ private $messageFactory; /** * @var \LibDNS\Records\QuestionFactory */ private $questionFactory; /** * @var \LibDNS\Records\ResourceBuilder */ private $resourceBuilder; /** * @var \LibDNS\Records\Types\TypeBuilder */ private $typeBuilder; /** * @var \LibDNS\Decoder\DecodingContextFactory */ private $decodingContextFactory; /** * @var bool */ private $allowTrailingData; /** * Constructor * * @param \LibDNS\Packets\PacketFactory $packetFactory * @param \LibDNS\Messages\MessageFactory $messageFactory * @param \LibDNS\Records\QuestionFactory $questionFactory * @param \LibDNS\Records\ResourceBuilder $resourceBuilder * @param \LibDNS\Records\Types\TypeBuilder $typeBuilder * @param \LibDNS\Decoder\DecodingContextFactory $decodingContextFactory * @param bool $allowTrailingData */ public function __construct( PacketFactory $packetFactory, MessageFactory $messageFactory, QuestionFactory $questionFactory, ResourceBuilder $resourceBuilder, TypeBuilder $typeBuilder, DecodingContextFactory $decodingContextFactory, bool $allowTrailingData = true ) { $this->packetFactory = $packetFactory; $this->messageFactory = $messageFactory; $this->questionFactory = $questionFactory; $this->resourceBuilder = $resourceBuilder; $this->typeBuilder = $typeBuilder; $this->decodingContextFactory = $decodingContextFactory; $this->allowTrailingData = $allowTrailingData; } /** * Read a specified number of bytes of data from a packet * * @param \LibDNS\Packets\Packet $packet * @param int $length * @return string * @throws \UnexpectedValueException When the read operation does not result in the requested number of bytes */ private function readDataFromPacket(Packet $packet, int $length): string { if ($packet->getBytesRemaining() < $length) { throw new \UnexpectedValueException('Decode error: Incomplete packet (tried to read ' . $length . ' bytes from index ' . $packet->getPointer()); } return $packet->read($length); } /** * Decode the header section of the message * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Messages\Message $message * @throws \UnexpectedValueException When the header section is invalid */ private function decodeHeader(DecodingContext $decodingContext, Message $message) { $header = \unpack('nid/nmeta/nqd/nan/nns/nar', $this->readDataFromPacket($decodingContext->getPacket(), 12)); if (!$header) { throw new \UnexpectedValueException('Decode error: Header unpack failed'); } $message->setID($header['id']); $message->setType(($header['meta'] & 0b1000000000000000) >> 15); $message->setOpCode(($header['meta'] & 0b0111100000000000) >> 11); $message->isAuthoritative((bool)(($header['meta'] & 0b0000010000000000) >> 10)); $message->isTruncated((bool)(($header['meta'] & 0b0000001000000000) >> 9)); $message->isRecursionDesired((bool)(($header['meta'] & 0b0000000100000000) >> 8)); $message->isRecursionAvailable((bool)(($header['meta'] & 0b0000000010000000) >> 7)); $message->setResponseCode($header['meta'] & 0b0000000000001111); $decodingContext->setExpectedQuestionRecords($header['qd']); $decodingContext->setExpectedAnswerRecords($header['an']); $decodingContext->setExpectedAuthorityRecords($header['ns']); $decodingContext->setExpectedAdditionalRecords($header['ar']); } /** * Decode an Anything field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\Anything $anything The object to populate with the result * @param int $length * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeAnything(DecodingContext $decodingContext, Anything $anything, int $length): int { $anything->setValue($this->readDataFromPacket($decodingContext->getPacket(), $length)); return $length; } /** * Decode a BitMap field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\BitMap $bitMap The object to populate with the result * @param int $length * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeBitMap(DecodingContext $decodingContext, BitMap $bitMap, int $length): int { $bitMap->setValue($this->readDataFromPacket($decodingContext->getPacket(), $length)); return $length; } /** * Decode a Char field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\Char $char The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeChar(DecodingContext $decodingContext, Char $char): int { $value = \unpack('C', $this->readDataFromPacket($decodingContext->getPacket(), 1))[1]; $char->setValue($value); return 1; } /** * Decode a CharacterString field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\CharacterString $characterString The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeCharacterString(DecodingContext $decodingContext, CharacterString $characterString): int { $packet = $decodingContext->getPacket(); $length = \ord($this->readDataFromPacket($packet, 1)); $characterString->setValue($this->readDataFromPacket($packet, $length)); return $length + 1; } /** * Decode a DomainName field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\DomainName $domainName The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeDomainName(DecodingContext $decodingContext, DomainName $domainName): int { $packet = $decodingContext->getPacket(); $startIndex = '0x' . \dechex($packet->getPointer()); $labelRegistry = $decodingContext->getLabelRegistry(); $labels = []; $totalLength = 0; while (++$totalLength && $length = \ord($this->readDataFromPacket($packet, 1))) { $labelType = $length & 0b11000000; if ($labelType === 0b00000000) { $index = $packet->getPointer() - 1; $label = $this->readDataFromPacket($packet, $length); \array_unshift($labels, [$index, $label]); $totalLength += $length; } else if ($labelType === 0b11000000) { $index = (($length & 0b00111111) << 8) | \ord($this->readDataFromPacket($packet, 1)); $ref = $labelRegistry->lookupLabel($index); if ($ref === null) { throw new \UnexpectedValueException('Decode error: Invalid compression pointer reference in domain name at position ' . $startIndex); } \array_unshift($labels, $ref); $totalLength++; break; } else { throw new \UnexpectedValueException('Decode error: Invalid label type ' . $labelType . 'in domain name at position ' . $startIndex); } } $result = []; foreach ($labels as $label) { if (\is_int($label[0])) { \array_unshift($result, $label[1]); $labelRegistry->register($result, $label[0]); } else { $result = $label; } } $domainName->setLabels($result); return $totalLength; } /** * Decode an IPv4Address field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\IPv4Address $ipv4Address The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeIPv4Address(DecodingContext $decodingContext, IPv4Address $ipv4Address): int { $octets = \unpack('C4', $this->readDataFromPacket($decodingContext->getPacket(), 4)); $ipv4Address->setOctets($octets); return 4; } /** * Decode an IPv6Address field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\IPv6Address $ipv6Address The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeIPv6Address(DecodingContext $decodingContext, IPv6Address $ipv6Address): int { $shorts = \unpack('n8', $this->readDataFromPacket($decodingContext->getPacket(), 16)); $ipv6Address->setShorts($shorts); return 16; } /** * Decode a Long field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\Long $long The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeLong(DecodingContext $decodingContext, Long $long): int { $value = \unpack('N', $this->readDataFromPacket($decodingContext->getPacket(), 4))[1]; $long->setValue($value); return 4; } /** * Decode a Short field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\Short $short The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeShort(DecodingContext $decodingContext, Short $short): int { $value = \unpack('n', $this->readDataFromPacket($decodingContext->getPacket(), 2))[1]; $short->setValue($value); return 2; } /** * Decode a Type field * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @param \LibDNS\Records\Types\Type $type The object to populate with the result * @param int $length Expected data length * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid * @throws \InvalidArgumentException When the Type subtype is unknown */ private function decodeType(DecodingContext $decodingContext, Type $type, int $length): int { if ($type instanceof Anything) { $result = $this->decodeAnything($decodingContext, $type, $length); } else if ($type instanceof BitMap) { $result = $this->decodeBitMap($decodingContext, $type, $length); } else if ($type instanceof Char) { $result = $this->decodeChar($decodingContext, $type); } else if ($type instanceof CharacterString) { $result = $this->decodeCharacterString($decodingContext, $type); } else if ($type instanceof DomainName) { $result = $this->decodeDomainName($decodingContext, $type); } else if ($type instanceof IPv4Address) { $result = $this->decodeIPv4Address($decodingContext, $type); } else if ($type instanceof IPv6Address) { $result = $this->decodeIPv6Address($decodingContext, $type); } else if ($type instanceof Long) { $result = $this->decodeLong($decodingContext, $type); } else if ($type instanceof Short) { $result = $this->decodeShort($decodingContext, $type); } else { throw new \InvalidArgumentException('Unknown Type ' . \get_class($type)); } return $result; } /** * Decode a question record * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @return \LibDNS\Records\Question * @throws \UnexpectedValueException When the record is invalid */ private function decodeQuestionRecord(DecodingContext $decodingContext): Question { /** @var \LibDNS\Records\Types\DomainName $domainName */ $domainName = $this->typeBuilder->build(Types::DOMAIN_NAME); $this->decodeDomainName($decodingContext, $domainName); $meta = \unpack('ntype/nclass', $this->readDataFromPacket($decodingContext->getPacket(), 4)); $question = $this->questionFactory->create($meta['type']); $question->setName($domainName); $question->setClass($meta['class']); return $question; } /** * Decode a resource record * * @param \LibDNS\Decoder\DecodingContext $decodingContext * @return \LibDNS\Records\Resource * @throws \UnexpectedValueException When the record is invalid * @throws \InvalidArgumentException When a type subtype is unknown */ private function decodeResourceRecord(DecodingContext $decodingContext): Resource { /** @var \LibDNS\Records\Types\DomainName $domainName */ $domainName = $this->typeBuilder->build(Types::DOMAIN_NAME); $this->decodeDomainName($decodingContext, $domainName); $meta = \unpack('ntype/nclass/Nttl/nlength', $this->readDataFromPacket($decodingContext->getPacket(), 10)); $resource = $this->resourceBuilder->build($meta['type']); $resource->setName($domainName); $resource->setClass($meta['class']); $resource->setTTL($meta['ttl']); $data = $resource->getData(); $remainingLength = $meta['length']; $fieldDef = $index = null; foreach ($resource->getData()->getTypeDefinition() as $index => $fieldDef) { $field = $this->typeBuilder->build($fieldDef->getType()); $remainingLength -= $this->decodeType($decodingContext, $field, $remainingLength); $data->setField($index, $field); } if ($fieldDef->allowsMultiple()) { while ($remainingLength) { $field = $this->typeBuilder->build($fieldDef->getType()); $remainingLength -= $this->decodeType($decodingContext, $field, $remainingLength); $data->setField(++$index, $field); } } if ($remainingLength !== 0) { throw new \UnexpectedValueException('Decode error: Invalid length for record data section'); } return $resource; } /** * Decode a Message from raw network data * * @param string $data The data string to decode * @return \LibDNS\Messages\Message * @throws \UnexpectedValueException When the packet data is invalid * @throws \InvalidArgumentException When a type subtype is unknown */ public function decode(string $data): Message { $packet = $this->packetFactory->create($data); $decodingContext = $this->decodingContextFactory->create($packet); $message = $this->messageFactory->create(); $this->decodeHeader($decodingContext, $message); $questionRecords = $message->getQuestionRecords(); $expected = $decodingContext->getExpectedQuestionRecords(); for ($i = 0; $i < $expected; $i++) { $questionRecords->add($this->decodeQuestionRecord($decodingContext)); } $answerRecords = $message->getAnswerRecords(); $expected = $decodingContext->getExpectedAnswerRecords(); for ($i = 0; $i < $expected; $i++) { $answerRecords->add($this->decodeResourceRecord($decodingContext)); } $authorityRecords = $message->getAuthorityRecords(); $expected = $decodingContext->getExpectedAuthorityRecords(); for ($i = 0; $i < $expected; $i++) { $authorityRecords->add($this->decodeResourceRecord($decodingContext)); } $additionalRecords = $message->getAdditionalRecords(); $expected = $decodingContext->getExpectedAdditionalRecords(); for ($i = 0; $i < $expected; $i++) { $additionalRecords->add($this->decodeResourceRecord($decodingContext)); } if (!$this->allowTrailingData && $packet->getBytesRemaining() !== 0) { throw new \UnexpectedValueException('Decode error: Unexpected data at end of packet'); } return $message; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Decoder; use \LibDNS\Packets\Packet; use \LibDNS\Packets\LabelRegistry; /** * Holds data associated with a decode operation * * @category LibDNS * @package Decoder * @author Chris Wright */ class DecodingContext { /** * @var \LibDNS\Packets\Packet */ private $packet; /** * @var \LibDNS\Packets\LabelRegistry */ private $labelRegistry; /** * @var int */ private $expectedQuestionRecords = 0; /** * @var int */ private $expectedAnswerRecords = 0; /** * @var int */ private $expectedAuthorityRecords = 0; /** * @var int */ private $expectedAdditionalRecords = 0; /** * Constructor * * @param \LibDNS\Packets\Packet $packet * @param \LibDNS\Packets\LabelRegistry $labelRegistry */ public function __construct(Packet $packet, LabelRegistry $labelRegistry) { $this->packet = $packet; $this->labelRegistry = $labelRegistry; } /** * Get the packet * * @return \LibDNS\Packets\Packet */ public function getPacket(): Packet { return $this->packet; } /** * Get the label registry * * @return \LibDNS\Packets\LabelRegistry */ public function getLabelRegistry(): LabelRegistry { return $this->labelRegistry; } /** * Get the number of question records expected in the message * * @return int */ public function getExpectedQuestionRecords(): int { return $this->expectedQuestionRecords; } /** * Get the number of question records expected in the message * * @param int $expectedQuestionRecords */ public function setExpectedQuestionRecords(int $expectedQuestionRecords) { $this->expectedQuestionRecords = $expectedQuestionRecords; } /** * Get the number of answer records expected in the message * * @return int */ public function getExpectedAnswerRecords(): int { return $this->expectedAnswerRecords; } /** * Set the number of answer records expected in the message * * @param int $expectedAnswerRecords */ public function setExpectedAnswerRecords(int $expectedAnswerRecords) { $this->expectedAnswerRecords = $expectedAnswerRecords; } /** * Get the number of authority records expected in the message * * @return int */ public function getExpectedAuthorityRecords(): int { return $this->expectedAuthorityRecords; } /** * Set the number of authority records expected in the message * * @param int $expectedAuthorityRecords */ public function setExpectedAuthorityRecords(int $expectedAuthorityRecords) { $this->expectedAuthorityRecords = $expectedAuthorityRecords; } /** * Get the number of additional records expected in the message * * @return int */ public function getExpectedAdditionalRecords(): int { return $this->expectedAdditionalRecords; } /** * Set the number of additional records expected in the message * * @param int $expectedAdditionalRecords */ public function setExpectedAdditionalRecords(int $expectedAdditionalRecords) { $this->expectedAdditionalRecords = $expectedAdditionalRecords; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Decoder; use \LibDNS\Packets\Packet; use \LibDNS\Packets\LabelRegistry; /** * Creates DecodingContext objects * * @category LibDNS * @package Decoder * @author Chris Wright */ class DecodingContextFactory { /** * Create a new DecodingContext object * * @param \LibDNS\Packets\Packet $packet The packet to be decoded * @return \LibDNS\Decoder\DecodingContext */ public function create(Packet $packet): DecodingContext { return new DecodingContext($packet, new LabelRegistry); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Decoder; use \LibDNS\Packets\PacketFactory; use \LibDNS\Messages\MessageFactory; use \LibDNS\Records\RecordCollectionFactory; use \LibDNS\Records\QuestionFactory; use \LibDNS\Records\ResourceBuilder; use \LibDNS\Records\ResourceFactory; use \LibDNS\Records\RDataBuilder; use \LibDNS\Records\RDataFactory; use \LibDNS\Records\Types\TypeBuilder; use \LibDNS\Records\Types\TypeFactory; use \LibDNS\Records\TypeDefinitions\TypeDefinitionManager; use \LibDNS\Records\TypeDefinitions\TypeDefinitionFactory; use \LibDNS\Records\TypeDefinitions\FieldDefinitionFactory; /** * Creates Decoder objects * * @category LibDNS * @package Decoder * @author Chris Wright */ class DecoderFactory { /** * Create a new Decoder object * * @param \LibDNS\Records\TypeDefinitions\TypeDefinitionManager $typeDefinitionManager * @param bool $allowTrailingData * @return Decoder */ public function create(TypeDefinitionManager $typeDefinitionManager = null, bool $allowTrailingData = true): Decoder { $typeBuilder = new TypeBuilder(new TypeFactory); return new Decoder( new PacketFactory, new MessageFactory(new RecordCollectionFactory), new QuestionFactory, new ResourceBuilder( new ResourceFactory, new RDataBuilder( new RDataFactory, $typeBuilder ), $typeDefinitionManager ?: new TypeDefinitionManager( new TypeDefinitionFactory, new FieldDefinitionFactory ) ), $typeBuilder, new DecodingContextFactory, $allowTrailingData ); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Messages; use \LibDNS\Enumeration; /** * Enumeration of possible message types * * @category LibDNS * @package Messages * @author Chris Wright */ final class MessageTypes extends Enumeration { const QUERY = 0; const RESPONSE = 1; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Messages; use \LibDNS\Enumeration; /** * Enumeration of possible message types * * @category LibDNS * @package Messages * @author Chris Wright */ final class MessageOpCodes extends Enumeration { const QUERY = 0; const IQUERY = 1; const STATUS = 2; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Messages; use LibDNS\Records\RecordCollection; use \LibDNS\Records\RecordCollectionFactory; use \LibDNS\Records\RecordTypes; /** * Represents a DNS protocol message * * @category LibDNS * @package Messages * @author Chris Wright */ class Message { /** * @var int Unsigned short that identifies the DNS transaction */ private $id = 0; /** * @var int Indicates the type of the message, can be indicated using the MessageTypes enum */ private $type = -1; /** * @var int Message opcode, can be indicated using the MessageOpCodes enum */ private $opCode = MessageOpCodes::QUERY; /** * @var bool Whether a response message is authoritative */ private $authoritative = false; /** * @var bool Whether the message is truncated */ private $truncated = false; /** * @var bool Whether a query desires the server to recurse the lookup */ private $recursionDesired = true; /** * @var bool Whether a server could provide recursion in a response */ private $recursionAvailable = false; /** * @var int Message response code, can be indicated using the MessageResponseCodes enum */ private $responseCode = MessageResponseCodes::NO_ERROR; /** * @var \LibDNS\Records\RecordCollection Collection of question records */ private $questionRecords; /** * @var \LibDNS\Records\RecordCollection Collection of question records */ private $answerRecords; /** * @var \LibDNS\Records\RecordCollection Collection of authority records */ private $authorityRecords; /** * @var \LibDNS\Records\RecordCollection Collection of authority records */ private $additionalRecords; /** * Constructor * * @param \LibDNS\Records\RecordCollectionFactory $recordCollectionFactory Factory which makes RecordCollection objects * @param int $type Value of the message type field * @throws \RangeException When the supplied message type is outside the valid range 0 - 1 */ public function __construct(RecordCollectionFactory $recordCollectionFactory, int $type = null) { $this->questionRecords = $recordCollectionFactory->create(RecordTypes::QUESTION); $this->answerRecords = $recordCollectionFactory->create(RecordTypes::RESOURCE); $this->authorityRecords = $recordCollectionFactory->create(RecordTypes::RESOURCE); $this->additionalRecords = $recordCollectionFactory->create(RecordTypes::RESOURCE); if ($type !== null) { $this->setType($type); } } /** * Get the value of the message ID field * * @return int */ public function getID(): int { return $this->id; } /** * Set the value of the message ID field * * @param int $id The new value * @throws \RangeException When the supplied value is outside the valid range 0 - 65535 */ public function setID(int $id) { if ($id < 0 || $id > 65535) { throw new \RangeException('Message ID must be in the range 0 - 65535'); } $this->id = $id; } /** * Get the value of the message type field * * @return int */ public function getType(): int { return $this->type; } /** * Set the value of the message type field * * @param int $type The new value * @throws \RangeException When the supplied value is outside the valid range 0 - 1 */ public function setType(int $type) { if ($type < 0 || $type > 1) { throw new \RangeException('Message type must be in the range 0 - 1'); } $this->type = $type; } /** * Get the value of the message opcode field * * @return int */ public function getOpCode(): int { return $this->opCode; } /** * Set the value of the message opcode field * * @param int $opCode The new value * @throws \RangeException When the supplied value is outside the valid range 0 - 15 */ public function setOpCode(int $opCode) { if ($opCode < 0 || $opCode > 15) { throw new \RangeException('Message opcode must be in the range 0 - 15'); } $this->opCode = $opCode; } /** * Inspect the value of the authoritative field and optionally set a new value * * @param bool $newValue The new value * @return bool The old value */ public function isAuthoritative(bool $newValue = null): bool { $result = $this->authoritative; if ($newValue !== null) { $this->authoritative = $newValue; } return $result; } /** * Inspect the value of the truncated field and optionally set a new value * * @param bool $newValue The new value * @return bool The old value */ public function isTruncated(bool $newValue = null): bool { $result = $this->truncated; if ($newValue !== null) { $this->truncated = $newValue; } return $result; } /** * Inspect the value of the recusion desired field and optionally set a new value * * @param bool $newValue The new value * @return bool The old value */ public function isRecursionDesired(bool $newValue = null): bool { $result = $this->recursionDesired; if ($newValue !== null) { $this->recursionDesired = $newValue; } return $result; } /** * Inspect the value of the recursion available field and optionally set a new value * * @param bool $newValue The new value * @return bool The old value */ public function isRecursionAvailable(bool $newValue = null): bool { $result = $this->recursionAvailable; if ($newValue !== null) { $this->recursionAvailable = $newValue; } return $result; } /** * Get the value of the message response code field * * @return int */ public function getResponseCode(): int { return $this->opCode; } /** * Set the value of the message response code field * * @param int $responseCode The new value * @throws \RangeException When the supplied value is outside the valid range 0 - 15 */ public function setResponseCode(int $responseCode) { if ($responseCode < 0 || $responseCode > 15) { throw new \RangeException('Message response code must be in the range 0 - 15'); } $this->responseCode = $responseCode; } /** * Get the question records collection * * @return \LibDNS\Records\RecordCollection */ public function getQuestionRecords(): RecordCollection { return $this->questionRecords; } /** * Get the answer records collection * * @return \LibDNS\Records\RecordCollection */ public function getAnswerRecords(): RecordCollection { return $this->answerRecords; } /** * Get the authority records collection * * @return \LibDNS\Records\RecordCollection */ public function getAuthorityRecords(): RecordCollection { return $this->authorityRecords; } /** * Get the additional records collection * * @return \LibDNS\Records\RecordCollection */ public function getAdditionalRecords(): RecordCollection { return $this->additionalRecords; } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Messages; use \LibDNS\Enumeration; /** * Enumeration of possible message types * * @category LibDNS * @package Messages * @author Chris Wright */ final class MessageResponseCodes extends Enumeration { const NO_ERROR = 0; const FORMAT_ERROR = 1; const SERVER_FAILURE = 2; const NAME_ERROR = 3; const NOT_IMPLEMENTED = 4; const REFUSED = 5; } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS\Messages; use \LibDNS\Records\RecordCollectionFactory; /** * Factory which creates Message objects * * @category LibDNS * @package Messages * @author Chris Wright */ class MessageFactory { /** * Create a new Message object * * @param int $type Value of the message type field * @return \LibDNS\Messages\Message */ public function create(int $type = null): Message { return new Message(new RecordCollectionFactory, $type); } } * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace LibDNS; /** * Base class for enumerations to prevent instantiation * * @category LibDNS * @package LibDNS * @author Chris Wright */ abstract class Enumeration { final protected function __construct() { throw new \LogicException('Enumerations cannot be instantiated'); } } textElements($text); # convert to markup $markup = $this->elements($Elements); # trim line breaks $markup = trim($markup, "\n"); return $markup; } protected function textElements($text) { # make sure no definitions are set $this->DefinitionData = array(); # standardize line breaks $text = str_replace(array("\r\n", "\r"), "\n", $text); # remove surrounding line breaks $text = trim($text, "\n"); # split text into lines $lines = explode("\n", $text); # iterate through lines to identify blocks return $this->linesElements($lines); } # # Setters # function setBreaksEnabled($breaksEnabled) { $this->breaksEnabled = $breaksEnabled; return $this; } protected $breaksEnabled; function setMarkupEscaped($markupEscaped) { $this->markupEscaped = $markupEscaped; return $this; } protected $markupEscaped; function setUrlsLinked($urlsLinked) { $this->urlsLinked = $urlsLinked; return $this; } protected $urlsLinked = true; function setSafeMode($safeMode) { $this->safeMode = (bool) $safeMode; return $this; } protected $safeMode; function setStrictMode($strictMode) { $this->strictMode = (bool) $strictMode; return $this; } protected $strictMode; protected $safeLinksWhitelist = array( 'http://', 'https://', 'ftp://', 'ftps://', 'mailto:', 'data:image/png;base64,', 'data:image/gif;base64,', 'data:image/jpeg;base64,', 'irc:', 'ircs:', 'git:', 'ssh:', 'news:', 'steam:', ); # # Lines # protected $BlockTypes = array( '#' => array('Header'), '*' => array('Rule', 'List'), '+' => array('List'), '-' => array('SetextHeader', 'Table', 'Rule', 'List'), '0' => array('List'), '1' => array('List'), '2' => array('List'), '3' => array('List'), '4' => array('List'), '5' => array('List'), '6' => array('List'), '7' => array('List'), '8' => array('List'), '9' => array('List'), ':' => array('Table'), '<' => array('Comment', 'Markup'), '=' => array('SetextHeader'), '>' => array('Quote'), '[' => array('Reference'), '_' => array('Rule'), '`' => array('FencedCode'), '|' => array('Table'), '~' => array('FencedCode'), ); # ~ protected $unmarkedBlockTypes = array( 'Code', ); # # Blocks # protected function lines(array $lines) { return $this->elements($this->linesElements($lines)); } protected function linesElements(array $lines) { $Elements = array(); $CurrentBlock = null; foreach ($lines as $line) { if (chop($line) === '') { if (isset($CurrentBlock)) { $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted']) ? $CurrentBlock['interrupted'] + 1 : 1 ); } continue; } while (($beforeTab = strstr($line, "\t", true)) !== false) { $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; $line = $beforeTab . str_repeat(' ', $shortage) . substr($line, strlen($beforeTab) + 1) ; } $indent = strspn($line, ' '); $text = $indent > 0 ? substr($line, $indent) : $line; # ~ $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); # ~ if (isset($CurrentBlock['continuable'])) { $methodName = 'block' . $CurrentBlock['type'] . 'Continue'; $Block = $this->$methodName($Line, $CurrentBlock); if (isset($Block)) { $CurrentBlock = $Block; continue; } else { if ($this->isBlockCompletable($CurrentBlock['type'])) { $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; $CurrentBlock = $this->$methodName($CurrentBlock); } } } # ~ $marker = $text[0]; # ~ $blockTypes = $this->unmarkedBlockTypes; if (isset($this->BlockTypes[$marker])) { foreach ($this->BlockTypes[$marker] as $blockType) { $blockTypes []= $blockType; } } # # ~ foreach ($blockTypes as $blockType) { $Block = $this->{"block$blockType"}($Line, $CurrentBlock); if (isset($Block)) { $Block['type'] = $blockType; if ( ! isset($Block['identified'])) { if (isset($CurrentBlock)) { $Elements[] = $this->extractElement($CurrentBlock); } $Block['identified'] = true; } if ($this->isBlockContinuable($blockType)) { $Block['continuable'] = true; } $CurrentBlock = $Block; continue 2; } } # ~ if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph') { $Block = $this->paragraphContinue($Line, $CurrentBlock); } if (isset($Block)) { $CurrentBlock = $Block; } else { if (isset($CurrentBlock)) { $Elements[] = $this->extractElement($CurrentBlock); } $CurrentBlock = $this->paragraph($Line); $CurrentBlock['identified'] = true; } } # ~ if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) { $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; $CurrentBlock = $this->$methodName($CurrentBlock); } # ~ if (isset($CurrentBlock)) { $Elements[] = $this->extractElement($CurrentBlock); } # ~ return $Elements; } protected function extractElement(array $Component) { if ( ! isset($Component['element'])) { if (isset($Component['markup'])) { $Component['element'] = array('rawHtml' => $Component['markup']); } elseif (isset($Component['hidden'])) { $Component['element'] = array(); } } return $Component['element']; } protected function isBlockContinuable($Type) { return method_exists($this, 'block' . $Type . 'Continue'); } protected function isBlockCompletable($Type) { return method_exists($this, 'block' . $Type . 'Complete'); } # # Code protected function blockCode($Line, $Block = null) { if (isset($Block) and $Block['type'] === 'Paragraph' and ! isset($Block['interrupted'])) { return; } if ($Line['indent'] >= 4) { $text = substr($Line['body'], 4); $Block = array( 'element' => array( 'name' => 'pre', 'element' => array( 'name' => 'code', 'text' => $text, ), ), ); return $Block; } } protected function blockCodeContinue($Line, $Block) { if ($Line['indent'] >= 4) { if (isset($Block['interrupted'])) { $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); unset($Block['interrupted']); } $Block['element']['element']['text'] .= "\n"; $text = substr($Line['body'], 4); $Block['element']['element']['text'] .= $text; return $Block; } } protected function blockCodeComplete($Block) { return $Block; } # # Comment protected function blockComment($Line) { if ($this->markupEscaped or $this->safeMode) { return; } if (strpos($Line['text'], '') !== false) { $Block['closed'] = true; } return $Block; } } protected function blockCommentContinue($Line, array $Block) { if (isset($Block['closed'])) { return; } $Block['element']['rawHtml'] .= "\n" . $Line['body']; if (strpos($Line['text'], '-->') !== false) { $Block['closed'] = true; } return $Block; } # # Fenced Code protected function blockFencedCode($Line) { $marker = $Line['text'][0]; $openerLength = strspn($Line['text'], $marker); if ($openerLength < 3) { return; } $infostring = trim(substr($Line['text'], $openerLength), "\t "); if (strpos($infostring, '`') !== false) { return; } $Element = array( 'name' => 'code', 'text' => '', ); if ($infostring !== '') { /** * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes * Every HTML element may have a class attribute specified. * The attribute, if specified, must have a value that is a set * of space-separated tokens representing the various classes * that the element belongs to. * [...] * The space characters, for the purposes of this specification, * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and * U+000D CARRIAGE RETURN (CR). */ $language = substr($infostring, 0, strcspn($infostring, " \t\n\f\r")); $Element['attributes'] = array('class' => "language-$language"); } $Block = array( 'char' => $marker, 'openerLength' => $openerLength, 'element' => array( 'name' => 'pre', 'element' => $Element, ), ); return $Block; } protected function blockFencedCodeContinue($Line, $Block) { if (isset($Block['complete'])) { return; } if (isset($Block['interrupted'])) { $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); unset($Block['interrupted']); } if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] and chop(substr($Line['text'], $len), ' ') === '' ) { $Block['element']['element']['text'] = substr($Block['element']['element']['text'], 1); $Block['complete'] = true; return $Block; } $Block['element']['element']['text'] .= "\n" . $Line['body']; return $Block; } protected function blockFencedCodeComplete($Block) { return $Block; } # # Header protected function blockHeader($Line) { $level = strspn($Line['text'], '#'); if ($level > 6) { return; } $text = trim($Line['text'], '#'); if ($this->strictMode and isset($text[0]) and $text[0] !== ' ') { return; } $text = trim($text, ' '); $Block = array( 'element' => array( 'name' => 'h' . min(6, $level), 'handler' => array( 'function' => 'lineElements', 'argument' => $text, 'destination' => 'elements', ) ), ); return $Block; } # # List protected function blockList($Line, array $CurrentBlock = null) { list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}+[.\)]'); if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) { $contentIndent = strlen($matches[2]); if ($contentIndent >= 5) { $contentIndent -= 1; $matches[1] = substr($matches[1], 0, -$contentIndent); $matches[3] = str_repeat(' ', $contentIndent) . $matches[3]; } elseif ($contentIndent === 0) { $matches[1] .= ' '; } $markerWithoutWhitespace = strstr($matches[1], ' ', true); $Block = array( 'indent' => $Line['indent'], 'pattern' => $pattern, 'data' => array( 'type' => $name, 'marker' => $matches[1], 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)), ), 'element' => array( 'name' => $name, 'elements' => array(), ), ); $Block['data']['markerTypeRegex'] = preg_quote($Block['data']['markerType'], '/'); if ($name === 'ol') { $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; if ($listStart !== '1') { if ( isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph' and ! isset($CurrentBlock['interrupted']) ) { return; } $Block['element']['attributes'] = array('start' => $listStart); } } $Block['li'] = array( 'name' => 'li', 'handler' => array( 'function' => 'li', 'argument' => !empty($matches[3]) ? array($matches[3]) : array(), 'destination' => 'elements' ) ); $Block['element']['elements'] []= & $Block['li']; return $Block; } } protected function blockListContinue($Line, array $Block) { if (isset($Block['interrupted']) and empty($Block['li']['handler']['argument'])) { return null; } $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); if ($Line['indent'] < $requiredIndent and ( ( $Block['data']['type'] === 'ol' and preg_match('/^[0-9]++'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) ) or ( $Block['data']['type'] === 'ul' and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) ) ) ) { if (isset($Block['interrupted'])) { $Block['li']['handler']['argument'] []= ''; $Block['loose'] = true; unset($Block['interrupted']); } unset($Block['li']); $text = isset($matches[1]) ? $matches[1] : ''; $Block['indent'] = $Line['indent']; $Block['li'] = array( 'name' => 'li', 'handler' => array( 'function' => 'li', 'argument' => array($text), 'destination' => 'elements' ) ); $Block['element']['elements'] []= & $Block['li']; return $Block; } elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line)) { return null; } if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; } if ($Line['indent'] >= $requiredIndent) { if (isset($Block['interrupted'])) { $Block['li']['handler']['argument'] []= ''; $Block['loose'] = true; unset($Block['interrupted']); } $text = substr($Line['body'], $requiredIndent); $Block['li']['handler']['argument'] []= $text; return $Block; } if ( ! isset($Block['interrupted'])) { $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}+/', '', $Line['body']); $Block['li']['handler']['argument'] []= $text; return $Block; } } protected function blockListComplete(array $Block) { if (isset($Block['loose'])) { foreach ($Block['element']['elements'] as &$li) { if (end($li['handler']['argument']) !== '') { $li['handler']['argument'] []= ''; } } } return $Block; } # # Quote protected function blockQuote($Line) { if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) { $Block = array( 'element' => array( 'name' => 'blockquote', 'handler' => array( 'function' => 'linesElements', 'argument' => (array) $matches[1], 'destination' => 'elements', ) ), ); return $Block; } } protected function blockQuoteContinue($Line, array $Block) { if (isset($Block['interrupted'])) { return; } if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) { $Block['element']['handler']['argument'] []= $matches[1]; return $Block; } if ( ! isset($Block['interrupted'])) { $Block['element']['handler']['argument'] []= $Line['text']; return $Block; } } # # Rule protected function blockRule($Line) { $marker = $Line['text'][0]; if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') { $Block = array( 'element' => array( 'name' => 'hr', ), ); return $Block; } } # # Setext protected function blockSetextHeader($Line, array $Block = null) { if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) { return; } if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '') { $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; return $Block; } } # # Markup protected function blockMarkup($Line) { if ($this->markupEscaped or $this->safeMode) { return; } if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches)) { $element = strtolower($matches[1]); if (in_array($element, $this->textLevelElements)) { return; } $Block = array( 'name' => $matches[1], 'element' => array( 'rawHtml' => $Line['text'], 'autobreak' => true, ), ); return $Block; } } protected function blockMarkupContinue($Line, array $Block) { if (isset($Block['closed']) or isset($Block['interrupted'])) { return; } $Block['element']['rawHtml'] .= "\n" . $Line['body']; return $Block; } # # Reference protected function blockReference($Line) { if (strpos($Line['text'], ']') !== false and preg_match('/^\[(.+?)\]:[ ]*+?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) ) { $id = strtolower($matches[1]); $Data = array( 'url' => $matches[2], 'title' => isset($matches[3]) ? $matches[3] : null, ); $this->DefinitionData['Reference'][$id] = $Data; $Block = array( 'element' => array(), ); return $Block; } } # # Table protected function blockTable($Line, array $Block = null) { if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) { return; } if ( strpos($Block['element']['handler']['argument'], '|') === false and strpos($Line['text'], '|') === false and strpos($Line['text'], ':') === false or strpos($Block['element']['handler']['argument'], "\n") !== false ) { return; } if (chop($Line['text'], ' -:|') !== '') { return; } $alignments = array(); $divider = $Line['text']; $divider = trim($divider); $divider = trim($divider, '|'); $dividerCells = explode('|', $divider); foreach ($dividerCells as $dividerCell) { $dividerCell = trim($dividerCell); if ($dividerCell === '') { return; } $alignment = null; if ($dividerCell[0] === ':') { $alignment = 'left'; } if (substr($dividerCell, - 1) === ':') { $alignment = $alignment === 'left' ? 'center' : 'right'; } $alignments []= $alignment; } # ~ $HeaderElements = array(); $header = $Block['element']['handler']['argument']; $header = trim($header); $header = trim($header, '|'); $headerCells = explode('|', $header); if (count($headerCells) !== count($alignments)) { return; } foreach ($headerCells as $index => $headerCell) { $headerCell = trim($headerCell); $HeaderElement = array( 'name' => 'th', 'handler' => array( 'function' => 'lineElements', 'argument' => $headerCell, 'destination' => 'elements', ) ); if (isset($alignments[$index])) { $alignment = $alignments[$index]; $HeaderElement['attributes'] = array( 'style' => "text-align: $alignment;", ); } $HeaderElements []= $HeaderElement; } # ~ $Block = array( 'alignments' => $alignments, 'identified' => true, 'element' => array( 'name' => 'table', 'elements' => array(), ), ); $Block['element']['elements'] []= array( 'name' => 'thead', ); $Block['element']['elements'] []= array( 'name' => 'tbody', 'elements' => array(), ); $Block['element']['elements'][0]['elements'] []= array( 'name' => 'tr', 'elements' => $HeaderElements, ); return $Block; } protected function blockTableContinue($Line, array $Block) { if (isset($Block['interrupted'])) { return; } if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|')) { $Elements = array(); $row = $Line['text']; $row = trim($row); $row = trim($row, '|'); preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]++`|`)++/', $row, $matches); $cells = array_slice($matches[0], 0, count($Block['alignments'])); foreach ($cells as $index => $cell) { $cell = trim($cell); $Element = array( 'name' => 'td', 'handler' => array( 'function' => 'lineElements', 'argument' => $cell, 'destination' => 'elements', ) ); if (isset($Block['alignments'][$index])) { $Element['attributes'] = array( 'style' => 'text-align: ' . $Block['alignments'][$index] . ';', ); } $Elements []= $Element; } $Element = array( 'name' => 'tr', 'elements' => $Elements, ); $Block['element']['elements'][1]['elements'] []= $Element; return $Block; } } # # ~ # protected function paragraph($Line) { return array( 'type' => 'Paragraph', 'element' => array( 'name' => 'p', 'handler' => array( 'function' => 'lineElements', 'argument' => $Line['text'], 'destination' => 'elements', ), ), ); } protected function paragraphContinue($Line, array $Block) { if (isset($Block['interrupted'])) { return; } $Block['element']['handler']['argument'] .= "\n".$Line['text']; return $Block; } # # Inline Elements # protected $InlineTypes = array( '!' => array('Image'), '&' => array('SpecialCharacter'), '*' => array('Emphasis'), ':' => array('Url'), '<' => array('UrlTag', 'EmailTag', 'Markup'), '[' => array('Link'), '_' => array('Emphasis'), '`' => array('Code'), '~' => array('Strikethrough'), '\\' => array('EscapeSequence'), ); # ~ protected $inlineMarkerList = '!*_&[:<`~\\'; # # ~ # public function line($text, $nonNestables = array()) { return $this->elements($this->lineElements($text, $nonNestables)); } protected function lineElements($text, $nonNestables = array()) { $Elements = array(); $nonNestables = (empty($nonNestables) ? array() : array_combine($nonNestables, $nonNestables) ); # $excerpt is based on the first occurrence of a marker while ($excerpt = strpbrk($text, $this->inlineMarkerList)) { $marker = $excerpt[0]; $markerPosition = strlen($text) - strlen($excerpt); $Excerpt = array('text' => $excerpt, 'context' => $text); foreach ($this->InlineTypes[$marker] as $inlineType) { # check to see if the current inline type is nestable in the current context if (isset($nonNestables[$inlineType])) { continue; } $Inline = $this->{"inline$inlineType"}($Excerpt); if ( ! isset($Inline)) { continue; } # makes sure that the inline belongs to "our" marker if (isset($Inline['position']) and $Inline['position'] > $markerPosition) { continue; } # sets a default inline position if ( ! isset($Inline['position'])) { $Inline['position'] = $markerPosition; } # cause the new element to 'inherit' our non nestables $Inline['element']['nonNestables'] = isset($Inline['element']['nonNestables']) ? array_merge($Inline['element']['nonNestables'], $nonNestables) : $nonNestables ; # the text that comes before the inline $unmarkedText = substr($text, 0, $Inline['position']); # compile the unmarked text $InlineText = $this->inlineText($unmarkedText); $Elements[] = $InlineText['element']; # compile the inline $Elements[] = $this->extractElement($Inline); # remove the examined text $text = substr($text, $Inline['position'] + $Inline['extent']); continue 2; } # the marker does not belong to an inline $unmarkedText = substr($text, 0, $markerPosition + 1); $InlineText = $this->inlineText($unmarkedText); $Elements[] = $InlineText['element']; $text = substr($text, $markerPosition + 1); } $InlineText = $this->inlineText($text); $Elements[] = $InlineText['element']; foreach ($Elements as &$Element) { if ( ! isset($Element['autobreak'])) { $Element['autobreak'] = false; } } return $Elements; } # # ~ # protected function inlineText($text) { $Inline = array( 'extent' => strlen($text), 'element' => array(), ); $Inline['element']['elements'] = self::pregReplaceElements( $this->breaksEnabled ? '/[ ]*+\n/' : '/(?:[ ]*+\\\\|[ ]{2,}+)\n/', array( array('name' => 'br'), array('text' => "\n"), ), $text ); return $Inline; } protected function inlineCode($Excerpt) { $marker = $Excerpt['text'][0]; if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(? strlen($matches[0]), 'element' => array( 'name' => 'code', 'text' => $text, ), ); } } protected function inlineEmailTag($Excerpt) { $hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?'; $commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@' . $hostnameLabel . '(?:\.' . $hostnameLabel . ')*'; if (strpos($Excerpt['text'], '>') !== false and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) ){ $url = $matches[1]; if ( ! isset($matches[2])) { $url = "mailto:$url"; } return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => 'a', 'text' => $matches[1], 'attributes' => array( 'href' => $url, ), ), ); } } protected function inlineEmphasis($Excerpt) { if ( ! isset($Excerpt['text'][1])) { return; } $marker = $Excerpt['text'][0]; if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) { $emphasis = 'strong'; } elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) { $emphasis = 'em'; } else { return; } return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => $emphasis, 'handler' => array( 'function' => 'lineElements', 'argument' => $matches[1], 'destination' => 'elements', ) ), ); } protected function inlineEscapeSequence($Excerpt) { if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) { return array( 'element' => array('rawHtml' => $Excerpt['text'][1]), 'extent' => 2, ); } } protected function inlineImage($Excerpt) { if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') { return; } $Excerpt['text']= substr($Excerpt['text'], 1); $Link = $this->inlineLink($Excerpt); if ($Link === null) { return; } $Inline = array( 'extent' => $Link['extent'] + 1, 'element' => array( 'name' => 'img', 'attributes' => array( 'src' => $Link['element']['attributes']['href'], 'alt' => $Link['element']['handler']['argument'], ), 'autobreak' => true, ), ); $Inline['element']['attributes'] += $Link['element']['attributes']; unset($Inline['element']['attributes']['href']); return $Inline; } protected function inlineLink($Excerpt) { $Element = array( 'name' => 'a', 'handler' => array( 'function' => 'lineElements', 'argument' => null, 'destination' => 'elements', ), 'nonNestables' => array('Url', 'Link'), 'attributes' => array( 'href' => null, 'title' => null, ), ); $extent = 0; $remainder = $Excerpt['text']; if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) { $Element['handler']['argument'] = $matches[1]; $extent += strlen($matches[0]); $remainder = substr($remainder, $extent); } else { return; } if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) { $Element['attributes']['href'] = $matches[1]; if (isset($matches[2])) { $Element['attributes']['title'] = substr($matches[2], 1, - 1); } $extent += strlen($matches[0]); } else { if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) { $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; $definition = strtolower($definition); $extent += strlen($matches[0]); } else { $definition = strtolower($Element['handler']['argument']); } if ( ! isset($this->DefinitionData['Reference'][$definition])) { return; } $Definition = $this->DefinitionData['Reference'][$definition]; $Element['attributes']['href'] = $Definition['url']; $Element['attributes']['title'] = $Definition['title']; } return array( 'extent' => $extent, 'element' => $Element, ); } protected function inlineMarkup($Excerpt) { if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) { return; } if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) { return array( 'element' => array('rawHtml' => $matches[0]), 'extent' => strlen($matches[0]), ); } if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) { return array( 'element' => array('rawHtml' => $matches[0]), 'extent' => strlen($matches[0]), ); } if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) { return array( 'element' => array('rawHtml' => $matches[0]), 'extent' => strlen($matches[0]), ); } } protected function inlineSpecialCharacter($Excerpt) { if ($Excerpt['text'][1] !== ' ' and strpos($Excerpt['text'], ';') !== false and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) ) { return array( 'element' => array('rawHtml' => '&' . $matches[1] . ';'), 'extent' => strlen($matches[0]), ); } return; } protected function inlineStrikethrough($Excerpt) { if ( ! isset($Excerpt['text'][1])) { return; } if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) { return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => 'del', 'handler' => array( 'function' => 'lineElements', 'argument' => $matches[1], 'destination' => 'elements', ) ), ); } } protected function inlineUrl($Excerpt) { if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') { return; } if (strpos($Excerpt['context'], 'http') !== false and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE) ) { $url = $matches[0][0]; $Inline = array( 'extent' => strlen($matches[0][0]), 'position' => $matches[0][1], 'element' => array( 'name' => 'a', 'text' => $url, 'attributes' => array( 'href' => $url, ), ), ); return $Inline; } } protected function inlineUrlTag($Excerpt) { if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) { $url = $matches[1]; return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => 'a', 'text' => $url, 'attributes' => array( 'href' => $url, ), ), ); } } # ~ protected function unmarkedText($text) { $Inline = $this->inlineText($text); return $this->element($Inline['element']); } # # Handlers # protected function handle(array $Element) { if (isset($Element['handler'])) { if (!isset($Element['nonNestables'])) { $Element['nonNestables'] = array(); } if (is_string($Element['handler'])) { $function = $Element['handler']; $argument = $Element['text']; unset($Element['text']); $destination = 'rawHtml'; } else { $function = $Element['handler']['function']; $argument = $Element['handler']['argument']; $destination = $Element['handler']['destination']; } $Element[$destination] = $this->{$function}($argument, $Element['nonNestables']); if ($destination === 'handler') { $Element = $this->handle($Element); } unset($Element['handler']); } return $Element; } protected function handleElementRecursive(array $Element) { return $this->elementApplyRecursive(array($this, 'handle'), $Element); } protected function handleElementsRecursive(array $Elements) { return $this->elementsApplyRecursive(array($this, 'handle'), $Elements); } protected function elementApplyRecursive($closure, array $Element) { $Element = call_user_func($closure, $Element); if (isset($Element['elements'])) { $Element['elements'] = $this->elementsApplyRecursive($closure, $Element['elements']); } elseif (isset($Element['element'])) { $Element['element'] = $this->elementApplyRecursive($closure, $Element['element']); } return $Element; } protected function elementApplyRecursiveDepthFirst($closure, array $Element) { if (isset($Element['elements'])) { $Element['elements'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['elements']); } elseif (isset($Element['element'])) { $Element['element'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['element']); } $Element = call_user_func($closure, $Element); return $Element; } protected function elementsApplyRecursive($closure, array $Elements) { foreach ($Elements as &$Element) { $Element = $this->elementApplyRecursive($closure, $Element); } return $Elements; } protected function elementsApplyRecursiveDepthFirst($closure, array $Elements) { foreach ($Elements as &$Element) { $Element = $this->elementApplyRecursiveDepthFirst($closure, $Element); } return $Elements; } protected function element(array $Element) { if ($this->safeMode) { $Element = $this->sanitiseElement($Element); } # identity map if element has no handler $Element = $this->handle($Element); $hasName = isset($Element['name']); $markup = ''; if ($hasName) { $markup .= '<' . $Element['name']; if (isset($Element['attributes'])) { foreach ($Element['attributes'] as $name => $value) { if ($value === null) { continue; } $markup .= " $name=\"".self::escape($value).'"'; } } } $permitRawHtml = false; if (isset($Element['text'])) { $text = $Element['text']; } // very strongly consider an alternative if you're writing an // extension elseif (isset($Element['rawHtml'])) { $text = $Element['rawHtml']; $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; } $hasContent = isset($text) || isset($Element['element']) || isset($Element['elements']); if ($hasContent) { $markup .= $hasName ? '>' : ''; if (isset($Element['elements'])) { $markup .= $this->elements($Element['elements']); } elseif (isset($Element['element'])) { $markup .= $this->element($Element['element']); } else { if (!$permitRawHtml) { $markup .= self::escape($text, true); } else { $markup .= $text; } } $markup .= $hasName ? '' : ''; } elseif ($hasName) { $markup .= ' />'; } return $markup; } protected function elements(array $Elements) { $markup = ''; $autoBreak = true; foreach ($Elements as $Element) { if (empty($Element)) { continue; } $autoBreakNext = (isset($Element['autobreak']) ? $Element['autobreak'] : isset($Element['name']) ); // (autobreak === false) covers both sides of an element $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext; $markup .= ($autoBreak ? "\n" : '') . $this->element($Element); $autoBreak = $autoBreakNext; } $markup .= $autoBreak ? "\n" : ''; return $markup; } # ~ protected function li($lines) { $Elements = $this->linesElements($lines); if ( ! in_array('', $lines) and isset($Elements[0]) and isset($Elements[0]['name']) and $Elements[0]['name'] === 'p' ) { unset($Elements[0]['name']); } return $Elements; } # # AST Convenience # /** * Replace occurrences $regexp with $Elements in $text. Return an array of * elements representing the replacement. */ protected static function pregReplaceElements($regexp, $Elements, $text) { $newElements = array(); while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE)) { $offset = $matches[0][1]; $before = substr($text, 0, $offset); $after = substr($text, $offset + strlen($matches[0][0])); $newElements[] = array('text' => $before); foreach ($Elements as $Element) { $newElements[] = $Element; } $text = $after; } $newElements[] = array('text' => $text); return $newElements; } # # Deprecated Methods # function parse($text) { $markup = $this->text($text); return $markup; } protected function sanitiseElement(array $Element) { static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; static $safeUrlNameToAtt = array( 'a' => 'href', 'img' => 'src', ); if ( ! isset($Element['name'])) { unset($Element['attributes']); return $Element; } if (isset($safeUrlNameToAtt[$Element['name']])) { $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); } if ( ! empty($Element['attributes'])) { foreach ($Element['attributes'] as $att => $val) { # filter out badly parsed attribute if ( ! preg_match($goodAttribute, $att)) { unset($Element['attributes'][$att]); } # dump onevent attribute elseif (self::striAtStart($att, 'on')) { unset($Element['attributes'][$att]); } } } return $Element; } protected function filterUnsafeUrlInAttribute(array $Element, $attribute) { foreach ($this->safeLinksWhitelist as $scheme) { if (self::striAtStart($Element['attributes'][$attribute], $scheme)) { return $Element; } } $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); return $Element; } # # Static Methods # protected static function escape($text, $allowQuotes = false) { return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); } protected static function striAtStart($string, $needle) { $len = strlen($needle); if ($len > strlen($string)) { return false; } else { return strtolower(substr($string, 0, $len)) === strtolower($needle); } } static function instance($name = 'default') { if (isset(self::$instances[$name])) { return self::$instances[$name]; } $instance = new static(); self::$instances[$name] = $instance; return $instance; } private static $instances = array(); # # Fields # protected $DefinitionData; # # Read-Only protected $specialCharacters = array( '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', '~' ); protected $StrongRegex = array( '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*+[*])+?)[*]{2}(?![*])/s', '_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us', ); protected $EmRegex = array( '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', ); protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+'; protected $voidElements = array( 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', ); protected $textLevelElements = array( 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', 'i', 'rp', 'del', 'code', 'strike', 'marquee', 'q', 'rt', 'ins', 'font', 'strong', 's', 'tt', 'kbd', 'mark', 'u', 'xm', 'sub', 'nobr', 'sup', 'ruby', 'var', 'span', 'wbr', 'time', ); } { "name": "erusev/parsedown", "description": "Parser for Markdown.", "keywords": ["markdown", "parser"], "homepage": "http://parsedown.org", "type": "library", "license": "MIT", "authors": [ { "name": "Emanuil Rusev", "email": "hello@erusev.com", "homepage": "http://erusev.com" } ], "require": { "php": ">=5.3.0", "ext-mbstring": "*" }, "require-dev": { "phpunit/phpunit": "^4.8.35" }, "autoload": { "psr-0": {"Parsedown": ""} }, "autoload-dev": { "psr-0": { "TestParsedown": "test/", "ParsedownTest": "test/", "CommonMarkTest": "test/", "CommonMarkTestWeak": "test/" } } } { "name": "psr/http-message", "description": "Common interface for HTTP messages", "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"], "homepage": "https://github.com/php-fig/http-message", "license": "MIT", "authors": [ { "name": "PHP-FIG", "homepage": "http://www.php-fig.org/" } ], "require": { "php": ">=5.3.0" }, "autoload": { "psr-4": { "Psr\\Http\\Message\\": "src/" } }, "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } } } * [user-info@]host[:port] * * * If the port component is not set or is the standard port for the current * scheme, it SHOULD NOT be included. * * @see https://tools.ietf.org/html/rfc3986#section-3.2 * @return string The URI authority, in "[user-info@]host[:port]" format. */ public function getAuthority(); /** * Retrieve the user information component of the URI. * * If no user information is present, this method MUST return an empty * string. * * If a user is present in the URI, this will return that value; * additionally, if the password is also present, it will be appended to the * user value, with a colon (":") separating the values. * * The trailing "@" character is not part of the user information and MUST * NOT be added. * * @return string The URI user information, in "username[:password]" format. */ public function getUserInfo(); /** * Retrieve the host component of the URI. * * If no host is present, this method MUST return an empty string. * * The value returned MUST be normalized to lowercase, per RFC 3986 * Section 3.2.2. * * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 * @return string The URI host. */ public function getHost(); /** * Retrieve the port component of the URI. * * If a port is present, and it is non-standard for the current scheme, * this method MUST return it as an integer. If the port is the standard port * used with the current scheme, this method SHOULD return null. * * If no port is present, and no scheme is present, this method MUST return * a null value. * * If no port is present, but a scheme is present, this method MAY return * the standard port for that scheme, but SHOULD return null. * * @return null|int The URI port. */ public function getPort(); /** * Retrieve the path component of the URI. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * Normally, the empty path "" and absolute path "/" are considered equal as * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically * do this normalization because in contexts with a trimmed base path, e.g. * the front controller, this difference becomes significant. It's the task * of the user to handle both "" and "/". * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.3. * * As an example, if the value should include a slash ("/") not intended as * delimiter between path segments, that value MUST be passed in encoded * form (e.g., "%2F") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.3 * @return string The URI path. */ public function getPath(); /** * Retrieve the query string of the URI. * * If no query string is present, this method MUST return an empty string. * * The leading "?" character is not part of the query and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.4. * * As an example, if a value in a key/value pair of the query string should * include an ampersand ("&") not intended as a delimiter between values, * that value MUST be passed in encoded form (e.g., "%26") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.4 * @return string The URI query string. */ public function getQuery(); /** * Retrieve the fragment component of the URI. * * If no fragment is present, this method MUST return an empty string. * * The leading "#" character is not part of the fragment and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.5. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.5 * @return string The URI fragment. */ public function getFragment(); /** * Return an instance with the specified scheme. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified scheme. * * Implementations MUST support the schemes "http" and "https" case * insensitively, and MAY accommodate other schemes if required. * * An empty scheme is equivalent to removing the scheme. * * @param string $scheme The scheme to use with the new instance. * @return static A new instance with the specified scheme. * @throws \InvalidArgumentException for invalid or unsupported schemes. */ public function withScheme($scheme); /** * Return an instance with the specified user information. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified user information. * * Password is optional, but the user information MUST include the * user; an empty string for the user is equivalent to removing user * information. * * @param string $user The user name to use for authority. * @param null|string $password The password associated with $user. * @return static A new instance with the specified user information. */ public function withUserInfo($user, $password = null); /** * Return an instance with the specified host. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified host. * * An empty host value is equivalent to removing the host. * * @param string $host The hostname to use with the new instance. * @return static A new instance with the specified host. * @throws \InvalidArgumentException for invalid hostnames. */ public function withHost($host); /** * Return an instance with the specified port. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified port. * * Implementations MUST raise an exception for ports outside the * established TCP and UDP port ranges. * * A null value provided for the port is equivalent to removing the port * information. * * @param null|int $port The port to use with the new instance; a null value * removes the port information. * @return static A new instance with the specified port. * @throws \InvalidArgumentException for invalid ports. */ public function withPort($port); /** * Return an instance with the specified path. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified path. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * If the path is intended to be domain-relative rather than path relative then * it must begin with a slash ("/"). Paths not starting with a slash ("/") * are assumed to be relative to some base path known to the application or * consumer. * * Users can provide both encoded and decoded path characters. * Implementations ensure the correct encoding as outlined in getPath(). * * @param string $path The path to use with the new instance. * @return static A new instance with the specified path. * @throws \InvalidArgumentException for invalid paths. */ public function withPath($path); /** * Return an instance with the specified query string. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified query string. * * Users can provide both encoded and decoded query characters. * Implementations ensure the correct encoding as outlined in getQuery(). * * An empty query string value is equivalent to removing the query string. * * @param string $query The query string to use with the new instance. * @return static A new instance with the specified query string. * @throws \InvalidArgumentException for invalid query strings. */ public function withQuery($query); /** * Return an instance with the specified URI fragment. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified URI fragment. * * Users can provide both encoded and decoded fragment characters. * Implementations ensure the correct encoding as outlined in getFragment(). * * An empty fragment value is equivalent to removing the fragment. * * @param string $fragment The fragment to use with the new instance. * @return static A new instance with the specified fragment. */ public function withFragment($fragment); /** * Return the string representation as a URI reference. * * Depending on which components of the URI are present, the resulting * string is either a full URI or relative reference according to RFC 3986, * Section 4.1. The method concatenates the various components of the URI, * using the appropriate delimiters: * * - If a scheme is present, it MUST be suffixed by ":". * - If an authority is present, it MUST be prefixed by "//". * - The path can be concatenated without delimiters. But there are two * cases where the path has to be adjusted to make the URI reference * valid as PHP does not allow to throw an exception in __toString(): * - If the path is rootless and an authority is present, the path MUST * be prefixed by "/". * - If the path is starting with more than one "/" and no authority is * present, the starting slashes MUST be reduced to one. * - If a query is present, it MUST be prefixed by "?". * - If a fragment is present, it MUST be prefixed by "#". * * @see http://tools.ietf.org/html/rfc3986#section-4.1 * @return string */ public function __toString(); } getQuery()` * or from the `QUERY_STRING` server param. * * @return array */ public function getQueryParams(); /** * Return an instance with the specified query string arguments. * * These values SHOULD remain immutable over the course of the incoming * request. They MAY be injected during instantiation, such as from PHP's * $_GET superglobal, or MAY be derived from some other value such as the * URI. In cases where the arguments are parsed from the URI, the data * MUST be compatible with what PHP's parse_str() would return for * purposes of how duplicate query parameters are handled, and how nested * sets are handled. * * Setting query string arguments MUST NOT change the URI stored by the * request, nor the values in the server params. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated query string arguments. * * @param array $query Array of query string arguments, typically from * $_GET. * @return static */ public function withQueryParams(array $query); /** * Retrieve normalized file upload data. * * This method returns upload metadata in a normalized tree, with each leaf * an instance of Psr\Http\Message\UploadedFileInterface. * * These values MAY be prepared from $_FILES or the message body during * instantiation, or MAY be injected via withUploadedFiles(). * * @return array An array tree of UploadedFileInterface instances; an empty * array MUST be returned if no data is present. */ public function getUploadedFiles(); /** * Create a new instance with the specified uploaded files. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated body parameters. * * @param array $uploadedFiles An array tree of UploadedFileInterface instances. * @return static * @throws \InvalidArgumentException if an invalid structure is provided. */ public function withUploadedFiles(array $uploadedFiles); /** * Retrieve any parameters provided in the request body. * * If the request Content-Type is either application/x-www-form-urlencoded * or multipart/form-data, and the request method is POST, this method MUST * return the contents of $_POST. * * Otherwise, this method may return any results of deserializing * the request body content; as parsing returns structured content, the * potential types MUST be arrays or objects only. A null value indicates * the absence of body content. * * @return null|array|object The deserialized body parameters, if any. * These will typically be an array or object. */ public function getParsedBody(); /** * Return an instance with the specified body parameters. * * These MAY be injected during instantiation. * * If the request Content-Type is either application/x-www-form-urlencoded * or multipart/form-data, and the request method is POST, use this method * ONLY to inject the contents of $_POST. * * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of * deserializing the request body content. Deserialization/parsing returns * structured data, and, as such, this method ONLY accepts arrays or objects, * or a null value if nothing was available to parse. * * As an example, if content negotiation determines that the request data * is a JSON payload, this method could be used to create a request * instance with the deserialized parameters. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated body parameters. * * @param null|array|object $data The deserialized body data. This will * typically be in an array or object. * @return static * @throws \InvalidArgumentException if an unsupported argument type is * provided. */ public function withParsedBody($data); /** * Retrieve attributes derived from the request. * * The request "attributes" may be used to allow injection of any * parameters derived from the request: e.g., the results of path * match operations; the results of decrypting cookies; the results of * deserializing non-form-encoded message bodies; etc. Attributes * will be application and request specific, and CAN be mutable. * * @return array Attributes derived from the request. */ public function getAttributes(); /** * Retrieve a single derived request attribute. * * Retrieves a single derived request attribute as described in * getAttributes(). If the attribute has not been previously set, returns * the default value as provided. * * This method obviates the need for a hasAttribute() method, as it allows * specifying a default value to return if the attribute is not found. * * @see getAttributes() * @param string $name The attribute name. * @param mixed $default Default value to return if the attribute does not exist. * @return mixed */ public function getAttribute($name, $default = null); /** * Return an instance with the specified derived request attribute. * * This method allows setting a single derived request attribute as * described in getAttributes(). * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * updated attribute. * * @see getAttributes() * @param string $name The attribute name. * @param mixed $value The value of the attribute. * @return static */ public function withAttribute($name, $value); /** * Return an instance that removes the specified derived request attribute. * * This method allows removing a single derived request attribute as * described in getAttributes(). * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that removes * the attribute. * * @see getAttributes() * @param string $name The attribute name. * @return static */ public function withoutAttribute($name); } getHeaders() as $name => $values) { * echo $name . ": " . implode(", ", $values); * } * * // Emit headers iteratively: * foreach ($message->getHeaders() as $name => $values) { * foreach ($values as $value) { * header(sprintf('%s: %s', $name, $value), false); * } * } * * While header names are not case-sensitive, getHeaders() will preserve the * exact case in which headers were originally specified. * * @return string[][] Returns an associative array of the message's headers. Each * key MUST be a header name, and each value MUST be an array of strings * for that header. */ public function getHeaders(); /** * Checks if a header exists by the given case-insensitive name. * * @param string $name Case-insensitive header field name. * @return bool Returns true if any header names match the given header * name using a case-insensitive string comparison. Returns false if * no matching header name is found in the message. */ public function hasHeader($name); /** * Retrieves a message header value by the given case-insensitive name. * * This method returns an array of all the header values of the given * case-insensitive header name. * * If the header does not appear in the message, this method MUST return an * empty array. * * @param string $name Case-insensitive header field name. * @return string[] An array of string values as provided for the given * header. If the header does not appear in the message, this method MUST * return an empty array. */ public function getHeader($name); /** * Retrieves a comma-separated string of the values for a single header. * * This method returns all of the header values of the given * case-insensitive header name as a string concatenated together using * a comma. * * NOTE: Not all header values may be appropriately represented using * comma concatenation. For such headers, use getHeader() instead * and supply your own delimiter when concatenating. * * If the header does not appear in the message, this method MUST return * an empty string. * * @param string $name Case-insensitive header field name. * @return string A string of values as provided for the given header * concatenated together using a comma. If the header does not appear in * the message, this method MUST return an empty string. */ public function getHeaderLine($name); /** * Return an instance with the provided value replacing the specified header. * * While header names are case-insensitive, the casing of the header will * be preserved by this function, and returned from getHeaders(). * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * new and/or updated header and value. * * @param string $name Case-insensitive header field name. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withHeader($name, $value); /** * Return an instance with the specified header appended with the given value. * * Existing values for the specified header will be maintained. The new * value(s) will be appended to the existing list. If the header did not * exist previously, it will be added. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that has the * new header and/or value. * * @param string $name Case-insensitive header field name to add. * @param string|string[] $value Header value(s). * @return static * @throws \InvalidArgumentException for invalid header names or values. */ public function withAddedHeader($name, $value); /** * Return an instance without the specified header. * * Header resolution MUST be done without case-sensitivity. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return an instance that removes * the named header. * * @param string $name Case-insensitive header field name to remove. * @return static */ public function withoutHeader($name); /** * Gets the body of the message. * * @return StreamInterface Returns the body as a stream. */ public function getBody(); /** * Return an instance with the specified message body. * * The body MUST be a StreamInterface object. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return a new instance that has the * new body stream. * * @param StreamInterface $body Body. * @return static * @throws \InvalidArgumentException When the body is not valid. */ public function withBody(StreamInterface $body); } =7.0", "amphp/cache": "^1.2", "amphp/parser": "^1", "danog/libdns-json": "^0.1", "daverandom/libdns": "^2.0.1", "amphp/amp": "^2", "amphp/artax": "dev-master", "amphp/dns": "dev-master as v0.9.x-dev", "ext-filter": "*", "ext-json": "*" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "amphp/php-cs-fixer-config": "dev-master" }, "autoload": { "psr-4": { "Amp\\DoH\\": "lib" } }, "autoload-dev": { "psr-4": { "Amp\\DoH\\Test\\": "test" } }, "scripts": { "check": [ "@cs", "@test" ], "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run", "cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff", "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text" } } */ abstract public static function connect(Client $artax, Nameserver $nameserver): self; /** * @param Message $message * * @return Promise */ abstract protected function resolve(Message $message): Promise; protected function __construct() { $this->messageFactory = new MessageFactory; $this->onResolve = function (\Throwable $exception = null, Message $message = null) { if ($exception) { $this->error($exception); return; } \assert($message instanceof Message); $id = $message->getId(); // Ignore duplicate and invalid responses. if (isset($this->pending[$id]) && $this->matchesQuestion($message, $this->pending[$id]->question)) { /** @var Deferred $deferred */ $deferred = $this->pending[$id]->deferred; unset($this->pending[$id]); $deferred->resolve($message); } }; } /** * @param \LibDNS\Records\Question $question * @param int $timeout * * @return \Amp\Promise<\LibDNS\Messages\Message> */ final public function ask(Question $question, int $timeout): Promise { return call(function () use ($question, $timeout) { if (\count($this->pending) > self::MAX_CONCURRENT_REQUESTS) { $deferred = new Deferred; $this->queue[] = $deferred; yield $deferred->promise(); } do { $id = \random_int(0, 0xffff); } while (isset($this->pending[$id])); $deferred = new Deferred; $pending = new class { use Amp\Struct; public $deferred; public $question; }; $pending->deferred = $deferred; $pending->question = $question; $this->pending[$id] = $pending; $message = $this->createMessage($question, $id); try { $response = $this->resolve($message); } catch (StreamException $exception) { $exception = new DnsException("Sending the request failed", 0, $exception); $this->error($exception); throw $exception; } $response->onResolve($this->onResolve); try { // Work around an OPCache issue that returns an empty array with "return ...", // so assign to a variable first and return after the try block. // // See https://github.com/amphp/dns/issues/58. // See https://bugs.php.net/bug.php?id=74840. $result = yield Promise\timeout($deferred->promise(), $timeout); } catch (Amp\TimeoutException $exception) { unset($this->pending[$id]); throw new TimeoutException("Didn't receive a response within {$timeout} milliseconds."); } finally { if ($this->queue) { $deferred = \array_shift($this->queue); $deferred->resolve(); } } return $result; }); } private function error(\Throwable $exception) { if (empty($this->pending)) { return; } if (!$exception instanceof DnsException && !$exception instanceof DoHException) { $message = "Unexpected error during resolution: ".$exception->getMessage(); $exception = new DnsException($message, 0, $exception); } $pending = $this->pending; $this->pending = []; foreach ($pending as $pendingQuestion) { /** @var Deferred $deferred */ $deferred = $pendingQuestion->deferred; $deferred->fail($exception); } } final protected function createMessage(Question $question, int $id): Message { $request = $this->messageFactory->create(MessageTypes::QUERY); $request->getQuestionRecords()->add($question); $request->isRecursionDesired(true); $request->setID($id); return $request; } private function matchesQuestion(Message $message, Question $question): bool { if ($message->getType() !== MessageTypes::RESPONSE) { return false; } $questionRecords = $message->getQuestionRecords(); // We only ever ask one question at a time if (\count($questionRecords) !== 1) { return false; } $questionRecord = $questionRecords->getIterator()->current(); if ($questionRecord->getClass() !== $question->getClass()) { return false; } if ($questionRecord->getType() !== $question->getType()) { return false; } if ($questionRecord->getName()->getValue() !== $question->getName()->getValue()) { return false; } return true; } } httpClient = $artax; $this->nameserver = $nameserver; if ($nameserver->getType() !== Nameserver::GOOGLE_JSON) { $this->encoder = (new EncoderFactory)->create(); $this->decoder = (new DecoderFactory)->create(); } else { $this->encoder = (new QueryEncoderFactory)->create(); $this->decoder = (new JsonDecoderFactory)->create(); } parent::__construct(); } protected function resolve(Message $message): Promise { $id = $message->getID(); switch ($this->nameserver->getType()) { case Nameserver::RFC8484_GET: $data = $this->encoder->encode($message); $request = (new Request($this->nameserver->getUri().'?'.\http_build_query(['dns' => \base64_encode($data), 'ct' => 'application/dns-message']), "GET")) ->withHeader('accept', 'application/dns-message') ->withHeaders($this->nameserver->getHeaders()); break; case Nameserver::RFC8484_POST: $data = $this->encoder->encode($message); $request = (new Request($this->nameserver->getUri(), "POST")) ->withBody($data) ->withHeader('content-type', 'application/dns-message') ->withHeader('accept', 'application/dns-message') ->withHeaders($this->nameserver->getHeaders()); break; case Nameserver::GOOGLE_JSON: $data = $this->encoder->encode($message); $request = (new Request($this->nameserver->getUri().'?'.$data, "GET")) ->withHeader('accept', 'application/dns-json') ->withHeaders($this->nameserver->getHeaders()); break; } $response = $this->httpClient->request($request); return call(function () use ($response, $id) { $response = yield $response; if ($response->getStatus() !== 200) { throw new DoHException("HTTP result !== 200: ".$response->getStatus()." ".$response->getReason(), $response->getStatus()); } $response = yield $response->getBody(); switch ($this->nameserver->getType()) { case Nameserver::RFC8484_GET: case Nameserver::RFC8484_POST: return $this->decoder->decode($response); case Nameserver::GOOGLE_JSON: return $this->decoder->decode($response, $id); } }); } } getSubResolver(); if ($resolver instanceof Rfc8484StubResolver) { throw new ConfigException("Can't use Rfc8484StubResolver as subresolver for Rfc8484StubResolver"); } $this->cache = $config->getCache(); $this->configLoader = $config->getConfigLoader(); $this->subResolver = $resolver; $this->dohConfig = $config; $this->questionFactory = new QuestionFactory; } /** @inheritdoc */ public function resolve(string $name, int $typeRestriction = null): Promise { if ($typeRestriction !== null && $typeRestriction !== Record::A && $typeRestriction !== Record::AAAA) { throw new \Error("Invalid value for parameter 2: null|Record::A|Record::AAAA expected"); } return call(function () use ($name, $typeRestriction) { if (!$this->config) { try { yield $this->reloadConfig(); } catch (ConfigException $e) { $this->config = new Config(['0.0.0.0'], []); } } switch ($typeRestriction) { case Record::A: if (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return [new Record($name, Record::A, null)]; } elseif (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { throw new DnsException("Got an IPv6 address, but type is restricted to IPv4"); } break; case Record::AAAA: if (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return [new Record($name, Record::AAAA, null)]; } elseif (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { throw new DnsException("Got an IPv4 address, but type is restricted to IPv6"); } break; default: if (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return [new Record($name, Record::A, null)]; } elseif (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return [new Record($name, Record::AAAA, null)]; } break; } $name = normalizeName($name); if ($records = $this->queryHosts($name, $typeRestriction)) { return $records; } // Follow RFC 6761 and never send queries for localhost to the caching DNS server // Usually, these queries are already resolved via queryHosts() if ($name === 'localhost') { return $typeRestriction === Record::AAAA ? [new Record('::1', Record::AAAA, null)] : [new Record('127.0.0.1', Record::A, null)]; } if ($this->dohConfig->isNameserver($name)) { // Work around an OPCache issue that returns an empty array with "return ...", // so assign to a variable first and return after the try block. // // See https://github.com/amphp/dns/issues/58. // See https://bugs.php.net/bug.php?id=74840. $records = yield $this->subResolver->resolve($name, $typeRestriction); return $records; } for ($redirects = 0; $redirects < 5; $redirects++) { try { if ($typeRestriction) { $records = yield $this->query($name, $typeRestriction); } else { try { list(, $records) = yield Promise\some([ $this->query($name, Record::A), $this->query($name, Record::AAAA), ]); $records = \array_merge(...$records); break; // Break redirect loop, otherwise we query the same records 5 times } catch (MultiReasonException $e) { $errors = []; foreach ($e->getReasons() as $reason) { if ($reason instanceof NoRecordException) { throw $reason; } $errors[] = $reason->getMessage(); } throw new DnsException("All query attempts failed for {$name}: ".\implode(", ", $errors), 0, $e); } } } catch (NoRecordException $e) { try { /** @var Record[] $cnameRecords */ $cnameRecords = yield $this->query($name, Record::CNAME); $name = $cnameRecords[0]->getValue(); continue; } catch (NoRecordException $e) { /** @var Record[] $dnameRecords */ $dnameRecords = yield $this->query($name, Record::DNAME); $name = $dnameRecords[0]->getValue(); continue; } } } return $records; }); } /** * Reloads the configuration in the background. * * Once it's finished, the configuration will be used for new requests. * * @return Promise */ public function reloadConfig(): Promise { if ($this->pendingConfig) { return $this->pendingConfig; } $promise = call(function () { yield $this->subResolver->reloadConfig(); $this->config = yield $this->configLoader->loadConfig(); }); $this->pendingConfig = $promise; $promise->onResolve(function () { $this->pendingConfig = null; }); return $promise; } private function queryHosts(string $name, int $typeRestriction = null): array { $hosts = $this->config->getKnownHosts(); $records = []; $returnIPv4 = $typeRestriction === null || $typeRestriction === Record::A; $returnIPv6 = $typeRestriction === null || $typeRestriction === Record::AAAA; if ($returnIPv4 && isset($hosts[Record::A][$name])) { $records[] = new Record($hosts[Record::A][$name], Record::A, null); } if ($returnIPv6 && isset($hosts[Record::AAAA][$name])) { $records[] = new Record($hosts[Record::AAAA][$name], Record::AAAA, null); } return $records; } /** @inheritdoc */ public function query(string $name, int $type): Promise { $pendingQueryKey = $type." ".$name; if (isset($this->pendingQueries[$pendingQueryKey])) { return $this->pendingQueries[$pendingQueryKey]; } $promise = call(function () use ($name, $type) { if (!$this->config) { try { yield $this->reloadConfig(); } catch (ConfigException $e) { $this->config = new Config(['0.0.0.0'], []); } } $name = $this->normalizeName($name, $type); $question = $this->createQuestion($name, $type); if (null !== $cachedValue = yield $this->cache->get($this->getCacheKey($name, $type))) { return $this->decodeCachedResult($name, $type, $cachedValue); } /** @var Nameserver[] $nameservers */ $nameservers = $this->dohConfig->getNameservers(); $attempts = $this->config->getAttempts() * \count($nameservers); $attempt = 0; /** @var Socket $socket */ $nameserver = $nameservers[0]; $socket = $this->getSocket($nameserver); $attemptDescription = []; while ($attempt < $attempts) { try { $attemptDescription[] = $nameserver; /** @var Message $response */ try { $response = yield $socket->ask($question, $this->config->getTimeout()); } catch (DoHException $e) { // Defer call, because it might interfere with the unreference() call in Internal\Socket otherwise $i = ++$attempt % \count($nameservers); $nameserver = $nameservers[$i]; $socket = $this->getSocket($nameserver); continue; } catch (NoRecordException $e) { // Defer call, because it might interfere with the unreference() call in Internal\Socket otherwise $i = ++$attempt % \count($nameservers); $nameserver = $nameservers[$i]; $socket = $this->getSocket($nameserver); continue; } $this->assertAcceptableResponse($response); if ($response->isTruncated()) { throw new DnsException("Server returned a truncated response for '{$name}' (".Record::getName($type).")"); } $answers = $response->getAnswerRecords(); $result = []; $ttls = []; /** @var \LibDNS\Records\Resource $record */ foreach ($answers as $record) { $recordType = $record->getType(); $result[$recordType][] = (string) $record->getData(); // Cache for max one day $ttls[$recordType] = \min($ttls[$recordType] ?? 86400, $record->getTTL()); } foreach ($result as $recordType => $records) { // We don't care here whether storing in the cache fails $this->cache->set($this->getCacheKey($name, $recordType), \json_encode($records), $ttls[$recordType]); } if (!isset($result[$type])) { // "it MUST NOT cache it for longer than five (5) minutes" per RFC 2308 section 7.1 $this->cache->set($this->getCacheKey($name, $type), \json_encode([]), 300); throw new NoRecordException("No records returned for '{$name}' (".Record::getName($type).")"); } return \array_map(function ($data) use ($type, $ttls) { return new Record($data, $type, $ttls[$type]); }, $result[$type]); } catch (TimeoutException $e) { // Defer call, because it might interfere with the unreference() call in Internal\Socket otherwise $i = ++$attempt % \count($nameservers); $nameserver = $nameservers[$i]; $socket = $this->getSocket($nameserver); continue; } } throw new TimeoutException(\sprintf( "No response for '%s' (%s) from any nameserver after %d attempts, tried %s", $name, Record::getName($type), $attempts, \implode(", ", $attemptDescription) )); }); $this->pendingQueries[$type." ".$name] = $promise; $promise->onResolve(function () use ($name, $type) { unset($this->pendingQueries[$type." ".$name]); }); return $promise; } private function normalizeName(string $name, int $type) { if ($type === Record::PTR) { if (($packedIp = @\inet_pton($name)) !== false) { if (isset($packedIp[4])) { // IPv6 $name = \wordwrap(\strrev(\bin2hex($packedIp)), 1, ".", true).".ip6.arpa"; } else { // IPv4 $name = \inet_ntop(\strrev($packedIp)).".in-addr.arpa"; } } } elseif (\in_array($type, [Record::A, Record::AAAA])) { $name = normalizeName($name); } return $name; } /** * @param string $name * @param int $type * * @return \LibDNS\Records\Question */ private function createQuestion(string $name, int $type): Question { if (0 > $type || 0xffff < $type) { $message = \sprintf('%d does not correspond to a valid record type (must be between 0 and 65535).', $type); throw new \Error($message); } $question = $this->questionFactory->create($type); $question->setName($name); return $question; } private function getCacheKey(string $name, int $type): string { return self::CACHE_PREFIX.$name."#".$type; } private function decodeCachedResult(string $name, int $type, string $encoded) { $decoded = \json_decode($encoded, true); if (!$decoded) { throw new NoRecordException("No records returned for {$name} (cached result)"); } $result = []; foreach ($decoded as $data) { $result[] = new Record($data, $type); } return $result; } private function getSocket(Nameserver $nameserver) { $uri = $nameserver->getUri(); if (isset($this->sockets[$uri])) { return $this->sockets[$uri]; } $this->sockets[$uri] = HttpsSocket::connect($this->dohConfig->getArtax(), $nameserver); return $this->sockets[$uri]; } private function assertAcceptableResponse(Message $response) { if ($response->getResponseCode() !== 0) { throw new DnsException(\sprintf("Server returned error code: %d", $response->getResponseCode())); } } } uri = $uri; $this->type = $type; $this->headers = $headers; $this->host = \parse_url($uri, PHP_URL_HOST); } public function getUri(): string { return $this->uri; } public function getHost(): string { return $this->host; } public function getHeaders(): array { return $this->headers; } public function getType(): int { return $this->type; } public function __toString(): string { return $this->uri; /* switch ($this->type) { case self::RFC8484_GET: return "{$this->uri} RFC 8484 GET"; case self::RFC8484_POST: return "{$this->uri} RFC 8484 POST"; case self::GOOGLE_JSON: return "{$this->uri} google JSON"; }*/ } } validateNameserver($nameserver); } $this->nameservers = $nameservers; $this->artax = $artax ?? new DefaultClient(); $this->cache = $cache ?? new ArrayCache(5000/* default gc interval */, 256/* size */); $this->configLoader = $configLoader ?? (\stripos(PHP_OS, "win") === 0 ? new WindowsConfigLoader : new UnixConfigLoader); $this->subResolver = $resolver ?? new Rfc1035StubResolver(null, $this->configLoader); } private function validateNameserver($nameserver) { if (!($nameserver instanceof Nameserver)) { throw new ConfigException("Invalid nameserver: {$nameserver}"); } } public function getNameservers(): array { return $this->nameservers; } public function isNameserver($string): bool { foreach ($this->nameservers as $nameserver) { if ($nameserver->getHost() === $string) { return true; } } return false; } public function getArtax(): Client { return $this->artax; } public function getCache(): Cache { return $this->cache; } public function getConfigLoader(): ConfigLoader { return $this->configLoader; } public function getSubResolver(): Resolver { return $this->subResolver; } } { "name": "danog/libdns-json", "homepage": "https://github.com/danog/libdns-json", "description": "Encoder/decoder for google's JSON DNS message format based on libdns", "keywords": [ "dns", "doh", "dns-over-https", "https", "json", "libdns", "message" ], "license": "MIT", "authors": [{ "name": "Daniil Gentili", "email": "daniil@daniil.it" }, { "name": "Chris Wright", "email": "addr@daverandom.com" } ], "require": { "php": ">=7.0", "daverandom/libdns": "^2.0.1", "ext-json": "*" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "phpunit/phpunit": "^6" }, "autoload": { "psr-4": { "danog\\LibDNSJson\\": "lib" } }, "autoload-dev": { "psr-4": { "danog\\LibDNSJson\\Test\\": "test" } }, "scripts": { "check": [ "@cs", "@test" ], "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run", "cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff", "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text" } }create(); $response = $decoder->decode($message, 0); $response->setType(MessageTypes::QUERY); $encoder = (new QueryEncoderFactory)->create(); $request = $encoder->encode($response); $this->assertInternalType('string', $request, "Got a ".\gettype($request)." instead of a string"); \parse_str($request, $output); $this->assertNotEmpty($output); $this->assertArrayHasKey('cd', $output); $this->assertArrayHasKey('do', $output); $this->assertArrayHasKey('ct', $output); $this->assertArrayHasKey('type', $output); $this->assertArrayHasKey('name', $output); $this->assertEquals($output['cd'], 0); $this->assertEquals($output['do'], 0); $this->assertEquals($output['ct'], 'application/dns-json'); $this->assertEquals($output['type'], $response->getQuestionRecords()->getRecordByIndex(0)->getType()); $this->assertEquals($output['name'], \implode('.', $response->getQuestionRecords()->getRecordByIndex(0)->getName()->getLabels())); } public function provideValidQueryPayloads() { return [ [ '{ "Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [ { "name": "apple.com.", "type": 1 } ], "Answer": [ { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.178.96.59" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.172.224.47" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.142.160.59" } ], "Additional": [ ], "edns_client_subnet": "12.34.56.78/0" }', 2 ], [ '{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": true,"CD": false,"Question":[{"name": "example.com.", "type": 28}],"Answer":[{"name": "example.com.", "type": 28, "TTL": 7092, "data": "2606:2800:220:1:248:1893:25c8:1946"}]}', 3 ], [ '{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "daniil.it.", "type": 1}],"Answer":[{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.146.166"},{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.147.166"}]}', 3 ], [ '{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3 ], ]; } /** * Test query encoding of invalid DNS payloads. * * @param $request * @return void * * @dataProvider provideInvalidQueryPayloads */ public function testEncodesInvalidQueryPayloads($request) { $encoder = (new QueryEncoderFactory)->create(); $this->expectException(\InvalidArgumentException::class); $encoder->encode($request); } public function provideInvalidQueryPayloads() { $decoder = (new JsonDecoderFactory)->create(); return [ [ $decoder->decode( '{ "Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [ { "name": "apple.com.", "type": 1 } ], "Answer": [ { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.178.96.59" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.172.224.47" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.142.160.59" } ], "Additional": [ ], "edns_client_subnet": "12.34.56.78/0" }', 2 ) ], [ $decoder->decode( '{ "Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [ ], "Answer": [ { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.178.96.59" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.172.224.47" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.142.160.59" } ], "Additional": [ ], "edns_client_subnet": "12.34.56.78/0" }', 2 ) ], ]; } } assertInstanceOf(JsonDecoder::class, (new JsonDecoderFactory)->create()); } } create(); $response = $decoder->decode($message, $requestId); $this->assertInstanceOf(Message::class, $response); $this->assertEquals(MessageTypes::RESPONSE, $response->getType()); } public function provideValidJsonPayloads() { return [ [ '{ "Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [ { "name": "apple.com.", "type": 1 } ], "Answer": [ { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.178.96.59" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.172.224.47" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.142.160.59" } ], "Additional": [ ], "edns_client_subnet": "12.34.56.78/0" }', 2, ], [ '{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": true,"CD": false,"Question":[{"name": "example.com.", "type": 28}],"Answer":[{"name": "example.com.", "type": 28, "TTL": 7092, "data": "2606:2800:220:1:248:1893:25c8:1946"}]}', 3, ], [ '{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "daniil.it.", "type": 1}],"Answer":[{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.146.166"},{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.147.166"}]}', 3, ], [ '{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3, ], ]; } /** * Test decoding of invalid JSON DNS payloads. * * @param string $message * @param int $requestId * @return void * * @dataProvider provideInvalidJsonPayloads */ public function testDecodesInvalidJsonPayloads($message, $requestId) { $decoder = (new JsonDecoderFactory)->create(); $this->expectException(\InvalidArgumentException::class); $decoder->decode($message, $requestId); } public function provideInvalidJsonPayloads() { return [ [ '{lmfao "Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [ { "name": "apple.com.", "type": 1 } ], "Answer": [ { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.178.96.59" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.172.224.47" }, { "name": "apple.com.", "type": 1, "TTL": 3599, "data": "17.142.160.59" } ], "Additional": [ ], "edns_client_subnet": "12.34.56.78/0" }', 2, ], [ 'xd{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": true,"CD": false,"Question":[{"name": "example.com.", "type": 28}],"Answer":[{"name": "example.com.", "type": 28, "TTL": 7092, "data": "2606:2800:220:1:248:1893:25c8:1946"}]}', 3, ], [ 'whaaa{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "daniil.it.", "type": 1}],"Answer":[{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.146.166"},{"name": "daniil.it.", "type": 1, "TTL": 300, "data": "104.27.147.166"}]}', 3, ], [ 'xdxdxxxxx{"Status": 0,"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3, ], [ '{"TC": false,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3, ], [ '{"Status": 0,"RD": true, "RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3, ], [ '{"Status": 0,"TC": false,"RA": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3, ], [ '{"Status": 0,"TC": false,"RD": true, "AD": false,"CD": false,"Question":[{"name": "amphp.org.", "type": 15}],"Answer":[{"name": "amphp.org.", "type": 15, "TTL": 86400, "data": "0 mail.negativeion.net."}]}', 3, ], [ 'xd', 0 ], ]; } } assertInstanceOf(QueryEncoder::class, (new QueryEncoderFactory)->create()); } } , Chris Wright */ class JsonDecoder { /** * @var \LibDNS\Packets\PacketFactory */ private $packetFactory; /** * @var \LibDNS\Messages\MessageFactory */ private $messageFactory; /** * @var \LibDNS\Records\QuestionFactory */ private $questionFactory; /** * @var \LibDNS\Records\ResourceBuilder */ private $resourceBuilder; /** * @var \LibDNS\Records\Types\TypeBuilder */ private $typeBuilder; /** * @var \LibDNS\Decoder\DecodingContextFactory */ private $decodingContextFactory; /** * Constructor. * * @param \LibDNS\Packets\PacketFactory $packetFactory * @param \LibDNS\Messages\MessageFactory $messageFactory * @param \LibDNS\Records\QuestionFactory $questionFactory * @param \LibDNS\Records\ResourceBuilder $resourceBuilder * @param \LibDNS\Records\Types\TypeBuilder $typeBuilder * @param \LibDNS\Decoder\DecodingContextFactory $decodingContextFactory * @param bool $allowTrailingData */ public function __construct( PacketFactory $packetFactory, MessageFactory $messageFactory, QuestionFactory $questionFactory, ResourceBuilder $resourceBuilder, TypeBuilder $typeBuilder, DecodingContextFactory $decodingContextFactory ) { $this->packetFactory = $packetFactory; $this->messageFactory = $messageFactory; $this->questionFactory = $questionFactory; $this->resourceBuilder = $resourceBuilder; $this->typeBuilder = $typeBuilder; $this->decodingContextFactory = $decodingContextFactory; } /** * Decode a question record. * * * @return \LibDNS\Records\Question * @throws \UnexpectedValueException When the record is invalid */ private function decodeQuestionRecord(array $record): Question { /** @var \LibDNS\Records\Types\DomainName $domainName */ $domainName = $this->typeBuilder->build(Types::DOMAIN_NAME); $labels = \explode('.', $record['name']); if (!empty($last = \array_pop($labels))) { $labels[] = $last; } $domainName->setLabels($labels); $question = $this->questionFactory->create($record['type']); $question->setName($domainName); //$question->setClass($meta['class']); return $question; } /** * Decode a resource record. * * * @return \LibDNS\Records\Resource * @throws \UnexpectedValueException When the record is invalid * @throws \InvalidArgumentException When a type subtype is unknown */ private function decodeResourceRecord(array $record): Resource { /** @var \LibDNS\Records\Types\DomainName $domainName */ $domainName = $this->typeBuilder->build(Types::DOMAIN_NAME); $labels = \explode('.', $record['name']); if (!empty($last = \array_pop($labels))) { $labels[] = $last; } $domainName->setLabels($labels); $resource = $this->resourceBuilder->build($record['type']); $resource->setName($domainName); //$resource->setClass($meta['class']); $resource->setTTL($record['TTL']); $data = $resource->getData(); $fieldDef = $index = null; foreach ($resource->getData()->getTypeDefinition() as $index => $fieldDef) { $field = $this->typeBuilder->build($fieldDef->getType()); $this->decodeType($field, $record['data']); $data->setField($index, $field); break; // For now parse only one field } return $resource; } /** * Decode a Type field. * * * @param \LibDNS\Records\Types\Type $type The object to populate with the result * @throws \UnexpectedValueException When the packet data is invalid * @throws \InvalidArgumentException When the Type subtype is unknown */ private function decodeType(Type $type, $data) { if ($type instanceof Anything) { $this->decodeAnything($type, $data); } elseif ($type instanceof BitMap) { $this->decodeBitMap($type, $data); } elseif ($type instanceof Char) { $this->decodeChar($type, $data); } elseif ($type instanceof CharacterString) { $this->decodeCharacterString($type, $data); } elseif ($type instanceof DomainName) { $this->decodeDomainName($type, $data); } elseif ($type instanceof IPv4Address) { $this->decodeIPv4Address($type, $data); } elseif ($type instanceof IPv6Address) { $this->decodeIPv6Address($type, $data); } elseif ($type instanceof Long) { $this->decodeLong($type, $data); } elseif ($type instanceof Short) { $this->decodeShort($type, $data); } else { throw new \InvalidArgumentException('Unknown Type '.\get_class($type)); } } /** * Decode an Anything field. * * * @param \LibDNS\Records\Types\Anything $anything The object to populate with the result * @param int $length * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeAnything(Anything $anything, $data) { $anything->setValue(\hex2bin($data)); } /** * Decode a BitMap field. * * * @param \LibDNS\Records\Types\BitMap $bitMap The object to populate with the result * @param int $length * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeBitMap(BitMap $bitMap, $data) { $bitMap->setValue(\hex2bin($data)); } /** * Decode a Char field. * * * @param \LibDNS\Records\Types\Char $char The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeChar(Char $char, $result) { $value = \unpack('C', $result)[1]; $char->setValue($value); } /** * Decode a CharacterString field. * * * @param \LibDNS\Records\Types\CharacterString $characterString The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeCharacterString(CharacterString $characterString, $result) { $characterString->setValue($result); } /** * Decode a DomainName field. * * * @param \LibDNS\Records\Types\DomainName $domainName The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeDomainName(DomainName $domainName, $result) { $labels = \explode('.', $result); if (!empty($last = \array_pop($labels))) { $labels[] = $last; } $domainName->setLabels($labels); } /** * Decode an IPv4Address field. * * * @param \LibDNS\Records\Types\IPv4Address $ipv4Address The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeIPv4Address(IPv4Address $ipv4Address, $result) { $octets = \unpack('C4', \inet_pton($result)); $ipv4Address->setOctets($octets); } /** * Decode an IPv6Address field. * * * @param \LibDNS\Records\Types\IPv6Address $ipv6Address The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeIPv6Address(IPv6Address $ipv6Address, $result) { $shorts = \unpack('n8', \inet_pton($result)); $ipv6Address->setShorts($shorts); } /** * Decode a Long field. * * * @param \LibDNS\Records\Types\Long $long The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeLong(Long $long, $result) { $long->setValue((int) $result); } /** * Decode a Short field. * * * @param \LibDNS\Records\Types\Short $short The object to populate with the result * @return int The number of packet bytes consumed by the operation * @throws \UnexpectedValueException When the packet data is invalid */ private function decodeShort(Short $short, $result) { $short->setValue((int) $result); } /** * Decode a Message from JSON-encoded string. * * @param string $data The data string to decode * @param int $requestId The message ID to set * @return \LibDNS\Messages\Message * @throws \UnexpectedValueException When the packet data is invalid * @throws \InvalidArgumentException When a type subtype is unknown */ public function decode(string $result, int $requestId): Message { $result = \json_decode($result, true); if ($result === false) { $error = \json_last_error_msg(); throw new \InvalidArgumentException("Could not decode JSON DNS payload ($error)"); } if (!isset($result['Status'], $result['TC'], $result['RD'], $result['RA'])) { throw new \InvalidArgumentException('Wrong reply from server, missing required fields'); } $message = $this->messageFactory->create(); $decodingContext = $this->decodingContextFactory->create($this->packetFactory->create()); //$message->isAuthoritative(true); $message->setType(MessageTypes::RESPONSE); $message->setID($requestId); $message->setResponseCode($result['Status']); $message->isTruncated($result['TC']); $message->isRecursionDesired($result['RD']); $message->isRecursionAvailable($result['RA']); $decodingContext->setExpectedQuestionRecords(isset($result['Question']) ? \count($result['Question']) : 0); $decodingContext->setExpectedAnswerRecords(isset($result['Answer']) ? \count($result['Answer']) : 0); $decodingContext->setExpectedAuthorityRecords(0); $decodingContext->setExpectedAdditionalRecords(isset($result['Additional']) ? \count($result['Additional']) : 0); $questionRecords = $message->getQuestionRecords(); $expected = $decodingContext->getExpectedQuestionRecords(); for ($i = 0; $i < $expected; $i++) { $questionRecords->add($this->decodeQuestionRecord($result['Question'][$i])); } $answerRecords = $message->getAnswerRecords(); $expected = $decodingContext->getExpectedAnswerRecords(); for ($i = 0; $i < $expected; $i++) { $answerRecords->add($this->decodeResourceRecord($result['Answer'][$i])); } $authorityRecords = $message->getAuthorityRecords(); $expected = $decodingContext->getExpectedAuthorityRecords(); for ($i = 0; $i < $expected; $i++) { $authorityRecords->add($this->decodeResourceRecord($result['Authority'][$i])); } $additionalRecords = $message->getAdditionalRecords(); $expected = $decodingContext->getExpectedAdditionalRecords(); for ($i = 0; $i < $expected; $i++) { $additionalRecords->add($this->decodeResourceRecord($result['Additional'][$i])); } return $message; } } , Chris Wright * @copyright Copyright (c) Chris Wright , * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace danog\LibDNSJson; use \LibDNS\Messages\MessageFactory; use \LibDNS\Packets\PacketFactory; use \LibDNS\Records\QuestionFactory; use \LibDNS\Records\RDataBuilder; use \LibDNS\Records\RDataFactory; use \LibDNS\Records\RecordCollectionFactory; use \LibDNS\Records\ResourceBuilder; use \LibDNS\Records\ResourceFactory; use \LibDNS\Records\TypeDefinitions\FieldDefinitionFactory; use \LibDNS\Records\TypeDefinitions\TypeDefinitionFactory; use \LibDNS\Records\TypeDefinitions\TypeDefinitionManager; use \LibDNS\Records\Types\TypeBuilder; use \LibDNS\Records\Types\TypeFactory; use LibDNS\Decoder\DecodingContextFactory; /** * Creates JsonDecoder objects. * * @author Daniil Gentili , Chris Wright */ class JsonDecoderFactory { /** * Create a new JsonDecoder object. * * @param \LibDNS\Records\TypeDefinitions\TypeDefinitionManager $typeDefinitionManager * @return JsonDecoder */ public function create(TypeDefinitionManager $typeDefinitionManager = null): JsonDecoder { $typeBuilder = new TypeBuilder(new TypeFactory); return new JsonDecoder( new PacketFactory, new MessageFactory(new RecordCollectionFactory), new QuestionFactory, new ResourceBuilder( new ResourceFactory, new RDataBuilder( new RDataFactory, $typeBuilder ), $typeDefinitionManager ?: new TypeDefinitionManager( new TypeDefinitionFactory, new FieldDefinitionFactory ) ), $typeBuilder, new DecodingContextFactory ); } } , Chris Wright * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace danog\LibDNSJson; /** * Creates QueryEncoder objects. * * @category LibDNS * @package Encoder * @author Daniil Gentili , Chris Wright */ class QueryEncoderFactory { /** * Create a new Encoder object. * * @return \LibDNS\Encoder\Encoder */ public function create(): QueryEncoder { return new QueryEncoder(); } } , Chris Wright * @copyright Copyright (c) Chris Wright * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 2.0.0 */ namespace danog\LibDNSJson; use \LibDNS\Messages\Message; use LibDNS\Messages\MessageTypes; /** * Encodes Message objects to query strings. * * @category LibDNS * @package Encoder * @author Daniil Gentili , Chris Wright */ class QueryEncoder { /** * Encode a Message to URL payload. * * @param \LibDNS\Messages\Message $message The Message to encode * @return string */ public function encode(Message $message): string { if ($message->getType() !== MessageTypes::QUERY) { throw new \InvalidArgumentException('Invalid question: is not a question record'); } $questions = $message->getQuestionRecords(); if ($questions->count() === 0) { throw new \InvalidArgumentException('Invalid question: 0 question records provided'); } $question = $questions->getRecordByIndex(0); return \http_build_query( [ 'cd' => 0, // Do not disable result validation 'do' => 0, // Do not send me DNSSEC data 'type' => $question->getType(), // Record type being requested 'name' => \implode('.', $question->getName()->getLabels()), // Record name being requested 'ct' => 'application/dns-json', // Content-type of request ] ); } } #!/usr/bin/env php . */ if (!isset($argv[3])) { echo 'Usage: '.$argv[0].' inputDir output.phar ref'.PHP_EOL; die(1); } @unlink($argv[2]); $p = new Phar(__DIR__.'/'.$argv[2], 0, $argv[2]); $p->buildFromDirectory(realpath($argv[1]), '/^((?!tests).)*(\.php|\.py|\.tl|\.json|\.dat)$/i'); $p->addFromString('vendor/danog/madelineproto/.git/refs/heads/master', $argv[3]); $p->addFromString('.git/refs/heads/master', $argv[3]); $p->setStub(''); #!/usr/bin/env php . */ require 'vendor/autoload.php'; $param = 1; \danog\MadelineProto\Logger::constructor($param); $logger = \danog\MadelineProto\Logger::$default; set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']); \danog\MadelineProto\Logger::log('Copying readme...', \danog\MadelineProto\Logger::NOTICE); file_put_contents('docs/docs/index.md', '--- title: MadelineProto documentation description: PHP client/server for the telegram MTProto protocol (a better tg-cli) image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- '.str_replace(' ['td' => __DIR__.'/src/danog/MadelineProto/TL_td.tl'], 'title' => 'MadelineProto API documentation (td-lib)', 'description' => 'MadelineProto API documentation (td-lib)', 'output_dir' => __DIR__.'/docs/docs/TD_docs', 'readme' => false, 'td' => true, ],*/ [ 'tl_schema' => ['mtproto' => __DIR__.'/src/danog/MadelineProto/TL_mtproto_v1.json'], 'title' => 'MadelineProto API documentation (mtproto)', 'description' => 'MadelineProto API documentation (mtproto)', 'output_dir' => __DIR__.'/docs/docs/MTProto_docs', 'readme' => false, ], [ 'tl_schema' => ['telegram' => __DIR__.'/src/danog/MadelineProto/TL_telegram_v97.tl', 'calls' => __DIR__.'/src/danog/MadelineProto/TL_calls.tl', 'secret' => __DIR__.'/src/danog/MadelineProto/TL_secret.tl', 'td' => __DIR__.'/src/danog/MadelineProto/TL_td.tl'], 'title' => 'MadelineProto API documentation (layer 97)', 'description' => 'MadelineProto API documentation (layer 97)', 'output_dir' => __DIR__.'/docs/docs/API_docs', 'readme' => false, ], ]; $layer_list = ''; foreach (array_slice(glob(__DIR__.'/src/danog/MadelineProto/TL_telegram_*'), 0, -1) as $file) { $layer = preg_replace(['/.*telegram_/', '/\..+/'], '', $file); $docs[] = [ 'tl_schema' => ['telegram' => $file], 'title' => 'MadelineProto API documentation (layer '.$layer.')', 'description' => 'MadelineProto API documentation (layer '.$layer.')', 'output_dir' => __DIR__.'/docs/old_docs/API_docs_'.$layer, 'readme' => true, ]; $layer_list = '[Layer '.$layer.'](API_docs_'.$layer.'/) '; } file_put_contents('docs/old_docs/README.md', '--- title: Documentations of old mtproto layers description: Documentation of old mtproto layers --- # Documentation of old mtproto layers '.$layer_list); $doc = new \danog\MadelineProto\AnnotationsBuilder($logger, $docs[1]); $doc->mk_annotations(); foreach ($docs as $settings) { $doc = new \danog\MadelineProto\DocsBuilder($logger, $settings); $doc->mk_docs(); } chdir(__DIR__); $orderedfiles = []; $order = [ 'ASYNC', 'CREATING_A_CLIENT', 'LOGIN', 'FEATURES', 'REQUIREMENTS', 'INSTALLATION', 'UPDATES', 'SETTINGS', 'SELF', 'EXCEPTIONS', 'FLOOD_WAIT', 'LOGGING', 'CALLS', 'FILES', 'CHAT_INFO', 'DIALOGS', 'INLINE_BUTTONS', 'SECRET_CHATS', 'LUA', 'PROXY', 'USING_METHODS', 'CONTRIB', 'TEMPLATES', ]; $index = ''; $files = glob('docs/docs/docs/*md'); foreach ($files as $file) { $base = basename($file, '.md'); $key = array_search($base, $order); if ($key !== false) { $orderedfiles[$key] = $file; } } ksort($orderedfiles); foreach ($orderedfiles as $key => $filename) { $lines = explode("\n", file_get_contents($filename)); while (end($lines) === '' || strpos(end($lines), 'Next')) { unset($lines[count($lines) - 1]); } if ($lines[0] === '---') { array_shift($lines); while ($lines[0] !== '---') { array_shift($lines); } array_shift($lines); } preg_match('|^# (.*)|', $lines[0], $matches); $title = $matches[1]; $description = $lines[2]; array_unshift($lines, '---', 'title: '.$title, 'description: '.$description, 'image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png', '---'); if (isset($orderedfiles[$key + 1])) { $nextfile = 'https://docs.madelineproto.xyz/docs/'.basename($orderedfiles[$key + 1], '.md').'.html'; $prevfile = $key === 0 ? 'https://docs.madelineproto.xyz' : 'https://docs.madelineproto.xyz/docs/'.basename($orderedfiles[$key - 1], '.md').'.html'; $lines[count($lines)] = "\nNext section"; } else { $lines[count($lines)] = "\nNext section"; } file_put_contents($filename, implode("\n", $lines)); $file = file_get_contents($filename); preg_match_all('|( *)\* \[(.*)\]\((.*)\)|', $file, $matches); $file = 'https://docs.madelineproto.xyz/docs/'.basename($filename, '.md').'.html'; $index .= "* [$title]($file)\n"; if (basename($filename) !== 'FEATURES.md') { foreach ($matches[1] as $key => $match) { $spaces = " $match"; $name = $matches[2][$key]; $url = $matches[3][$key][0] === '#' ? $file.$matches[3][$key] : $matches[3][$key]; $index .= "$spaces* [$name]($url)\n"; if ($name === 'FULL API Documentation with descriptions') { $spaces .= ' '; preg_match_all('|\* (.*)|', file_get_contents('docs/docs/API_docs/methods/index.md'), $smatches); foreach ($smatches[1] as $key => $match) { $match = str_replace('href="', 'href="https://docs.madelineproto.xyz/API_docs/methods/', $match); $index .= "$spaces* ".$match."\n"; } } } } } $readme = explode('## ', file_get_contents('README.md')); foreach ($readme as &$section) { if (explode("\n", $section)[0] === 'Documentation') { $section = "Documentation\n\n".$index."\n"; } } $readme = implode('## ', $readme); file_put_contents('README.md', $readme); file_put_contents('docs/docs/index.md', '--- title: MadelineProto documentation description: PHP client/server for the telegram MTProto protocol (a better tg-cli) image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- '.$readme); $line) { if (preg_match("/public function (\w*)[(]/", $line, $matches)) { $last_match = stripos($matches[1], 'async') === false ? $matches[1] : null; } if (preg_match('/function [(]/', $line) && stripos($line, 'public function') === false) { $last_match = 0; } if (strpos($line, 'yield') !== false) { if ($last_match) { echo "subbing $last_match for $line at $number in $file".PHP_EOL; $to_sub[] = $last_match; } elseif ($last_match === 0) { echo "============\nNOT SUBBING $last_match for $line at $number in $file\n============".PHP_EOL; $not_subbing[$file] = $file; } } } $input = []; $output = []; foreach ($to_sub as $func) { $input[] = "public function $func("; $output[] = "public function $func".'_async('; } if ($input) { file_put_contents($file, str_replace($input, $output, $filec)); } } var_dump(array_values($not_subbing)); start(); $me = $MadelineProto->get_self(); \danog\MadelineProto\Logger::log($me); if (!$me['bot']) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => "Hi!\nThanks for creating MadelineProto! <3"]); $MadelineProto->channels->joinChannel(['channel' => '@MadelineProto']); try { $MadelineProto->messages->importChatInvite(['hash' => 'https://t.me/joinchat/Bgrajz6K-aJKu0IpGsLpBg']); } catch (\danog\MadelineProto\RPCErrorException $e) { } $MadelineProto->messages->sendMessage(['peer' => 'https://t.me/joinchat/Bgrajz6K-aJKu0IpGsLpBg', 'message' => 'Testing MadelineProto!']); } echo 'OK, done!'.PHP_EOL; #!/usr/bin/env php . */ set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/')); /* * Various ways to load MadelineProto */ if (!file_exists(__DIR__.'/vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } class EventHandler extends \danog\MadelineProto\CombinedEventHandler { public function onAny($update, $path) { if (isset($update['message']['out']) && $update['message']['out']) { return; } $MadelineProto = $this->{$path}; if (isset($update['message']['media'])) { yield $MadelineProto->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]); } $res = json_encode($update, JSON_PRETTY_PRINT); if ($res == '') { $res = var_export($update, true); } yield $MadelineProto->sleep(3); try { yield $MadelineProto->messages->sendMessage(['peer' => $update, 'message' => "$res\n\nDopo 3 secondi, in modo asincrono", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']); //'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]); } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR); //$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } } } $settings = ['logger' => ['logger_level' => 5]]; $CombinedMadelineProto = new \danog\MadelineProto\CombinedAPI('combined_session.madeline', ['bot.madeline' => $settings, 'user.madeline' => $settings]); \danog\MadelineProto\Logger::log('Bot login', \danog\MadelineProto\Logger::WARNING); $CombinedMadelineProto->instances['bot.madeline']->start(); \danog\MadelineProto\Logger::log('Userbot login'); $CombinedMadelineProto->instances['user.madeline']->start(); $CombinedMadelineProto->setEventHandler('\EventHandler'); $CombinedMadelineProto->loop(); $CombinedMadelineProto->async(true); $CombinedMadelineProto->setEventHandler('\EventHandler'); $CombinedMadelineProto->loop(); #!/usr/bin/env php . */ set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/')); /* * Various ways to load MadelineProto */ if (!file_exists(__DIR__.'/vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } class EventHandler extends \danog\MadelineProto\EventHandler { private $sent = [-440592694 => true]; public function onUpdateNewEncryptedMessage($update) { try { if (isset($update['message']['decrypted_message']['media'])) { \danog\MadelineProto\Logger::log($this->download_to_dir($update, '.')); } if (isset($this->sent[$update['message']['chat_id']])) { return; } $secret_media = []; // Photo uploaded as document, secret chat $secret_media['document_photo'] = ['peer' => $update, 'file' => 'tests/faust.jpg', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/faust.jpg'), 'caption' => 'This file was uploaded using MadelineProto', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'faust.jpg', 'size' => filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914]]]]]; // Photo, secret chat $secret_media['photo'] = ['peer' => $update, 'file' => 'tests/faust.jpg', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaPhoto', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'caption' => 'This file was uploaded using MadelineProto', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'size' => filesize('tests/faust.jpg'), 'w' => 1280, 'h' => 914]]]; // GIF, secret chat $secret_media['gif'] = ['peer' => $update, 'file' => 'tests/pony.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/pony.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/pony.mp4'), 'caption' => 'test', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'pony.mp4', 'size' => filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeAnimated']]]]]; // Sticker, secret chat $secret_media['sticker'] = ['peer' => $update, 'file' => 'tests/lel.webp', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/lel.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/lel.webp'), 'caption' => 'test', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'lel.webp', 'size' => filesize('tests/lel.webp'), 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL', 'stickerset' => ['_' => 'inputStickerSetEmpty']]]]]]; // Document, secrey chat $secret_media['document'] = ['peer' => $update, 'file' => 'tests/60', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => 'magic/magic', 'caption' => 'test', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'magic.magic', 'size' => filesize('tests/60'), 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'fairy']]]]]; // Video, secret chat $secret_media['video'] = ['peer' => $update, 'file' => 'tests/swing.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/swing.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/swing.mp4'), 'caption' => 'test', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'swing.mp4', 'size' => filesize('tests/swing.mp4'), 'attributes' => [['_' => 'documentAttributeVideo', 'duration' => 5, 'w' => 1280, 'h' => 720]]]]]; // audio, secret chat $secret_media['audio'] = ['peer' => $update, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'mosconi.mp3', 'size' => filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'duration' => 1, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]]; $secret_media['voice'] = ['peer' => $update, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'key' => $inputEncryptedFile['key'], 'iv' => $inputEncryptedFile['iv'], 'file_name' => 'mosconi.mp3', 'size' => filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'duration' => 1, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]]; foreach ($secret_media as $type => $smessage) { $type = yield $this->messages->sendEncryptedFile($smessage); } $i = 0; while ($i < 10) { echo "SENDING MESSAGE $i TO ".$update['message']['chat_id'].PHP_EOL; // You can also use the sendEncrypted parameter for more options in secret chats //yield $this->messages->sendEncrypted(['peer' => $update, 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => (string) ($i++)]]); yield $this->messages->sendMessage(['peer' => $update, 'message' => (string) ($i++)]); } $this->sent[$update['message']['chat_id']] = true; } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log($e); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e); } } } if (file_exists('.env')) { echo 'Loading .env...'.PHP_EOL; $dotenv = Dotenv\Dotenv::create(getcwd()); $dotenv->load(); } echo 'Loading settings...'.PHP_EOL; $settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: []; $MadelineProto = new \danog\MadelineProto\API('s.madeline', $settings); $MadelineProto->start(); $MadelineProto->setEventHandler('\EventHandler'); $MadelineProto->async(true); $MadelineProto->loop(); #!/usr/bin/env php . */ set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/')); /* * Various ways to load MadelineProto */ if (!file_exists(__DIR__.'/vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; define('MADELINE_BRANCH', ''); if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } class EventHandler extends \danog\MadelineProto\EventHandler { public function onAny($update) { if (isset($update['message']['out']) && $update['message']['out']) { return; } if ($update['_'] === 'updateReadChannelOutbox') { return; } if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') { return; } $res = json_encode($update, JSON_PRETTY_PRINT); if ($res == '') { $res = var_export($update, true); } //yield $this->sleep(3); try { yield $this->messages->sendMessage(['peer' => $update, 'message' => "$res", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']); //'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]); if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') { yield $this->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]); //yield $this->download_to_dir($update, '/tmp') } } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR); } catch (\danog\MadelineProto\Exception $e) { if (stripos($e->getMessage(), 'invalid constructor given') === false) { \danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR); } //$this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } } } $settings = ['logger' => ['logger_level' => 5], 'connection_settings' => ['all' => ['protocol' => 'tcp_abridged']]]; $MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings); $MadelineProto->async(true); $MadelineProto->loop(function () use ($MadelineProto) { yield $MadelineProto->start(); yield $MadelineProto->setEventHandler('\EventHandler'); }); $MadelineProto->loop(); . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Lang { public static $lang = %s; // THIS WILL BE OVERWRITTEN BY $lang["en"] public static $current_lang = %s; }'; function from_camel_case($input) { preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); $ret = $matches[0]; foreach ($ret as &$match) { $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); } return implode(' ', $ret); } $lang_code = readline('Enter the language you whish to localize: '); if (!isset(\danog\MadelineProto\Lang::$lang[$lang_code])) { \danog\MadelineProto\Lang::$lang[$lang_code] = \danog\MadelineProto\Lang::$current_lang; echo 'New language detected!'.PHP_EOL.PHP_EOL; } else { echo 'Completing localization of existing language'.PHP_EOL.PHP_EOL; } $count = count(\danog\MadelineProto\Lang::$lang[$lang_code]); $curcount = 0; ksort(\danog\MadelineProto\Lang::$current_lang); foreach (\danog\MadelineProto\Lang::$current_lang as $key => $value) { if (!isset(\danog\MadelineProto\Lang::$lang[$lang_code][$key])) { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = $value; } if (\danog\MadelineProto\Lang::$lang[$lang_code][$key] === $value && ($lang_code !== 'en' || $value == '' || strpos($value, 'You cannot use this method directly') === 0 || strpos($value, 'Update ') === 0 || ctype_lower($value[0]) )) { $value = \danog\MadelineProto\Lang::$lang[$lang_code][$key]; if (in_array($key, ['v_error', 'v_tgerror'])) { $value = hex2bin($value); } if ($value == '') { $value = $key; } preg_match('/^[^_]+_(.*?)(?:_param_(.*)_type_(.*))?$/', $key, $matches); $method_name = isset($matches[1]) ? $matches[1] : ''; $param_name = isset($matches[2]) ? $matches[2] : ''; $param_type = isset($matches[3]) ? $matches[3] : ''; if ($param_name === 'nonce' && $param_type === 'int128') { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = 'Random number for cryptographic security'; } elseif ($param_name === 'server_nonce' && $param_type === 'int128') { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = 'Random number for cryptographic security, given by server'; } elseif ($param_name === 'random_id' && $param_type === 'long') { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = 'Random number for cryptographic security'; } elseif (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$method_name])) { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = \danog\MadelineProto\MTProto::DISALLOWED_METHODS[$method_name]; } elseif (strpos($value, 'Update ') === 0) { if (!$param_name && strpos($key, 'object_') === 0) { $value = str_replace('Update ', '', $value).' update'; } //} elseif (ctype_lower($value[0])) { } else { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = readline($value.' => '); if (\danog\MadelineProto\Lang::$lang[$lang_code][$key] === '') { if ($param_name) { $l = str_replace('_', ' ', $param_name); } else { $l = explode('.', $method_name); $l = from_camel_case(end($l)); } $l = ucfirst(strtolower($l)); if (preg_match('/ empty$/', $l)) { $l = 'Empty '.strtolower(preg_replace('/ empty$/', '', $l)); } foreach (['id', 'url', 'dc'] as $upper) { $l = str_replace([ucfirst($upper), ' '.$upper], [strtoupper($upper), ' '.strtoupper($upper)], $l); } if (in_array($param_type, ['Bool', 'true', 'false'])) { $l .= '?'; } \danog\MadelineProto\Lang::$lang[$lang_code][$key] = $l; echo 'Using default value '.\danog\MadelineProto\Lang::$lang[$lang_code][$key].PHP_EOL; } } \danog\MadelineProto\Lang::$lang[$lang_code][$key] = ucfirst(\danog\MadelineProto\Lang::$lang[$lang_code][$key]); if (in_array($key, ['v_error', 'v_tgerror'])) { \danog\MadelineProto\Lang::$lang[$lang_code][$key] = bin2hex(\danog\MadelineProto\Lang::$lang[$lang_code][$key]); } file_put_contents('src/danog/MadelineProto/Lang.php', sprintf($template, var_export(\danog\MadelineProto\Lang::$lang, true), var_export(\danog\MadelineProto\Lang::$lang['en'], true))); echo 'OK, '.($curcount * 100 / $count).'% done. edit src/danog/MadelineProto/Lang.php to fix mistakes.'.PHP_EOL; } $curcount++; } file_put_contents('src/danog/MadelineProto/Lang.php', sprintf($template, var_export(\danog\MadelineProto\Lang::$lang, true), var_export(\danog\MadelineProto\Lang::$lang['en'], true))); echo 'OK. edit src/danog/MadelineProto/Lang.php to fix mistakes.'.PHP_EOL; #!/usr/bin/env php . */ if (!file_exists(__DIR__.'/../vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } $settings = []; include_once 'token.php'; try { $MadelineProto = new \danog\MadelineProto\API('b.madeline'); } catch (\danog\MadelineProto\Exception $e) { $MadelineProto = new \danog\MadelineProto\API($settings); $authorization = $MadelineProto->bot_login($pwrtelegram_debug_token); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); } function base64url_decode($data) { return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); } function rle_decode($string) { $base256 = ''; $last = ''; foreach (str_split($string) as $cur) { if ($last === chr(0)) { $base256 .= str_repeat($last, ord($cur)); $last = ''; } else { $base256 .= $last; $last = $cur; } } $string = $base256.$last; return $string; } function foreach_offset_length($string) { /* $a = []; $b = []; foreach ([2, 3, 4] as $r) { $a []= chr(0).chr($r); $b []= str_repeat(chr(0), $r); } $string = str_replace($a, $b, $string);*/ $res = []; $strlen = strlen($string); for ($offset = 0; $offset < strlen($string); $offset++) { // for ($length = $strlen - $offset; $length > 0; $length--) { foreach (['i' => 4, 'q' => 8] as $c => $length) { $s = substr($string, $offset, $length); if (strlen($s) === $length) { $number = \danog\PHP\Struct::unpack('<'.$c, $s)[0]; //$number = ord($s); $res[] = ['number' => $number, 'offset' => $offset, 'length' => $length]; } } } return $res; } $res = ['offset' => 0, 'files' => []]; function getfiles($token, &$params) { foreach (json_decode(file_get_contents('https://api.telegram.org/bot'.$token.'/getupdates?offset='.$params['offset']), true)['result'] as $update) { $params['offset'] = $update['update_id'] + 1; if (isset($update['message']['audio'])) { $params['files'][$update['message']['message_id']] = $update['message']['audio']['file_id']; } if (isset($update['message']['document'])) { $params['files'][$update['message']['message_id']] = $update['message']['document']['file_id']; } if (isset($update['message']['video'])) { $params['files'][$update['message']['message_id']] = $update['message']['video']['file_id']; } if (isset($update['message']['sticker'])) { $params['files'][$update['message']['message_id']] = $update['message']['sticker']['file_id']; } if (isset($update['message']['voice'])) { $params['files'][$update['message']['message_id']] = $update['message']['voice']['file_id']; } if (isset($update['message']['photo'])) { $params['files'][$update['message']['message_id']] = end($update['message']['photo'])['file_id']; } } } function recurse($array, $prefix = '') { $res = []; foreach ($array as $k => $v) { if (is_array($v)) { $res = array_merge(recurse($v, $prefix.$k.'->'), $res); } elseif (is_int($v)) { $res[$prefix.$k] = $v; } } return $res; } $offset = 0; while (true) { $updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id switch ($update['update']['_']) { case 'updateNewMessage': if (isset($update['update']['message']['out']) && $update['update']['message']['out']) { continue; } try { if (isset($update['update']['message']['media'])) { getfiles($pwrtelegram_debug_token, $res); $bot_api_id = $message = $res['files'][$update['update']['message']['id']]; $bot_api_id_b256 = base64url_decode($bot_api_id); $bot_api_id_rledecoded = rle_decode($bot_api_id_b256); $message .= PHP_EOL.PHP_EOL; for ($x = 0; $x < strlen($bot_api_id_rledecoded) - 3; $x++) { $message .= 'Bytes '.$x.'-'.($x + 4).': '.\danog\PHP\Struct::unpack('param (value): start-end (length)'.PHP_EOL.PHP_EOL; $bot_api = foreach_offset_length($bot_api_id_rledecoded); //$mtproto = $MadelineProto->get_download_info($update['update']['message']['media'])['InputFileLocation']; //unset($mtproto['_']); $m = []; $mtproto = recurse($update['update']['message']); /* if (isset($mtproto['version'])) { unset($mtproto['version']); } if (isset($update['update']['message']['media']['photo'])) { $mtproto['id'] = $update['update']['message']['media']['photo']['id']; } $mtproto['sender_id'] = $update['update']['message']['from_id']; if (isset($update['update']['message']['media']['photo'])) { $mtproto['access_hash'] = $update['update']['message']['media']['photo']['access_hash']; } if (isset($update['update']['message']['media']['document'])) { $mtproto['id'] = $update['update']['message']['media']['document']['id']; } if (isset($update['update']['message']['media']['document'])) { $mtproto['access_hash'] = $update['update']['message']['media']['document']['access_hash']; }*/ foreach ($mtproto as $key => $n) { foreach ($bot_api as $bn) { if ($bn['number'] === $n) { $m[$bn['offset'] + $bn['length']] = $key.' ('.$n.'): '.$bn['offset'].'-'.($bn['offset'] + $bn['length']).' ('.$bn['length'].') FOUND'.PHP_EOL; unset($mtproto[$key]); } } } ksort($m); foreach ($m as $key => $bn) { $message .= $bn; } foreach ($mtproto as $key => $n) { $message .= $key.' ('.$n.'): not found'.PHP_EOL; } $message .= PHP_EOL.PHP_EOL.'File number: '.\danog\PHP\Struct::unpack('messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $message, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown']); } } catch (\danog\MadelineProto\RPCErrorException $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\Exception $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } try { if (isset($update['update']['message']['media']) && $update['update']['message']['media'] == 'messageMediaPhoto' && $update['update']['message']['media'] == 'messageMediaDocument') { $time = time(); // $file = $MadelineProto->download_to_dir($update['update']['message']['media'], '/tmp'); // $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => 'Downloaded to '.$file.' in '.(time() - $time).' seconds', 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]); } } catch (\danog\MadelineProto\RPCErrorException $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } } } echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('b.madeline', $MadelineProto).' bytes'.PHP_EOL; } #!/usr/bin/env php . */ if (!file_exists(__DIR__.'/../vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } $settings = []; $MadelineProto = false; try { $MadelineProto = new \danog\MadelineProto\API('MadelineProto_bot.madeline'); } catch (\danog\MadelineProto\Exception $e) { $MadelineProto = new \danog\MadelineProto\API($settings); $authorization = $MadelineProto->bot_login(readline('Enter a bot token: ')); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); } if (file_exists('token.php') && $MadelineProto === false) { include_once 'token.php'; $MadelineProto = new \danog\MadelineProto\API($settings); $authorization = $MadelineProto->bot_login($MadelineProto_token); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); } $offset = 0; $reply_markup = ['inline_keyboard' => [ [ // Row 1 ['text' => 'Row 1 c1'], ['text' => 'Row 1 c2'], ['text' => 'Row 1 c3'], ], [ // Row 2 ['text' => 'Row 2 c1'], ['text' => 'Row 2 c2'], ['text' => 'Row 2 c3'], ], [ // Row 3 ['text' => 'Row 3 c1'], ['text' => 'Row 3 c2'], ['text' => 'Row 3 c3'], ], ], ]; $start = 'This bot can create inline text buttons. To use it, simply type an inline query with the following syntax: @MadelineProto_bot Text to show in message Row 1 c1 | Row 1 c2 | Row 1 c3 Row 2 c1 | Row 2 c2 | Row 2 c3 Row 3 c1 | Row 3 c2 | Row 3 c3 This will create a keyboard exactly like the one used in this message (click the buttons ;D) with the phrase "Text to show in message" instead of this help message. Created by [Daniil Gentili](mention:@danogentili) (@daniilgentili) using the [MadelineProto PHP MTProto client](daniil.it/MadelineProto).'; echo 'Bot started.'.PHP_EOL; while (true) { $updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id switch ($update['update']['_']) { case 'updateNewMessage': if (isset($update['update']['message']['out']) && $update['update']['message']['out']) { continue; } try { if (isset($update['update']['message']['message']) && preg_match('|/start|', $update['update']['message']['message'])) { $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]); } } catch (\danog\MadelineProto\RPCErrorException $e) { //$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } break; case 'updateNewChannelMessage': if (isset($update['update']['message']['out']) && $update['update']['message']['out']) { continue; } try { if (preg_match('|/start|', $update['update']['message']['message'])) { $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]); } } catch (\danog\MadelineProto\RPCErrorException $e) { //$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\Exception $e) { //$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } break; case 'updateBotInlineQuery': try { $sswitch = ['_' => 'inlineBotSwitchPM', 'text' => 'FAQ', 'start_param' => 'lel']; if ($update['update']['query'] === '') { $MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]); } else { $toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true]; $rows = explode("\n", $update['update']['query']); $text = array_shift($rows); if (empty($rows)) { $MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]); } else { array_walk($rows, function (&$value, $key) { $value = explode('|', $value); array_walk($value, function (&$value, $key) { $value = ['text' => trim($value), 'url' => 'https://yayponies.eu']; }); }); $toset['results'] = [['_' => 'inputBotInlineResult', 'id' => (string) random_int(0, pow(2, 31) - 1), 'type' => 'article', 'title' => $text, 'description' => 'Your keyboard', 'send_message' => ['_' => 'inputBotInlineMessageText', 'message' => $text, 'reply_markup' => ['inline_keyboard' => $rows]]]]; $MadelineProto->messages->setInlineBotResults($toset); } } } catch (\danog\MadelineProto\RPCErrorException $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); try { $MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\Exception $e) { } try { $toset['switch_pm'] = $sswitch; $MadelineProto->messages->setInlineBotResults($toset); } catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\Exception $e) { } } catch (\danog\MadelineProto\Exception $e) { try { $MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\Exception $e) { } try { $toset['switch_pm'] = $sswitch; $MadelineProto->messages->setInlineBotResults($toset); } catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\Exception $e) { } } } } \danog\MadelineProto\Serialization::serialize('MadelineProto_bot.madeline', $MadelineProto); } #!/usr/bin/env php . */ if (!file_exists(__DIR__.'/../vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } $settings = []; $MadelineProto = false; $uMadelineProto = false; try { $MadelineProto = new \danog\MadelineProto\API('pipesbot.madeline'); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } try { $uMadelineProto = new \danog\MadelineProto\API('pwr.madeline'); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } if (file_exists('token.php') && $MadelineProto === false) { include_once 'token.php'; $MadelineProto = new \danog\MadelineProto\API($settings); $authorization = $MadelineProto->bot_login($pipes_token); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); } if ($uMadelineProto === false) { echo 'Loading MadelineProto...'.PHP_EOL; $uMadelineProto = new \danog\MadelineProto\API(array_merge($settings, ['updates' => ['handle_updates' => false]])); $sentCode = $uMadelineProto->phone_login(readline()); \danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE); echo 'Enter the code you received: '; $code = fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1); $authorization = $uMadelineProto->complete_phone_login($code); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); if ($authorization['_'] === 'account.noPassword') { throw new \danog\MadelineProto\Exception('2FA is enabled but no password is set!'); } if ($authorization['_'] === 'account.password') { \danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE); $authorization = $uMadelineProto->complete_2fa_login(readline('Please enter your password (hint '.$authorization['hint'].'): ')); } echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL; echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $uMadelineProto).' bytes'.PHP_EOL; } function inputify(&$stuff) { $stuff['_'] = 'input'.ucfirst($stuff['_']); return $stuff; } function translatetext(&$value) { inputify($value); if (isset($value['entities'])) { foreach ($value['entities'] as &$entity) { if ($entity['_'] === 'messageEntityMentionName') { inputify($entity); } } } if (isset($value['geo'])) { $value['geo_point'] = inputify($value['geo']); } } function translate(&$value, $key) { switch ($value['_']) { case 'botInlineResult': $value['_'] = 'inputBotInlineResult'; translatetext($value['send_message']); return $value; case 'botInlineMediaResult': if (isset($value['game'])) { throw new \danog\MadelineProto\RPCErrorException('Games are not supported.'); } if (isset($value['photo'])) { $value['_'] = 'inputBotInlineResultPhoto'; } if (isset($value['document'])) { $value['_'] = 'inputBotInlineResultDocument'; } translatetext($value['send_message']); return $value; } } $offset = 0; $start = "This bot can create a pipeline between inline bots. To use it, simply type an inline query with the following syntax: @pipesbot Hey I'm writing this using the leet filter of @filtersbot w/ @lolcatzbot | @filtersbot:eleet | @lolcatzbot \$ This will make an inline query with text \"Hey I'm writing this using the leet filter of @filtersbot w/ @lolcatzbot\" to @filtersbot, take the result that has the word \"eleet\" (regexes are supported. you can specify just the username to select the first result), in the title, if it's a text message (entities will be ignored, if it's a media message you will be redirected here), then it will make an inline query to @lolcatzbot with the text received out of the first bot fetch all results and return them to you. Note that the query must be terminated by a \$ Created by @danogentili (@daniilgentili) using the daniil.it/MadelineProto PHP MTProto client."; while (true) { $updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id try { switch ($update['update']['_']) { case 'updateNewMessage': if (isset($update['update']['message']['out']) && $update['update']['message']['out']) { continue; } try { if (preg_match('|/start|', $update['update']['message']['message'])) { $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]); } } catch (\danog\MadelineProto\RPCErrorException $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } break; case 'updateNewChannelMessage': if (isset($update['update']['message']['out']) && $update['update']['message']['out']) { continue; } try { if (preg_match('|/start|', $update['update']['message']['message'])) { $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]); } } catch (\danog\MadelineProto\RPCErrorException $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\Exception $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } break; case 'updateBotInlineQuery': try { $sswitch = ['_' => 'inlineBotSwitchPM', 'text' => 'FAQ', 'start_param' => 'lel']; if ($update['update']['query'] === '') { $MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]); } else { $toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true]; if (preg_match('|\$\s*$|', $update['update']['query'])) { $exploded = explode('|', preg_replace('/\$\s*$/', '', $update['update']['query'])); array_walk($exploded, function (&$value, $key) { $value = preg_replace(['/^\s+/', '/\s+$/'], '', $value); }); $query = array_shift($exploded); foreach ($exploded as $current => $botq) { $bot = preg_replace('|:.*|', '', $botq); if ($bot === '' || $uMadelineProto->get_info($bot)['bot_api_id'] === $MadelineProto->API->authorization['user']['id']) { $toset['switch_pm'] = $sswitch; break; } $select = preg_replace('|'.$bot.':|', '', $botq); $results = $uMadelineProto->messages->getInlineBotResults(['bot' => $bot, 'peer' => $update['update']['user_id'], 'query' => $query, 'offset' => $offset]); if (isset($results['switch_pm'])) { $toset['switch_pm'] = $results['switch_pm']; break; } $toset['gallery'] = $results['gallery']; $toset['results'] = []; if (is_numeric($select)) { $toset['results'][0] = $results['results'][$select - 1]; } elseif ($select === '') { $toset['results'] = $results['results']; } else { foreach ($results['results'] as $result) { if (isset($result['send_message']['message']) && preg_match('|'.$select.'|', $result['send_message']['message'])) { $toset['results'][0] = $result; } } } if (!isset($toset['results'][0])) { $toset['results'] = $results['results']; } if (count($exploded) - 1 === $current || !isset($toset['results'][0]['send_message']['message'])) { break; } $query = $toset['results'][0]['send_message']['message']; } } if (empty($toset['results'])) { $toset['switch_pm'] = $sswitch; } else { array_walk($toset['results'], 'translate'); } $MadelineProto->messages->setInlineBotResults($toset); } } catch (\danog\MadelineProto\RPCErrorException $e) { try { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); $MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } try { $toset['switch_pm'] = $sswitch; $MadelineProto->messages->setInlineBotResults($toset); } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } } catch (\danog\MadelineProto\Exception $e) { try { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); $MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } try { $toset['switch_pm'] = $sswitch; $MadelineProto->messages->setInlineBotResults($toset); } catch (\danog\MadelineProto\RPCErrorException $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } catch (\danog\MadelineProto\Exception $e) { \danog\MadelineProto\Logger::log($e->getMessage()); } } } } catch (\danog\MadelineProto\RPCErrorException $e) { } } \danog\MadelineProto\Serialization::serialize('pipesbot.madeline', $MadelineProto); \danog\MadelineProto\Serialization::serialize('pwr.madeline', $uMadelineProto); } { "name": "danog/madelineproto", "description": "PHP implementation of telegram's MTProto protocol.", "type": "project", "license": "AGPL-3.0-only", "homepage": "https://daniil.it/MadelineProto", "keywords": ["telegram", "mtproto", "protocol", "bytes", "messenger", "client", "PHP", "video", "stickers", "audio", "files", "GB"], "conflict": { "krakjoe/pthreads-polyfill": "*" }, "require": { "php": ">=7.1.0", "danog/primemodule": "^1", "danog/magicalserializer": "^1.0", "phpseclib/phpseclib": "dev-master#c62fc0c73373426d3ff8729f10e82e09e1874866 as 2.0.15", "vlucas/phpdotenv": "^3", "erusev/parsedown": "^1.6", "ext-mbstring": "*", "ext-json": "*", "ext-xml": "*", "ext-fileinfo": "*", "amphp/amp": "^2.0", "amphp/websocket": "dev-master as 1", "amphp/websocket-client": "dev-master as 1", "amphp/socket": "^0.10", "amphp/dns": "dev-master#aa1892bdf13b787d759df6f2523e8027a434d927 as v0.9.x-dev", "amphp/artax": "dev-master as 3.0.99", "amphp/file": "^0.3", "amphp/uri": "^0.1.4", "amphp/byte-stream": "^1.6", "danog/dns-over-https": "^0.1" }, "require-dev": { "phpdocumentor/reflection-docblock": "^3.1", "ennexa/amp-update-cache": "dev-master", "phpunit/phpunit": "^8" }, "suggest": { "ext-libtgvoip": "Install the php-libtgvoip extension to make phone calls (https://github.com/danog/php-libtgvoip)" }, "authors": [{ "name": "Daniil Gentili", "email": "daniil@daniil.it" }], "autoload": { "psr-0": { "danog\\MadelineProto\\": "src/" }, "files": [ "src/BigIntegor.php", "src/YieldReturnValue.php" ] }, "repositories": [ { "type": "git", "url": "https://github.com/danog/phpseclib" }, { "type": "git", "url": "https://github.com/danog/dns" } ] } '.$newline; } echo "**********************************************************************************$newline"; echo "**********************************************************************************$newline$newline"; echo "YOU ARE USING AN OLD AND BUGGED VERSION OF PHP, PLEASE UPDATE TO PHP 7.3$newline"; echo "PHP 5/7.0 USERS WILL NOT RECEIVE PHP UPDATES AND BUGFIXES: https://www.php.net/eol.php$newline"; echo "PHP 5/7.0 USERS WILL NOT RECEIVE MADELINEPROTO UPDATES AND BUGFIXES$newline$newline"; echo "SUPPORTED VERSIONS: PHP 7.1, 7.2, 7.3+$newline"; echo "RECOMMENDED VERSION: PHP 7.3$newline$newline"; echo "**********************************************************************************$newline"; echo "**********************************************************************************$newline"; unset($newline); } // MTProxy update $file = debug_backtrace(0, 1)[0]['file']; if (file_exists($file)) { $contents = file_get_contents($file); if (strpos($contents, 'new \danog\MadelineProto\Server') && in_array($contents, [file_get_contents('https://github.com/danog/MadelineProtoPhar/raw/2270bd9a94d168a5e6731ffd7e61821ea244beff/mtproxyd'), file_get_contents('https://github.com/danog/MadelineProtoPhar/raw/7cabb718ec3ccb79e3c8e3d34f5bccbe3f63b0fd/mtproxyd')]) && ($mtproxyd = file_get_contents('https://phar.madelineproto.xyz/mtproxyd?v=new'))) { file_put_contents($file, $mtproxyd); return; } } // MadelineProto update $release_template = 'https://phar.madelineproto.xyz/release%s?v=new'; $phar_template = 'https://phar.madelineproto.xyz/madeline%s.phar?v=new'; // Version definition $release_branch = defined('MADELINE_BRANCH') ? '-'.MADELINE_BRANCH : '-old'; if ($release_branch === '-') { $release_branch = ''; } $release_default_branch = ''; if (PHP_MAJOR_VERSION <= 5) { $release_branch = '5'.$release_branch; $release_default_branch = '5'; } elseif (PHP_MINOR_VERSION >= 3) { $release_branch = ''; } // Checking if defined branch/default branch builds can be downloaded if (!($release = @file_get_contents(sprintf($release_template, $release_branch)))) { if (!($release = @file_get_contents(sprintf($release_template, $release_default_branch)))) { return; } $release_branch = $release_default_branch; } if (!file_exists('madeline.phar') || !file_exists('madeline.phar.version') || file_get_contents('madeline.phar.version') !== $release) { $phar = file_get_contents(sprintf($phar_template, $release_branch)); if ($phar) { file_put_contents('madeline.phar', $phar); file_put_contents('madeline.phar.version', $release); } } } ___install_madeline(); require 'madeline.phar'; . */ require 'vendor/autoload.php'; $param = 1; \danog\MadelineProto\Logger::constructor($param); $logger = \danog\MadelineProto\Logger::$default; set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']); if ($argc !== 3) { die("Usage: {$argv[0]} layernumberold layernumbernew\n"); } /** * Get TL info of layer. * * @param int $layer Layer number * * @return void */ function getTL($layer) { $layer = __DIR__."/src/danog/MadelineProto/TL_telegram_v$layer.tl"; $layer = new class($layer) { use TL; public function __construct($layer) { $this->logger = Logger::$default; $this->construct_TL(['telegram' => $layer]); } }; return ['methods' => $layer->methods, 'constructors' => $layer->constructors]; } function getUrl($constructor, $type) { $changed = str_replace('.', '_', $constructor); return "[$constructor](https://docs.madelineproto.xyz/API_docs/$type/$changed.html)"; } $old = getTL($argv[1]); $new = getTL($argv[2]); $res = ''; foreach (['methods', 'constructors'] as $type) { $finder = $type === 'methods' ? 'find_by_method' : 'find_by_predicate'; $key = $type === 'methods' ? 'method' : 'predicate'; // New constructors $res .= "\n\nNew ".ucfirst($type)."\n"; foreach ($new[$type]->by_id as $constructor) { $name = $constructor[$key]; if (!$old[$type]->$finder($name)) { $name = getUrl($name, $type); $res .= "Added $name\n"; } } // Changed constructors $res .= "\n\nChanged ".ucfirst($type)."\n"; foreach ($new[$type]->by_id as $constructor) { $name = $constructor[$key]; $constructor['id'] = $new[$type]->$finder($name)['id']; if ($old[$type]->$finder($name) && $old[$type]->$finder($name)['id'] !== $constructor['id']) { $new_args = $constructor['params']; $old_args = $old[$type]->$finder($name)['params']; $final_new_args = []; $final_old_args = []; foreach ($new_args as $arg) { $final_new_args[$arg['name']] = $arg['type']; } foreach ($old_args as $arg) { $final_old_args[$arg['name']] = $arg['type']; } $url = getUrl($name, $type); foreach ($final_new_args as $name => $ttype) { if (!isset($final_old_args[$name])) { $res .= "Added $name param to $url\n"; } } foreach ($final_old_args as $name => $ttype) { if (!isset($final_new_args[$name])) { $res .= "Removed $name param from $url\n"; } } } } // Deleted constructors $res .= "\n\nDeleted ".ucfirst($type)."\n"; foreach ($old[$type]->by_id as $constructor) { $name = $constructor[$key]; if (!$new[$type]->$finder($name)) { $res .= "Removed $name\n"; } } } echo $res; #!/usr/bin/env php . */ require '../vendor/autoload.php'; $settings = []; $Lua = false; try { $Lua = \danog\MadelineProto\Serialization::deserialize('bot.madeline'); } catch (\danog\MadelineProto\Exception $e) { } if (!is_object($Lua)) { $MadelineProto = new \danog\MadelineProto\API($settings); while (!in_array(($res = readline('Do you want to login as a user or as a bot (u/b)? ')), ['u', 'b'])) { echo 'Please write either u or b'.PHP_EOL; } switch ($res) { case 'u': $sentCode = $MadelineProto->phone_login(readline('Enter your phone number: ')); \danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE); echo 'Enter the code you received: '; $code = fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1); $authorization = $MadelineProto->complete_phone_login($code); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); if ($authorization['_'] === 'account.noPassword') { throw new \danog\MadelineProto\Exception('2FA is enabled but no password is set!'); } if ($authorization['_'] === 'account.password') { \danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE); $authorization = $MadelineProto->complete_2fa_login(readline('Please enter your password (hint '.$authorization['hint'].'): ')); } if ($authorization['_'] === 'account.needSignup') { \danog\MadelineProto\Logger::log('Registering new user', \danog\MadelineProto\Logger::NOTICE); $authorization = $MadelineProto->complete_signup(readline('Please enter your first name: '), readline('Please enter your last name (can be empty): ')); } \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); $Lua = new \danog\MadelineProto\Lua('madeline.lua', $MadelineProto); break; case 'b': $authorization = $MadelineProto->bot_login(readline('Please enter a bot token: ')); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); $Lua = new \danog\MadelineProto\Lua('madeline.lua', $MadelineProto); break; } } $offset = 0; while (true) { $updates = $Lua->MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id $Lua->madeline_update_callback($update['update']); } echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('bot.madeline', $Lua).' bytes'.PHP_EOL; } #!/usr/bin/env php . */ require '../vendor/autoload.php'; $settings = []; $Lua = false; try { $Lua = \danog\MadelineProto\Serialization::deserialize('td.madeline'); } catch (\danog\MadelineProto\Exception $e) { } if (!is_object($Lua)) { $MadelineProto = new \danog\MadelineProto\API($settings); while (!in_array(($res = readline('Do you want to login as a user or as a bot (u/b)? ')), ['u', 'b'])) { echo 'Please write either u or b'.PHP_EOL; } switch ($res) { case 'u': $sentCode = $MadelineProto->phone_login(readline('Enter your phone number: ')); \danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE); echo 'Enter the code you received: '; $code = fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1); $authorization = $MadelineProto->complete_phone_login($code); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); if ($authorization['_'] === 'account.noPassword') { throw new \danog\MadelineProto\Exception('2FA is enabled but no password is set!'); } if ($authorization['_'] === 'account.password') { \danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE); $authorization = $MadelineProto->complete_2fa_login(readline('Please enter your password (hint '.$authorization['hint'].'): ')); } if ($authorization['_'] === 'account.needSignup') { \danog\MadelineProto\Logger::log('Registering new user', \danog\MadelineProto\Logger::NOTICE); $authorization = $MadelineProto->complete_signup(readline('Please enter your first name: '), readline('Please enter your last name (can be empty): ')); } \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); $Lua = new \danog\MadelineProto\Lua('madeline.lua', $MadelineProto); break; case 'b': $authorization = $MadelineProto->bot_login(readline('Please enter a bot token: ')); \danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE); $Lua = new \danog\MadelineProto\Lua('madeline.lua', $MadelineProto); break; } } $offset = 0; while (true) { $updates = $Lua->MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id $Lua->tdcli_update_callback($update['update']); } echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('td.madeline', $Lua).' bytes'.PHP_EOL; } #!/usr/bin/env php . */ set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/')); /* * Various ways to load MadelineProto */ if (!file_exists(__DIR__.'/vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } class EventHandler extends \danog\MadelineProto\EventHandler { public function onUpdateNewChannelMessage($update) { $this->onUpdateNewMessage($update); } public function onUpdateNewMessage($update) { if (isset($update['message']['out']) && $update['message']['out']) { return; } $res = json_encode($update, JSON_PRETTY_PRINT); if ($res == '') { $res = var_export($update, true); } try { $this->messages->sendMessage(['peer' => $update, 'message' => $res, 'reply_to_msg_id' => $update['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } try { if (isset($update['message']['media']) && ($update['message']['media']['_'] == 'messageMediaPhoto' || $update['message']['media']['_'] == 'messageMediaDocument')) { $time = microtime(true); $file = $this->download_to_dir($update, '/tmp'); $this->messages->sendMessage(['peer' => $update, 'message' => 'Downloaded to '.$file.' in '.(microtime(true) - $time).' seconds', 'reply_to_msg_id' => $update['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]); } } catch (\danog\MadelineProto\RPCErrorException $e) { $this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } } } $MadelineProto = new \danog\MadelineProto\API('bot.madeline'); $MadelineProto->start(); $MadelineProto->setEventHandler('\EventHandler'); $MadelineProto->loop(-1); . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\Deferred; class API extends APIFactory { use \danog\Serializable; use \danog\MadelineProto\Wrappers\ApiStart; use \danog\MadelineProto\Wrappers\ApiTemplates; public $session; public $serialized = 0; public $API; public $getting_api_id = false; public $my_telegram_org_wrapper; public $asyncAPIPromise; private $oldInstance = false; private $destructing = false; public function __magic_construct($params = [], $settings = []) { Magic::class_exists(); $deferred = new Deferred(); $this->asyncAPIPromise = $deferred->promise(); $this->asyncAPIPromise->onResolve(function () { $this->asyncAPIPromise = null; }); $this->setInitPromise($this->__construct_async($params, $settings, $deferred)); foreach (get_object_vars(new APIFactory('', $this, $this->async)) as $key => $var) { if (in_array($key, ['namespace', 'API', 'lua', 'async', 'asyncAPIPromise', 'methods', 'asyncInitPromise'])) { continue; } if (is_null($this->{$key})) { $this->{$key} = new APIFactory($key, $this->API, $this->async); } } } public function __construct_async($params, $settings, $deferred) { if (is_string($params)) { if (!\danog\MadelineProto\Logger::$default) { if (!isset($settings['logger']['logger_param'])) { $settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log'; } if (!isset($settings['logger']['logger'])) { $settings['logger']['logger'] = php_sapi_name() === 'cli' ? 3 : 2; } \danog\MadelineProto\Logger::constructor($settings['logger']['logger'], $settings['logger']['logger_param'], '', isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE, isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024); } $realpaths = Serialization::realpaths($params); $this->session = $realpaths['file']; if (file_exists($realpaths['file'])) { if (!file_exists($realpaths['lockfile'])) { touch($realpaths['lockfile']); clearstatcache(); } $realpaths['lockfile'] = fopen($realpaths['lockfile'], 'r'); \danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...'); flock($realpaths['lockfile'], LOCK_SH); \danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...'); try { $tounserialize = file_get_contents($realpaths['file']); } finally { flock($realpaths['lockfile'], LOCK_UN); fclose($realpaths['lockfile']); } \danog\MadelineProto\Magic::class_exists(); try { $unserialized = unserialize($tounserialize); } catch (\danog\MadelineProto\Bug74586Exception $e) { class_exists('\\Volatile'); $tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize); foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) { class_exists('\\danog\\MadelineProto\\'.$class); } $unserialized = \danog\Serialization::unserialize($tounserialize); } catch (\danog\MadelineProto\Exception $e) { if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) { throw $e; } if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { throw $e; } class_exists('\\Volatile'); foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) { class_exists('\\danog\\MadelineProto\\'.$class); } $changed = false; if (strpos($tounserialize, 'O:26:"danog\\MadelineProto\\Button":') !== false) { $tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize); $changed = true; } if (strpos($e->getMessage(), "Erroneous data format for unserializing 'phpseclib\\Math\\BigInteger'") === 0) { $tounserialize = str_replace('phpseclib\\Math\\BigInteger', 'phpseclib\\Math\\BigIntegor', $tounserialize); $changed = true; } Logger::log((string) $e, Logger::ERROR); if (!$changed) { throw $e; } $unserialized = \danog\Serialization::unserialize($tounserialize); } catch (\Throwable $e) { Logger::log((string) $e, Logger::ERROR); throw $e; } if ($unserialized instanceof \danog\PlaceHolder) { $unserialized = \danog\Serialization::unserialize($tounserialize); } if ($unserialized === false) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialization_error']); } $this->web_api_template = $unserialized->web_api_template; $this->my_telegram_org_wrapper = $unserialized->my_telegram_org_wrapper; $this->getting_api_id = $unserialized->getting_api_id; if (isset($unserialized->API)) { $this->API = $unserialized->API; $this->APIFactory(); $unserialized->oldInstance = true; $deferred->resolve(); yield $this->API->initAsync(); $this->APIFactory(); \danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE); $this->asyncInitPromise = null; $pong = yield $this->ping(['ping_id' => 3], ['async' => true]); \danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE); return; } } $params = $settings; } if (!\danog\MadelineProto\Logger::$default) { if (!isset($settings['logger']['logger_param'])) { $settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log'; } if (!isset($settings['logger']['logger'])) { $settings['logger']['logger'] = php_sapi_name() === 'cli' ? 3 : 2; } \danog\MadelineProto\Logger::constructor($settings['logger']['logger'], $settings['logger']['logger_param'], '', isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE, isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024); } if (!isset($params['app_info']['api_id']) || !$params['app_info']['api_id']) { $app = yield $this->api_start_async($params); $params['app_info']['api_id'] = $app['api_id']; $params['app_info']['api_hash'] = $app['api_hash']; } $this->API = new MTProto($params); $this->APIFactory(); $deferred->resolve(); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['apifactory_start'], Logger::VERBOSE); yield $this->API->initAsync(); $this->APIFactory(); $this->asyncInitPromise = null; \danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE); $pong = yield $this->ping(['ping_id' => 3], ['async' => true]); \danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE); } public function async($async) { $this->async = $async; if ($this->API) { if ($this->API->event_handler && class_exists($this->API->event_handler) && is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) { $this->API->setEventHandler($this->API->event_handler); } } } public function __wakeup() { //$this->APIFactory(); } public function __destruct() { if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()) || Magic::is_fork()) { return; } if ($this->asyncInitPromise) { $this->init(); } if (!$this->oldInstance) { if ($this->API) { $this->API->logger('Shutting down MadelineProto (normally or due to an exception, idk)'); $this->API->destructing = true; } else { Logger::log('Shutting down MadelineProto (normally or due to an exception, idk)'); } $this->destructing = true; $this->wait($this->serialize()); } //restore_error_handler(); } public function __sleep() { return ['API', 'web_api_template', 'getting_api_id', 'my_telegram_org_wrapper']; } private function from_camel_case($input) { preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); $ret = $matches[0]; foreach ($ret as &$match) { $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); } return implode('_', $ret); } public function my_get_self() { return isset($this->API) && isset($this->API->authorization['user']) ? $this->API->authorization['user'] : false; } public function APIFactory() { if ($this->API && !$this->API->asyncInitPromise) { foreach ($this->API->get_method_namespaces() as $namespace) { $this->{$namespace} = new APIFactory($namespace, $this->API, $this->async); } $methods = get_class_methods($this->API); foreach ($methods as $method) { if ($method == 'method_call_async_read') { unset($methods[array_search('method_call', $methods)]); } elseif (stripos($method, 'async') !== false) { if (strpos($method, '_async') !== false) { unset($methods[array_search(str_ireplace('_async', '', $method), $methods)]); } else { unset($methods[array_search(str_ireplace('async', '', $method), $methods)]); } } } $this->methods = []; foreach ($methods as $method) { $actual_method = $method; if ($method == 'method_call_async_read') { $method = 'method_call'; } elseif (stripos($method, 'async') !== false) { if (strpos($method, '_async') !== false) { $method = str_ireplace('_async', '', $method); } else { $method = str_ireplace('async', '', $method); } } $actual_method = $actual_method === 'get_self_async' ? [$this, 'my_get_self'] : [$this->API, $actual_method]; $this->methods[strtolower($method)] = $actual_method; if (strpos($method, '_') !== false) { $this->methods[strtolower(str_replace('_', '', $method))] = $actual_method; } else { $this->methods[strtolower($this->from_camel_case($method))] = $actual_method; } } $this->API->wrapper = $this; if ($this->API->event_handler && class_exists($this->API->event_handler) && is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) { $this->API->setEventHandler($this->API->event_handler); } } } public function get_all_methods() { if ($this->asyncInitPromise) { $this->init(); } $methods = []; foreach ($this->API->methods->by_id as $method) { $methods[] = $method['method']; } return array_merge($methods, get_class_methods($this->API)); } public function serialize($filename = null) { return $this->callFork((function () use ($filename) { if ($filename === null) { $filename = $this->session; } if (empty($filename)) { return; } Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']); if ($filename == '') { throw new \danog\MadelineProto\Exception('Empty filename'); } if (isset($this->API->setdem) && $this->API->setdem) { $this->API->setdem = false; $this->API->__construct($this->API->settings); } if ($this->API === null && !$this->getting_api_id) { return false; } if ($this->API && $this->API->asyncInitPromise) { yield $this->API->initAsync(); } $this->serialized = time(); $realpaths = Serialization::realpaths($filename); if (!file_exists($realpaths['lockfile'])) { touch($realpaths['lockfile']); clearstatcache(); } $realpaths['lockfile'] = fopen($realpaths['lockfile'], 'w'); \danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...'); flock($realpaths['lockfile'], LOCK_EX); \danog\MadelineProto\Logger::log('Lock acquired, serializing'); try { if (!$this->getting_api_id) { $update_closure = $this->API->settings['updates']['callback']; if ($this->API->settings['updates']['callback'] instanceof \Closure) { $this->API->settings['updates']['callback'] = [$this->API, 'noop']; } $logger_closure = $this->API->settings['logger']['logger_param']; if ($this->API->settings['logger']['logger_param'] instanceof \Closure) { $this->API->settings['logger']['logger_param'] = [$this->API, 'noop']; } } $wrote = file_put_contents($realpaths['tempfile'], serialize($this)); rename($realpaths['tempfile'], $realpaths['file']); } finally { if (!$this->getting_api_id) { $this->API->settings['updates']['callback'] = $update_closure; $this->API->settings['logger']['logger_param'] = $logger_closure; } flock($realpaths['lockfile'], LOCK_UN); fclose($realpaths['lockfile']); } return $wrote; })()); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\SecretChats; /** * Manages sequence numbers. */ trait SeqNoHandler { public function check_secret_in_seq_no_async($chat_id, $seqno) { $seqno = ($seqno - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2; $last = 0; foreach ($this->secret_chats[$chat_id]['incoming'] as $message) { if (isset($message['decrypted_message']['in_seq_no'])) { if (($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2 < $last) { yield $this->discard_secret_chat_async($chat_id); throw new \danog\MadelineProto\SecurityException('in_seq_no is not increasing'); } $last = ($message['decrypted_message']['in_seq_no'] - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2; } } if ($seqno > $this->secret_chats[$chat_id]['out_seq_no'] + 1) { yield $this->discard_secret_chat_async($chat_id); throw new \danog\MadelineProto\SecurityException('in_seq_no is too big'); } return true; } public function check_secret_out_seq_no_async($chat_id, $seqno) { $seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2; $C = 0; foreach ($this->secret_chats[$chat_id]['incoming'] as $message) { if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) { if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) { yield $this->discard_secret_chat_async($chat_id); throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2); } else { $C++; } } } //$this->logger->logger($C, $seqno); if ($seqno < $C) { // <= C $this->logger->logger('WARNING: dropping repeated message with seqno '.$seqno); return false; } if ($seqno > $C) { // > C+1 yield $this->discard_secret_chat_async($chat_id); throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!'); } return true; } public function generate_secret_in_seq_no($chat) { return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['in_seq_no'] * 2 + $this->secret_chats[$chat]['in_seq_no_x'] : -1; } public function generate_secret_out_seq_no($chat) { return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['out_seq_no'] * 2 + $this->secret_chats[$chat]['out_seq_no_x'] : -1; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\SecretChats; /** * Manages secret chats. * * https://core.telegram.org/api/end-to-end */ trait AuthKeyHandler { protected $temp_requested_secret_chats = []; protected $secret_chats = []; public function accept_secret_chat_async($params) { //$this->logger->logger($params['id'],$this->secret_chat_status($params['id'])); if ($this->secret_chat_status($params['id']) !== 0) { //$this->logger->logger($this->secret_chat_status($params['id'])); $this->logger->logger("I've already accepted secret chat ".$params['id']); return false; } $dh_config = yield $this->get_dh_config_async(); $this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE); $b = new \phpseclib\Math\BigInteger($this->random(256), 256); $params['g_a'] = new \phpseclib\Math\BigInteger($params['g_a'], 256); $this->check_G($params['g_a'], $dh_config['p']); $key = ['auth_key' => str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)]; //$this->logger->logger($key); $key['fingerprint'] = substr(sha1($key['auth_key'], true), -8); $key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16); $key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20); $this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'key_x' => 'from server', 'mtproto' => 1]; $g_b = $dh_config['g']->powMod($b, $dh_config['p']); $this->check_G($g_b, $dh_config['p']); yield $this->method_call_async_read('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]); yield $this->notify_layer_async($params['id']); $this->logger->logger('Secret chat '.$params['id'].' accepted successfully!', \danog\MadelineProto\Logger::NOTICE); } public function request_secret_chat_async($user) { $user = yield $this->get_info_async($user); if (!isset($user['InputUser'])) { throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } $user = $user['InputUser']; $this->logger->logger('Creating secret chat with '.$user['user_id'].'...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE); $a = new \phpseclib\Math\BigInteger($this->random(256), 256); $this->logger->logger('Generating g_a...', \danog\MadelineProto\Logger::VERBOSE); $g_a = $dh_config['g']->powMod($a, $dh_config['p']); $this->check_G($g_a, $dh_config['p']); $res = yield $this->method_call_async_read('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]); $this->temp_requested_secret_chats[$res['id']] = $a; $this->updaters[false]->resume(); $this->logger->logger('Secret chat '.$res['id'].' requested successfully!', \danog\MadelineProto\Logger::NOTICE); return $res['id']; } public function complete_secret_chat_async($params) { if ($this->secret_chat_status($params['id']) !== 1) { //$this->logger->logger($this->secret_chat_status($params['id'])); $this->logger->logger('Could not find and complete secret chat '.$params['id']); return false; } $dh_config = yield $this->get_dh_config_async(); $params['g_a_or_b'] = new \phpseclib\Math\BigInteger($params['g_a_or_b'], 256); $this->check_G($params['g_a_or_b'], $dh_config['p']); $key = ['auth_key' => str_pad($params['g_a_or_b']->powMod($this->temp_requested_secret_chats[$params['id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)]; unset($this->temp_requested_secret_chats[$params['id']]); $key['fingerprint'] = substr(sha1($key['auth_key'], true), -8); //$this->logger->logger($key); if ($key['fingerprint'] !== $params['key_fingerprint']) { yield $this->discard_secret_chat_async($params['id']); throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } $key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16); $key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20); $this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1]; yield $this->notify_layer_async($params['id']); $this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE); } public function notify_layer_async($chat) { yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->encrypted_layer]]], ['datacenter' => $this->datacenter->curdc]); } protected $temp_rekeyed_secret_chats = []; public function rekey_async($chat) { if ($this->secret_chats[$chat]['rekeying'][0] !== 0) { return; } $this->logger->logger('Rekeying secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE); $a = new \phpseclib\Math\BigInteger($this->random(256), 256); $this->logger->logger('Generating g_a...', \danog\MadelineProto\Logger::VERBOSE); $g_a = $dh_config['g']->powMod($a, $dh_config['p']); $this->check_G($g_a, $dh_config['p']); $e = $this->random(8); $this->temp_rekeyed_secret_chats[$e] = $a; $this->secret_chats[$chat]['rekeying'] = [1, $e]; yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionRequestKey', 'g_a' => $g_a->toBytes(), 'exchange_id' => $e]]], ['datacenter' => $this->datacenter->curdc]); $this->updaters[false]->resume(); return $e; } public function accept_rekey_async($chat, $params) { if ($this->secret_chats[$chat]['rekeying'][0] !== 0) { $my_exchange_id = new \phpseclib\Math\BigInteger($this->secret_chats[$chat]['rekeying'][1], -256); $other_exchange_id = new \phpseclib\Math\BigInteger($params['exchange_id'], -256); //$this->logger->logger($my, $params); if ($my_exchange_id > $other_exchange_id) { return; } if ($my_exchange_id === $other_exchange_id) { $this->secret_chats[$chat]['rekeying'] = [0]; return; } } $this->logger->logger('Accepting rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE); $b = new \phpseclib\Math\BigInteger($this->random(256), 256); $params['g_a'] = new \phpseclib\Math\BigInteger($params['g_a'], 256); $this->check_G($params['g_a'], $dh_config['p']); $key = ['auth_key' => str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)]; $key['fingerprint'] = substr(sha1($key['auth_key'], true), -8); $key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig']; $key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20); $this->temp_rekeyed_secret_chats[$params['exchange_id']] = $key; $this->secret_chats[$chat]['rekeying'] = [2, $params['exchange_id']]; $g_b = $dh_config['g']->powMod($b, $dh_config['p']); $this->check_G($g_b, $dh_config['p']); yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAcceptKey', 'g_b' => $g_b->toBytes(), 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]); $this->updaters[false]->resume(); } public function commit_rekey_async($chat, $params) { if ($this->secret_chats[$chat]['rekeying'][0] !== 1 || !isset($this->temp_rekeyed_secret_chats[$params['exchange_id']])) { $this->secret_chats[$chat]['rekeying'] = [0]; return; } $this->logger->logger('Committing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $params['g_b'] = new \phpseclib\Math\BigInteger($params['g_b'], 256); $this->check_G($params['g_b'], $dh_config['p']); $key = ['auth_key' => str_pad($params['g_b']->powMod($this->temp_rekeyed_secret_chats[$params['exchange_id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)]; $key['fingerprint'] = substr(sha1($key['auth_key'], true), -8); $key['visualization_orig'] = $this->secret_chats[$chat]['key']['visualization_orig']; $key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20); if ($key['fingerprint'] !== $params['key_fingerprint']) { yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]); throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionCommitKey', 'exchange_id' => $params['exchange_id'], 'key_fingerprint' => $key['fingerprint']]]], ['datacenter' => $this->datacenter->curdc]); unset($this->temp_rekeyed_secret_chats[$chat]); $this->secret_chats[$chat]['rekeying'] = [0]; $this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key']; $this->secret_chats[$chat]['key'] = $key; $this->secret_chats[$chat]['ttr'] = 100; $this->secret_chats[$chat]['updated'] = time(); $this->updaters[false]->resume(); } public function complete_rekey_async($chat, $params) { if ($this->secret_chats[$chat]['rekeying'][0] !== 2 || !isset($this->temp_rekeyed_secret_chats['fingerprint'])) { return; } if ($this->temp_rekeyed_secret_chats['fingerprint'] !== $params['key_fingerprint']) { yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]); throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); } $this->logger->logger('Completing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); $this->secret_chats[$chat]['rekeying'] = [0]; $this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key']; $this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$chat]; $this->secret_chats[$chat]['ttr'] = 100; $this->secret_chats[$chat]['updated'] = time(); unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]); yield $this->method_call_async_read('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]); $this->logger->logger('Secret chat '.$chat.' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE); return true; } public function secret_chat_status($chat) { if (isset($this->secret_chats[$chat])) { return 2; } if (isset($this->temp_requested_secret_chats[$chat])) { return 1; } return 0; } public function get_secret_chat($chat) { return $this->secret_chats[is_array($chat) ? $chat['chat_id'] : $chat]; } public function discard_secret_chat_async($chat) { $this->logger->logger('Discarding secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE); //$this->logger->logger(debug_backtrace(0)[0]); if (isset($this->secret_chats[$chat])) { unset($this->secret_chats[$chat]); } if (isset($this->temp_requested_secret_chats[$chat])) { unset($this->temp_requested_secret_chats[$chat]); } if (isset($this->temp_rekeyed_secret_chats[$chat])) { unset($this->temp_rekeyed_secret_chats[$chat]); } try { yield $this->method_call_async_read('messages.discardEncryption', ['chat_id' => $chat], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc !== 'ENCRYPTION_ALREADY_DECLINED') { throw $e; } } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\SecretChats; /** * Manages packing and unpacking of messages, and the list of sent and received messages. */ trait MessageHandler { public function encrypt_secret_message_async($chat_id, $message) { if (!isset($this->secret_chats[$chat_id])) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id)); return false; } $message['random_id'] = $this->random(8); $this->secret_chats[$chat_id]['ttr']--; if ($this->secret_chats[$chat_id]['layer'] > 8) { if (($this->secret_chats[$chat_id]['ttr'] <= 0 || time() - $this->secret_chats[$chat_id]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$chat_id]['rekeying'][0] === 0) { yield $this->rekey_async($chat_id); } $message = ['_' => 'decryptedMessageLayer', 'layer' => $this->secret_chats[$chat_id]['layer'], 'in_seq_no' => $this->generate_secret_in_seq_no($chat_id), 'out_seq_no' => $this->generate_secret_out_seq_no($chat_id), 'message' => $message]; $this->secret_chats[$chat_id]['out_seq_no']++; } $this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message; $message = yield $this->serialize_object_async(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']); $message = $this->pack_unsigned_int(strlen($message)).$message; if ($this->secret_chats[$chat_id]['mtproto'] === 2) { $padding = $this->posmod(-strlen($message), 16); if ($padding < 12) { $padding += 16; } $message .= $this->random($padding); $message_key = substr(hash('sha256', substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16); list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']); } else { $message_key = substr(sha1($message, true), -16); list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true); $message .= $this->random($this->posmod(-strlen($message), 16)); } $message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.$this->ige_encrypt($message, $aes_key, $aes_iv); return $message; } public function handle_encrypted_update_async($message, $test = false) { if (!isset($this->secret_chats[$message['message']['chat_id']])) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id'])); return false; } $auth_key_id = substr($message['message']['bytes'], 0, 8); $old = false; if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['key']['fingerprint']) { if (isset($this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint'])) { if ($auth_key_id !== $this->secret_chats[$message['message']['chat_id']]['old_key']['fingerprint']) { yield $this->discard_secret_chat_async($message['message']['chat_id']); throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']); } $old = true; } else { yield $this->discard_secret_chat_async($message['message']['chat_id']); throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_mismatch']); } } $message_key = substr($message['message']['bytes'], 8, 16); $encrypted_data = substr($message['message']['bytes'], 24); if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) { $this->logger->logger('Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); try { $message_data = $this->try_mtproto_v2_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); } catch (\danog\MadelineProto\SecurityException $e) { $this->logger->logger('MTProto v2 decryption failed with message '.$e->getMessage().', trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); $message_data = $this->try_mtproto_v1_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1; } } else { $this->logger->logger('Trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); try { $message_data = $this->try_mtproto_v1_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); } catch (\danog\MadelineProto\SecurityException $e) { $this->logger->logger('MTProto v1 decryption failed with message '.$e->getMessage().', trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); $message_data = $this->try_mtproto_v2_decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE); $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2; } } $deserialized = $this->deserialize($message_data, ['type' => '']); $this->secret_chats[$message['message']['chat_id']]['ttr']--; if (($this->secret_chats[$message['message']['chat_id']]['ttr'] <= 0 || time() - $this->secret_chats[$message['message']['chat_id']]['updated'] > 7 * 24 * 60 * 60) && $this->secret_chats[$message['message']['chat_id']]['rekeying'][0] === 0) { yield $this->rekey_async($message['message']['chat_id']); } unset($message['message']['bytes']); $message['message']['decrypted_message'] = $deserialized; $this->secret_chats[$message['message']['chat_id']]['incoming'][$this->secret_chats[$message['message']['chat_id']]['in_seq_no']] = $message['message']; yield $this->handle_decrypted_update_async($message); } public function try_mtproto_v1_decrypt($message_key, $chat_id, $old, $encrypted_data) { list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true); $decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv); $message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1]; $message_data = substr($decrypted_data, 4, $message_data_length); if ($message_data_length > strlen($decrypted_data)) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']); } if ($message_key != substr(sha1(substr($decrypted_data, 0, 4 + $message_data_length), true), -16)) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']); } if (strlen($decrypted_data) - 4 - $message_data_length > 15) { throw new \danog\MadelineProto\SecurityException('difference between message_data_length and the length of the remaining decrypted buffer is too big'); } if (strlen($decrypted_data) % 16 != 0) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']); } return $message_data; } public function try_mtproto_v2_decrypt($message_key, $chat_id, $old, $encrypted_data) { list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']); $decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv); $message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1]; $message_data = substr($decrypted_data, 4, $message_data_length); if ($message_data_length > strlen($decrypted_data)) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']); } if ($message_key != substr(hash('sha256', substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']); } if (strlen($decrypted_data) - 4 - $message_data_length < 12) { throw new \danog\MadelineProto\SecurityException('padding is too small'); } if (strlen($decrypted_data) - 4 - $message_data_length > 1024) { throw new \danog\MadelineProto\SecurityException('padding is too big'); } if (strlen($decrypted_data) % 16 != 0) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16']); } return $message_data; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\SecretChats; /** * Manages responses. */ trait ResponseHandler { public function handle_decrypted_update_async($update) { /*if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) { throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_short']); }*/ // already checked in TL.php switch ($update['message']['decrypted_message']['_']) { case 'decryptedMessageService': switch ($update['message']['decrypted_message']['action']['_']) { case 'decryptedMessageActionRequestKey': yield $this->accept_rekey_async($update['message']['chat_id'], $update['message']['decrypted_message']['action']); return; case 'decryptedMessageActionAcceptKey': yield $this->commit_rekey_async($update['message']['chat_id'], $update['message']['decrypted_message']['action']); return; case 'decryptedMessageActionCommitKey': yield $this->complete_rekey_async($update['message']['chat_id'], $update['message']['decrypted_message']['action']); return; case 'decryptedMessageActionNotifyLayer': $this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['action']['layer']; if ($update['message']['decrypted_message']['action']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) { yield $this->notify_layer_async($update['message']['chat_id']); } if ($update['message']['decrypted_message']['action']['layer'] >= 73) { $this->secret_chats[$update['message']['chat_id']]['mtproto'] = 2; } return; case 'decryptedMessageActionSetMessageTTL': $this->secret_chats[$update['message']['chat_id']]['ttl'] = $update['message']['decrypted_message']['action']['ttl_seconds']; yield $this->save_update_async($update); return; case 'decryptedMessageActionNoop': return; case 'decryptedMessageActionResend': $update['message']['decrypted_message']['action']['start_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x']; $update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x']; $update['message']['decrypted_message']['action']['start_seq_no'] /= 2; $update['message']['decrypted_message']['action']['end_seq_no'] /= 2; $this->logger->logger('Resending messages for secret chat '.$update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING); foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) { if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) { //throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']); yield $this->method_call_async_read('messages.sendEncrypted', ['peer' => $update['message']['chat_id'], 'message' => $update['message']['decrypted_message']], ['datacenter' => $this->datacenter->curdc]); } } return; default: // yield $this->save_update_async(['_' => 'updateNewDecryptedMessage', 'peer' => $this->secret_chats[$update['message']['chat_id']]['InputEncryptedChat'], 'in_seq_no' => $this->get_in_seq_no($update['message']['chat_id']), 'out_seq_no' => $this->get_out_seq_no($update['message']['chat_id']), 'message' => $update['message']['decrypted_message']]); yield $this->save_update_async($update); } break; case 'decryptedMessage': yield $this->save_update_async($update); break; case 'decryptedMessageLayer': if (yield $this->check_secret_out_seq_no_async($update['message']['chat_id'], $update['message']['decrypted_message']['out_seq_no']) && yield $this->check_secret_in_seq_no_async($update['message']['chat_id'], $update['message']['decrypted_message']['in_seq_no'])) { $this->secret_chats[$update['message']['chat_id']]['in_seq_no']++; if ($update['message']['decrypted_message']['layer'] >= 17) { $this->secret_chats[$update['message']['chat_id']]['layer'] = $update['message']['decrypted_message']['layer']; if ($update['message']['decrypted_message']['layer'] >= 17 && time() - $this->secret_chats[$update['message']['chat_id']]['created'] > 15) { yield $this->notify_layer_async($update['message']['chat_id']); } } $update['message']['decrypted_message'] = $update['message']['decrypted_message']['message']; yield $this->handle_decrypted_update_async($update); } break; default: throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].var_export($update, true)); break; } } } { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-2106507297", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "2004934137", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "-652419756", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "admins_enabled", "type": "flags.3?true" }, { "name": "admin", "type": "flags.4?true" }, { "name": "deactivated", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "migrated_to", "type": "flags.6?InputChannel" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "1061556205", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "1537633299", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" }, { "name": "views", "type": "flags.10?int" } ], "type": "Message" }, { "id": "-1066691065", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-136766906", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-892863022", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "ipv6", "type": "flags.0?true" }, { "name": "media_only", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1823925854", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "megagroup_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-719474725", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "channel", "type": "flags.0?true" }, { "name": "broadcast", "type": "flags.1?true" }, { "name": "public", "type": "flags.2?true" }, { "name": "megagroup", "type": "flags.3?true" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "installed", "type": "flags.0?true" }, { "name": "disabled", "type": "flags.1?true" }, { "name": "official", "type": "flags.2?true" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "585404530", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "self", "type": "flags.10?true" }, { "name": "contact", "type": "flags.11?true" }, { "name": "mutual_contact", "type": "flags.12?true" }, { "name": "deleted", "type": "flags.13?true" }, { "name": "bot", "type": "flags.14?true" }, { "name": "bot_chat_history", "type": "flags.15?true" }, { "name": "bot_nochats", "type": "flags.16?true" }, { "name": "verified", "type": "flags.17?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "resize", "type": "flags.0?true" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "1737397639", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "editor", "type": "flags.3?true" }, { "name": "moderator", "type": "flags.4?true" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "verified", "type": "flags.7?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "763724588", "predicate": "channelForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1640751649", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "can_view_participants", "type": "flags.3?true" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" }, { "name": "migrated_from_chat_id", "type": "flags.4?int" }, { "name": "migrated_from_max_id", "type": "flags.4?int" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "1620337698", "predicate": "updateChannelTooLong", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1016324548", "predicate": "updateChannelGroup", "params": [ { "name": "channel_id", "type": "int" }, { "name": "group", "type": "MessageGroup" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" }, { "id": "-100588754", "predicate": "channelMessagesFilterCollapsed", "params": [], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipant" }, { "id": "-636267638", "predicate": "chatParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-489233354", "predicate": "chatParticipantAdmin", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "1855224129", "predicate": "updateChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1232070311", "predicate": "updateChatParticipantAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "is_admin", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1371385889", "predicate": "messageActionChatMigrateTo", "params": [ { "name": "channel_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1689067688", "predicate": "messageActionChatDeactivate", "params": [], "type": "MessageAction" }, { "id": "1085115570", "predicate": "messageActionChatActivate", "params": [], "type": "MessageAction" }, { "id": "-1336546578", "predicate": "messageActionChannelMigrateFrom", "params": [ { "name": "title", "type": "string" }, { "name": "chat_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1328445861", "predicate": "channelParticipantsBots", "params": [], "type": "ChannelParticipantsFilter" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-2053423812", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1970355494", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "238054714", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "-1212072999", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-421563528", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "increment", "type": "Bool" } ], "type": "Vector" }, { "id": "-1445735863", "method": "channels.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-575067701", "method": "channels.getImportantHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "-192332417", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.0?true" }, { "name": "megagroup", "type": "flags.1?true" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "1387358562", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Bool" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-1432183160", "method": "channels.toggleComments", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" }, { "id": "-326379039", "method": "messages.toggleChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1444503762", "method": "messages.editChatAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "is_admin", "type": "Bool" } ], "type": "Bool" }, { "id": "1651444545", "method": "messages.deactivateChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "363051235", "method": "messages.migrateChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Updates" }, { "id": "-1640190800", "method": "messages.searchGlobal", "params": [ { "name": "q", "type": "string" }, { "name": "offset_date", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" } ] } = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#3213dbba flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; documentEmpty#36f8c871 id:long = Document; document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; help.passportConfigNotModified#bfb9f457 = help.PassportConfig; help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector; messages.clearAllDrafts#7e58ee9c = Bool; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#522d5a7d source:string = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#42c6978f lang_pack:string = Vector; // LAYER 86 dataJSON#7d748d04 data:string = DataJSON; socketMessageRequest request_id:int method:vector args:vector<%DataJSON> = SocketMessage; socketMessageResponse request_id:int data:%DataJSON = SocketMessage; socketMessageException request_id:int exception:SocketException = SocketMessage; socketMessageUpdate data:%DataJSON = SocketMessage; socketMessageLog flags:# thread:flags.0?true process:flags.1?true file:string level:int data:%DataJSON = SocketMessage; socketMessageRawData stream_id:string data:bytes = SocketMessage; socketException message:string code:int trace:%SocketTLTrace = SocketException; socketRPCErrorException flags:# rpc_message:flags.0?string message:flags.1?string code:int trace:%SocketTLTrace = SocketException; socketTLException message:string code:int trace:%SocketTLTrace = SocketException; socketDOMException message:string code:int trace:%SocketTLTrace = SocketException; socketTLTrace frames:vector<%SocketTLFrame> = SocketTLTrace; socketTLFrame flags:# file:flags.0?string line:flags.1?int function:flags.2?string args:flags.3?string tl_param:flags.4?string = SocketTLFrame; {"constructors":[{"id":"-1132882121","predicate":"boolFalse","params":[],"type":"Bool"},{"id":"-1720552011","predicate":"boolTrue","params":[],"type":"Bool"},{"id":"1072550713","predicate":"true","params":[],"type":"True"},{"id":"481674261","predicate":"vector","params":[],"type":"Vector t"},{"id":"-994444869","predicate":"error","params":[{"name":"code","type":"int"},{"name":"text","type":"string"}],"type":"Error"},{"id":"1450380236","predicate":"null","params":[],"type":"Null"},{"id":"2134579434","predicate":"inputPeerEmpty","params":[],"type":"InputPeer"},{"id":"2107670217","predicate":"inputPeerSelf","params":[],"type":"InputPeer"},{"id":"396093539","predicate":"inputPeerChat","params":[{"name":"chat_id","type":"int"}],"type":"InputPeer"},{"id":"-1182234929","predicate":"inputUserEmpty","params":[],"type":"InputUser"},{"id":"-138301121","predicate":"inputUserSelf","params":[],"type":"InputUser"},{"id":"-208488460","predicate":"inputPhoneContact","params":[{"name":"client_id","type":"long"},{"name":"phone","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"InputContact"},{"id":"-181407105","predicate":"inputFile","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"name","type":"string"},{"name":"md5_checksum","type":"string"}],"type":"InputFile"},{"id":"-1771768449","predicate":"inputMediaEmpty","params":[],"type":"InputMedia"},{"id":"-139464256","predicate":"inputMediaUploadedPhoto","params":[{"name":"file","type":"InputFile"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-373312269","predicate":"inputMediaPhoto","params":[{"name":"id","type":"InputPhoto"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-104578748","predicate":"inputMediaGeoPoint","params":[{"name":"geo_point","type":"InputGeoPoint"}],"type":"InputMedia"},{"id":"-1494984313","predicate":"inputMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"InputMedia"},{"id":"480546647","predicate":"inputChatPhotoEmpty","params":[],"type":"InputChatPhoto"},{"id":"-1809496270","predicate":"inputChatUploadedPhoto","params":[{"name":"file","type":"InputFile"},{"name":"crop","type":"InputPhotoCrop"}],"type":"InputChatPhoto"},{"id":"-1293828344","predicate":"inputChatPhoto","params":[{"name":"id","type":"InputPhoto"},{"name":"crop","type":"InputPhotoCrop"}],"type":"InputChatPhoto"},{"id":"-457104426","predicate":"inputGeoPointEmpty","params":[],"type":"InputGeoPoint"},{"id":"-206066487","predicate":"inputGeoPoint","params":[{"name":"lat","type":"double"},{"name":"long","type":"double"}],"type":"InputGeoPoint"},{"id":"483901197","predicate":"inputPhotoEmpty","params":[],"type":"InputPhoto"},{"id":"-74070332","predicate":"inputPhoto","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputPhoto"},{"id":"342061462","predicate":"inputFileLocation","params":[{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"InputFileLocation"},{"id":"-1377390588","predicate":"inputPhotoCropAuto","params":[],"type":"InputPhotoCrop"},{"id":"-644787419","predicate":"inputPhotoCrop","params":[{"name":"crop_left","type":"double"},{"name":"crop_top","type":"double"},{"name":"crop_width","type":"double"}],"type":"InputPhotoCrop"},{"id":"1996904104","predicate":"inputAppEvent","params":[{"name":"time","type":"double"},{"name":"type","type":"string"},{"name":"peer","type":"long"},{"name":"data","type":"string"}],"type":"InputAppEvent"},{"id":"-1649296275","predicate":"peerUser","params":[{"name":"user_id","type":"int"}],"type":"Peer"},{"id":"-1160714821","predicate":"peerChat","params":[{"name":"chat_id","type":"int"}],"type":"Peer"},{"id":"-1432995067","predicate":"storage.fileUnknown","params":[],"type":"storage.FileType"},{"id":"8322574","predicate":"storage.fileJpeg","params":[],"type":"storage.FileType"},{"id":"-891180321","predicate":"storage.fileGif","params":[],"type":"storage.FileType"},{"id":"172975040","predicate":"storage.filePng","params":[],"type":"storage.FileType"},{"id":"-1373745011","predicate":"storage.filePdf","params":[],"type":"storage.FileType"},{"id":"1384777335","predicate":"storage.fileMp3","params":[],"type":"storage.FileType"},{"id":"1258941372","predicate":"storage.fileMov","params":[],"type":"storage.FileType"},{"id":"1086091090","predicate":"storage.filePartial","params":[],"type":"storage.FileType"},{"id":"-1278304028","predicate":"storage.fileMp4","params":[],"type":"storage.FileType"},{"id":"276907596","predicate":"storage.fileWebp","params":[],"type":"storage.FileType"},{"id":"2086234950","predicate":"fileLocationUnavailable","params":[{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"FileLocation"},{"id":"1406570614","predicate":"fileLocation","params":[{"name":"dc_id","type":"int"},{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"FileLocation"},{"id":"537022650","predicate":"userEmpty","params":[{"name":"id","type":"int"}],"type":"User"},{"id":"1326562017","predicate":"userProfilePhotoEmpty","params":[],"type":"UserProfilePhoto"},{"id":"-715532088","predicate":"userProfilePhoto","params":[{"name":"photo_id","type":"long"},{"name":"photo_small","type":"FileLocation"},{"name":"photo_big","type":"FileLocation"}],"type":"UserProfilePhoto"},{"id":"164646985","predicate":"userStatusEmpty","params":[],"type":"UserStatus"},{"id":"-306628279","predicate":"userStatusOnline","params":[{"name":"expires","type":"int"}],"type":"UserStatus"},{"id":"9203775","predicate":"userStatusOffline","params":[{"name":"was_online","type":"int"}],"type":"UserStatus"},{"id":"-1683826688","predicate":"chatEmpty","params":[{"name":"id","type":"int"}],"type":"Chat"},{"id":"-652419756","predicate":"chat","params":[{"name":"flags","type":"#"},{"name":"creator","type":"flags.0?true"},{"name":"kicked","type":"flags.1?true"},{"name":"left","type":"flags.2?true"},{"name":"admins_enabled","type":"flags.3?true"},{"name":"admin","type":"flags.4?true"},{"name":"deactivated","type":"flags.5?true"},{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"photo","type":"ChatPhoto"},{"name":"participants_count","type":"int"},{"name":"date","type":"int"},{"name":"version","type":"int"},{"name":"migrated_to","type":"flags.6?InputChannel"}],"type":"Chat"},{"id":"120753115","predicate":"chatForbidden","params":[{"name":"id","type":"int"},{"name":"title","type":"string"}],"type":"Chat"},{"id":"771925524","predicate":"chatFull","params":[{"name":"id","type":"int"},{"name":"participants","type":"ChatParticipants"},{"name":"chat_photo","type":"Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"exported_invite","type":"ExportedChatInvite"},{"name":"bot_info","type":"Vector"}],"type":"ChatFull"},{"id":"-925415106","predicate":"chatParticipant","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChatParticipant"},{"id":"-57668565","predicate":"chatParticipantsForbidden","params":[{"name":"flags","type":"#"},{"name":"chat_id","type":"int"},{"name":"self_participant","type":"flags.0?ChatParticipant"}],"type":"ChatParticipants"},{"id":"1061556205","predicate":"chatParticipants","params":[{"name":"chat_id","type":"int"},{"name":"participants","type":"Vector"},{"name":"version","type":"int"}],"type":"ChatParticipants"},{"id":"935395612","predicate":"chatPhotoEmpty","params":[],"type":"ChatPhoto"},{"id":"1632839530","predicate":"chatPhoto","params":[{"name":"photo_small","type":"FileLocation"},{"name":"photo_big","type":"FileLocation"}],"type":"ChatPhoto"},{"id":"-2082087340","predicate":"messageEmpty","params":[{"name":"id","type":"int"}],"type":"Message"},{"id":"-1063525281","predicate":"message","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"post","type":"flags.14?true"},{"name":"id","type":"int"},{"name":"from_id","type":"flags.8?int"},{"name":"to_id","type":"Peer"},{"name":"fwd_from","type":"flags.2?MessageFwdHeader"},{"name":"via_bot_id","type":"flags.11?int"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"date","type":"int"},{"name":"message","type":"string"},{"name":"media","type":"flags.9?MessageMedia"},{"name":"reply_markup","type":"flags.6?ReplyMarkup"},{"name":"entities","type":"flags.7?Vector"},{"name":"views","type":"flags.10?int"},{"name":"edit_date","type":"flags.15?int"}],"type":"Message"},{"id":"-1642487306","predicate":"messageService","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"post","type":"flags.14?true"},{"name":"id","type":"int"},{"name":"from_id","type":"flags.8?int"},{"name":"to_id","type":"Peer"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"date","type":"int"},{"name":"action","type":"MessageAction"}],"type":"Message"},{"id":"1038967584","predicate":"messageMediaEmpty","params":[],"type":"MessageMedia"},{"id":"1032643901","predicate":"messageMediaPhoto","params":[{"name":"photo","type":"Photo"},{"name":"caption","type":"string"}],"type":"MessageMedia"},{"id":"1457575028","predicate":"messageMediaGeo","params":[{"name":"geo","type":"GeoPoint"}],"type":"MessageMedia"},{"id":"1585262393","predicate":"messageMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"user_id","type":"int"}],"type":"MessageMedia"},{"id":"-1618676578","predicate":"messageMediaUnsupported","params":[],"type":"MessageMedia"},{"id":"-1230047312","predicate":"messageActionEmpty","params":[],"type":"MessageAction"},{"id":"-1503425638","predicate":"messageActionChatCreate","params":[{"name":"title","type":"string"},{"name":"users","type":"Vector"}],"type":"MessageAction"},{"id":"-1247687078","predicate":"messageActionChatEditTitle","params":[{"name":"title","type":"string"}],"type":"MessageAction"},{"id":"2144015272","predicate":"messageActionChatEditPhoto","params":[{"name":"photo","type":"Photo"}],"type":"MessageAction"},{"id":"-1780220945","predicate":"messageActionChatDeletePhoto","params":[],"type":"MessageAction"},{"id":"1217033015","predicate":"messageActionChatAddUser","params":[{"name":"users","type":"Vector"}],"type":"MessageAction"},{"id":"-1297179892","predicate":"messageActionChatDeleteUser","params":[{"name":"user_id","type":"int"}],"type":"MessageAction"},{"id":"1728035348","predicate":"dialog","params":[{"name":"flags","type":"#"},{"name":"peer","type":"Peer"},{"name":"top_message","type":"int"},{"name":"read_inbox_max_id","type":"int"},{"name":"read_outbox_max_id","type":"int"},{"name":"unread_count","type":"int"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"pts","type":"flags.0?int"},{"name":"draft","type":"flags.1?DraftMessage"}],"type":"Dialog"},{"id":"590459437","predicate":"photoEmpty","params":[{"name":"id","type":"long"}],"type":"Photo"},{"id":"-840088834","predicate":"photo","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"sizes","type":"Vector"}],"type":"Photo"},{"id":"236446268","predicate":"photoSizeEmpty","params":[{"name":"type","type":"string"}],"type":"PhotoSize"},{"id":"2009052699","predicate":"photoSize","params":[{"name":"type","type":"string"},{"name":"location","type":"FileLocation"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"size","type":"int"}],"type":"PhotoSize"},{"id":"-374917894","predicate":"photoCachedSize","params":[{"name":"type","type":"string"},{"name":"location","type":"FileLocation"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"bytes","type":"bytes"}],"type":"PhotoSize"},{"id":"286776671","predicate":"geoPointEmpty","params":[],"type":"GeoPoint"},{"id":"541710092","predicate":"geoPoint","params":[{"name":"long","type":"double"},{"name":"lat","type":"double"}],"type":"GeoPoint"},{"id":"-2128698738","predicate":"auth.checkedPhone","params":[{"name":"phone_registered","type":"Bool"}],"type":"auth.CheckedPhone"},{"id":"1577067778","predicate":"auth.sentCode","params":[{"name":"flags","type":"#"},{"name":"phone_registered","type":"flags.0?true"},{"name":"type","type":"auth.SentCodeType"},{"name":"phone_code_hash","type":"string"},{"name":"next_type","type":"flags.1?auth.CodeType"},{"name":"timeout","type":"flags.2?int"}],"type":"auth.SentCode"},{"id":"-855308010","predicate":"auth.authorization","params":[{"name":"flags","type":"#"},{"name":"tmp_sessions","type":"flags.0?int"},{"name":"user","type":"User"}],"type":"auth.Authorization"},{"id":"-543777747","predicate":"auth.exportedAuthorization","params":[{"name":"id","type":"int"},{"name":"bytes","type":"bytes"}],"type":"auth.ExportedAuthorization"},{"id":"-1195615476","predicate":"inputNotifyPeer","params":[{"name":"peer","type":"InputPeer"}],"type":"InputNotifyPeer"},{"id":"423314455","predicate":"inputNotifyUsers","params":[],"type":"InputNotifyPeer"},{"id":"1251338318","predicate":"inputNotifyChats","params":[],"type":"InputNotifyPeer"},{"id":"-1540769658","predicate":"inputNotifyAll","params":[],"type":"InputNotifyPeer"},{"id":"-265263912","predicate":"inputPeerNotifyEventsEmpty","params":[],"type":"InputPeerNotifyEvents"},{"id":"-395694988","predicate":"inputPeerNotifyEventsAll","params":[],"type":"InputPeerNotifyEvents"},{"id":"949182130","predicate":"inputPeerNotifySettings","params":[{"name":"flags","type":"#"},{"name":"show_previews","type":"flags.0?true"},{"name":"silent","type":"flags.1?true"},{"name":"mute_until","type":"int"},{"name":"sound","type":"string"}],"type":"InputPeerNotifySettings"},{"id":"-1378534221","predicate":"peerNotifyEventsEmpty","params":[],"type":"PeerNotifyEvents"},{"id":"1830677896","predicate":"peerNotifyEventsAll","params":[],"type":"PeerNotifyEvents"},{"id":"1889961234","predicate":"peerNotifySettingsEmpty","params":[],"type":"PeerNotifySettings"},{"id":"-1697798976","predicate":"peerNotifySettings","params":[{"name":"flags","type":"#"},{"name":"show_previews","type":"flags.0?true"},{"name":"silent","type":"flags.1?true"},{"name":"mute_until","type":"int"},{"name":"sound","type":"string"}],"type":"PeerNotifySettings"},{"id":"-2122045747","predicate":"peerSettings","params":[{"name":"flags","type":"#"},{"name":"report_spam","type":"flags.0?true"}],"type":"PeerSettings"},{"id":"-860866985","predicate":"wallPaper","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"sizes","type":"Vector"},{"name":"color","type":"int"}],"type":"WallPaper"},{"id":"1490799288","predicate":"inputReportReasonSpam","params":[],"type":"ReportReason"},{"id":"505595789","predicate":"inputReportReasonViolence","params":[],"type":"ReportReason"},{"id":"777640226","predicate":"inputReportReasonPornography","params":[],"type":"ReportReason"},{"id":"-512463606","predicate":"inputReportReasonOther","params":[{"name":"text","type":"string"}],"type":"ReportReason"},{"id":"1496513539","predicate":"userFull","params":[{"name":"flags","type":"#"},{"name":"blocked","type":"flags.0?true"},{"name":"user","type":"User"},{"name":"about","type":"flags.1?string"},{"name":"link","type":"contacts.Link"},{"name":"profile_photo","type":"flags.2?Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"bot_info","type":"flags.3?BotInfo"}],"type":"UserFull"},{"id":"-116274796","predicate":"contact","params":[{"name":"user_id","type":"int"},{"name":"mutual","type":"Bool"}],"type":"Contact"},{"id":"-805141448","predicate":"importedContact","params":[{"name":"user_id","type":"int"},{"name":"client_id","type":"long"}],"type":"ImportedContact"},{"id":"1444661369","predicate":"contactBlocked","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"ContactBlocked"},{"id":"-748155807","predicate":"contactStatus","params":[{"name":"user_id","type":"int"},{"name":"status","type":"UserStatus"}],"type":"ContactStatus"},{"id":"986597452","predicate":"contacts.link","params":[{"name":"my_link","type":"ContactLink"},{"name":"foreign_link","type":"ContactLink"},{"name":"user","type":"User"}],"type":"contacts.Link"},{"id":"-1219778094","predicate":"contacts.contactsNotModified","params":[],"type":"contacts.Contacts"},{"id":"1871416498","predicate":"contacts.contacts","params":[{"name":"contacts","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Contacts"},{"id":"-1387117803","predicate":"contacts.importedContacts","params":[{"name":"imported","type":"Vector"},{"name":"retry_contacts","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.ImportedContacts"},{"id":"471043349","predicate":"contacts.blocked","params":[{"name":"blocked","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Blocked"},{"id":"-1878523231","predicate":"contacts.blockedSlice","params":[{"name":"count","type":"int"},{"name":"blocked","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Blocked"},{"id":"364538944","predicate":"messages.dialogs","params":[{"name":"dialogs","type":"Vector"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Dialogs"},{"id":"1910543603","predicate":"messages.dialogsSlice","params":[{"name":"count","type":"int"},{"name":"dialogs","type":"Vector"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Dialogs"},{"id":"-1938715001","predicate":"messages.messages","params":[{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Messages"},{"id":"189033187","predicate":"messages.messagesSlice","params":[{"name":"count","type":"int"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Messages"},{"id":"1694474197","predicate":"messages.chats","params":[{"name":"chats","type":"Vector"}],"type":"messages.Chats"},{"id":"-438840932","predicate":"messages.chatFull","params":[{"name":"full_chat","type":"ChatFull"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.ChatFull"},{"id":"-1269012015","predicate":"messages.affectedHistory","params":[{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"offset","type":"int"}],"type":"messages.AffectedHistory"},{"id":"1474492012","predicate":"inputMessagesFilterEmpty","params":[],"type":"MessagesFilter"},{"id":"-1777752804","predicate":"inputMessagesFilterPhotos","params":[],"type":"MessagesFilter"},{"id":"-1614803355","predicate":"inputMessagesFilterVideo","params":[],"type":"MessagesFilter"},{"id":"1458172132","predicate":"inputMessagesFilterPhotoVideo","params":[],"type":"MessagesFilter"},{"id":"-648121413","predicate":"inputMessagesFilterPhotoVideoDocuments","params":[],"type":"MessagesFilter"},{"id":"-1629621880","predicate":"inputMessagesFilterDocument","params":[],"type":"MessagesFilter"},{"id":"2129714567","predicate":"inputMessagesFilterUrl","params":[],"type":"MessagesFilter"},{"id":"-3644025","predicate":"inputMessagesFilterGif","params":[],"type":"MessagesFilter"},{"id":"522914557","predicate":"updateNewMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"1318109142","predicate":"updateMessageID","params":[{"name":"id","type":"int"},{"name":"random_id","type":"long"}],"type":"Update"},{"id":"-1576161051","predicate":"updateDeleteMessages","params":[{"name":"messages","type":"Vector"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"1548249383","predicate":"updateUserTyping","params":[{"name":"user_id","type":"int"},{"name":"action","type":"SendMessageAction"}],"type":"Update"},{"id":"-1704596961","predicate":"updateChatUserTyping","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"action","type":"SendMessageAction"}],"type":"Update"},{"id":"125178264","predicate":"updateChatParticipants","params":[{"name":"participants","type":"ChatParticipants"}],"type":"Update"},{"id":"469489699","predicate":"updateUserStatus","params":[{"name":"user_id","type":"int"},{"name":"status","type":"UserStatus"}],"type":"Update"},{"id":"-1489818765","predicate":"updateUserName","params":[{"name":"user_id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"username","type":"string"}],"type":"Update"},{"id":"-1791935732","predicate":"updateUserPhoto","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"photo","type":"UserProfilePhoto"},{"name":"previous","type":"Bool"}],"type":"Update"},{"id":"628472761","predicate":"updateContactRegistered","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"Update"},{"id":"-1657903163","predicate":"updateContactLink","params":[{"name":"user_id","type":"int"},{"name":"my_link","type":"ContactLink"},{"name":"foreign_link","type":"ContactLink"}],"type":"Update"},{"id":"-1895411046","predicate":"updateNewAuthorization","params":[{"name":"auth_key_id","type":"long"},{"name":"date","type":"int"},{"name":"device","type":"string"},{"name":"location","type":"string"}],"type":"Update"},{"id":"-1519637954","predicate":"updates.state","params":[{"name":"pts","type":"int"},{"name":"qts","type":"int"},{"name":"date","type":"int"},{"name":"seq","type":"int"},{"name":"unread_count","type":"int"}],"type":"updates.State"},{"id":"1567990072","predicate":"updates.differenceEmpty","params":[{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"updates.Difference"},{"id":"16030880","predicate":"updates.difference","params":[{"name":"new_messages","type":"Vector"},{"name":"new_encrypted_messages","type":"Vector"},{"name":"other_updates","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"state","type":"updates.State"}],"type":"updates.Difference"},{"id":"-1459938943","predicate":"updates.differenceSlice","params":[{"name":"new_messages","type":"Vector"},{"name":"new_encrypted_messages","type":"Vector"},{"name":"other_updates","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"intermediate_state","type":"updates.State"}],"type":"updates.Difference"},{"id":"-484987010","predicate":"updatesTooLong","params":[],"type":"Updates"},{"id":"-1857044719","predicate":"updateShortMessage","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"id","type":"int"},{"name":"user_id","type":"int"},{"name":"message","type":"string"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"date","type":"int"},{"name":"fwd_from","type":"flags.2?MessageFwdHeader"},{"name":"via_bot_id","type":"flags.11?int"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"entities","type":"flags.7?Vector"}],"type":"Updates"},{"id":"377562760","predicate":"updateShortChatMessage","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"chat_id","type":"int"},{"name":"message","type":"string"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"date","type":"int"},{"name":"fwd_from","type":"flags.2?MessageFwdHeader"},{"name":"via_bot_id","type":"flags.11?int"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"entities","type":"flags.7?Vector"}],"type":"Updates"},{"id":"2027216577","predicate":"updateShort","params":[{"name":"update","type":"Update"},{"name":"date","type":"int"}],"type":"Updates"},{"id":"1918567619","predicate":"updatesCombined","params":[{"name":"updates","type":"Vector"},{"name":"users","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"date","type":"int"},{"name":"seq_start","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"1957577280","predicate":"updates","params":[{"name":"updates","type":"Vector"},{"name":"users","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"-1916114267","predicate":"photos.photos","params":[{"name":"photos","type":"Vector"},{"name":"users","type":"Vector"}],"type":"photos.Photos"},{"id":"352657236","predicate":"photos.photosSlice","params":[{"name":"count","type":"int"},{"name":"photos","type":"Vector"},{"name":"users","type":"Vector"}],"type":"photos.Photos"},{"id":"539045032","predicate":"photos.photo","params":[{"name":"photo","type":"Photo"},{"name":"users","type":"Vector"}],"type":"photos.Photo"},{"id":"157948117","predicate":"upload.file","params":[{"name":"type","type":"storage.FileType"},{"name":"mtime","type":"int"},{"name":"bytes","type":"bytes"}],"type":"upload.File"},{"id":"98092748","predicate":"dcOption","params":[{"name":"flags","type":"#"},{"name":"ipv6","type":"flags.0?true"},{"name":"media_only","type":"flags.1?true"},{"name":"tcpo_only","type":"flags.2?true"},{"name":"id","type":"int"},{"name":"ip_address","type":"string"},{"name":"port","type":"int"}],"type":"DcOption"},{"id":"-1704251862","predicate":"config","params":[{"name":"flags","type":"#"},{"name":"date","type":"int"},{"name":"expires","type":"int"},{"name":"test_mode","type":"Bool"},{"name":"this_dc","type":"int"},{"name":"dc_options","type":"Vector"},{"name":"chat_size_max","type":"int"},{"name":"megagroup_size_max","type":"int"},{"name":"forwarded_count_max","type":"int"},{"name":"online_update_period_ms","type":"int"},{"name":"offline_blur_timeout_ms","type":"int"},{"name":"offline_idle_timeout_ms","type":"int"},{"name":"online_cloud_timeout_ms","type":"int"},{"name":"notify_cloud_delay_ms","type":"int"},{"name":"notify_default_delay_ms","type":"int"},{"name":"chat_big_size","type":"int"},{"name":"push_chat_period_ms","type":"int"},{"name":"push_chat_limit","type":"int"},{"name":"saved_gifs_limit","type":"int"},{"name":"edit_time_limit","type":"int"},{"name":"rating_e_decay","type":"int"},{"name":"stickers_recent_limit","type":"int"},{"name":"tmp_sessions","type":"flags.0?int"},{"name":"disabled_features","type":"Vector"}],"type":"Config"},{"id":"-1910892683","predicate":"nearestDc","params":[{"name":"country","type":"string"},{"name":"this_dc","type":"int"},{"name":"nearest_dc","type":"int"}],"type":"NearestDc"},{"id":"-1987579119","predicate":"help.appUpdate","params":[{"name":"id","type":"int"},{"name":"critical","type":"Bool"},{"name":"url","type":"string"},{"name":"text","type":"string"}],"type":"help.AppUpdate"},{"id":"-1000708810","predicate":"help.noAppUpdate","params":[],"type":"help.AppUpdate"},{"id":"415997816","predicate":"help.inviteText","params":[{"name":"message","type":"string"}],"type":"help.InviteText"},{"id":"1662091044","predicate":"wallPaperSolid","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"bg_color","type":"int"},{"name":"color","type":"int"}],"type":"WallPaper"},{"id":"314359194","predicate":"updateNewEncryptedMessage","params":[{"name":"message","type":"EncryptedMessage"},{"name":"qts","type":"int"}],"type":"Update"},{"id":"386986326","predicate":"updateEncryptedChatTyping","params":[{"name":"chat_id","type":"int"}],"type":"Update"},{"id":"-1264392051","predicate":"updateEncryption","params":[{"name":"chat","type":"EncryptedChat"},{"name":"date","type":"int"}],"type":"Update"},{"id":"956179895","predicate":"updateEncryptedMessagesRead","params":[{"name":"chat_id","type":"int"},{"name":"max_date","type":"int"},{"name":"date","type":"int"}],"type":"Update"},{"id":"-1417756512","predicate":"encryptedChatEmpty","params":[{"name":"id","type":"int"}],"type":"EncryptedChat"},{"id":"1006044124","predicate":"encryptedChatWaiting","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"}],"type":"EncryptedChat"},{"id":"-931638658","predicate":"encryptedChatRequested","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"},{"name":"g_a","type":"bytes"}],"type":"EncryptedChat"},{"id":"-94974410","predicate":"encryptedChat","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"},{"name":"g_a_or_b","type":"bytes"},{"name":"key_fingerprint","type":"long"}],"type":"EncryptedChat"},{"id":"332848423","predicate":"encryptedChatDiscarded","params":[{"name":"id","type":"int"}],"type":"EncryptedChat"},{"id":"-247351839","predicate":"inputEncryptedChat","params":[{"name":"chat_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputEncryptedChat"},{"id":"-1038136962","predicate":"encryptedFileEmpty","params":[],"type":"EncryptedFile"},{"id":"1248893260","predicate":"encryptedFile","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"size","type":"int"},{"name":"dc_id","type":"int"},{"name":"key_fingerprint","type":"int"}],"type":"EncryptedFile"},{"id":"406307684","predicate":"inputEncryptedFileEmpty","params":[],"type":"InputEncryptedFile"},{"id":"1690108678","predicate":"inputEncryptedFileUploaded","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"md5_checksum","type":"string"},{"name":"key_fingerprint","type":"int"}],"type":"InputEncryptedFile"},{"id":"1511503333","predicate":"inputEncryptedFile","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputEncryptedFile"},{"id":"-182231723","predicate":"inputEncryptedFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputFileLocation"},{"id":"-317144808","predicate":"encryptedMessage","params":[{"name":"random_id","type":"long"},{"name":"chat_id","type":"int"},{"name":"date","type":"int"},{"name":"bytes","type":"bytes"},{"name":"file","type":"EncryptedFile"}],"type":"EncryptedMessage"},{"id":"594758406","predicate":"encryptedMessageService","params":[{"name":"random_id","type":"long"},{"name":"chat_id","type":"int"},{"name":"date","type":"int"},{"name":"bytes","type":"bytes"}],"type":"EncryptedMessage"},{"id":"-1058912715","predicate":"messages.dhConfigNotModified","params":[{"name":"random","type":"bytes"}],"type":"messages.DhConfig"},{"id":"740433629","predicate":"messages.dhConfig","params":[{"name":"g","type":"int"},{"name":"p","type":"bytes"},{"name":"version","type":"int"},{"name":"random","type":"bytes"}],"type":"messages.DhConfig"},{"id":"1443858741","predicate":"messages.sentEncryptedMessage","params":[{"name":"date","type":"int"}],"type":"messages.SentEncryptedMessage"},{"id":"-1802240206","predicate":"messages.sentEncryptedFile","params":[{"name":"date","type":"int"},{"name":"file","type":"EncryptedFile"}],"type":"messages.SentEncryptedMessage"},{"id":"-95482955","predicate":"inputFileBig","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"name","type":"string"}],"type":"InputFile"},{"id":"767652808","predicate":"inputEncryptedFileBigUploaded","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"key_fingerprint","type":"int"}],"type":"InputEncryptedFile"},{"id":"-364179876","predicate":"updateChatParticipantAdd","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"},{"name":"version","type":"int"}],"type":"Update"},{"id":"1851755554","predicate":"updateChatParticipantDelete","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"version","type":"int"}],"type":"Update"},{"id":"-1906403213","predicate":"updateDcOptions","params":[{"name":"dc_options","type":"Vector"}],"type":"Update"},{"id":"495530093","predicate":"inputMediaUploadedDocument","params":[{"name":"file","type":"InputFile"},{"name":"mime_type","type":"string"},{"name":"attributes","type":"Vector"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-1386138479","predicate":"inputMediaUploadedThumbDocument","params":[{"name":"file","type":"InputFile"},{"name":"thumb","type":"InputFile"},{"name":"mime_type","type":"string"},{"name":"attributes","type":"Vector"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"444068508","predicate":"inputMediaDocument","params":[{"name":"id","type":"InputDocument"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-203411800","predicate":"messageMediaDocument","params":[{"name":"document","type":"Document"},{"name":"caption","type":"string"}],"type":"MessageMedia"},{"id":"1928391342","predicate":"inputDocumentEmpty","params":[],"type":"InputDocument"},{"id":"410618194","predicate":"inputDocument","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputDocument"},{"id":"1125058340","predicate":"inputDocumentFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"version","type":"int"}],"type":"InputFileLocation"},{"id":"922273905","predicate":"documentEmpty","params":[{"name":"id","type":"long"}],"type":"Document"},{"id":"-2027738169","predicate":"document","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"mime_type","type":"string"},{"name":"size","type":"int"},{"name":"thumb","type":"PhotoSize"},{"name":"dc_id","type":"int"},{"name":"version","type":"int"},{"name":"attributes","type":"Vector"}],"type":"Document"},{"id":"398898678","predicate":"help.support","params":[{"name":"phone_number","type":"string"},{"name":"user","type":"User"}],"type":"help.Support"},{"id":"-1613493288","predicate":"notifyPeer","params":[{"name":"peer","type":"Peer"}],"type":"NotifyPeer"},{"id":"-1261946036","predicate":"notifyUsers","params":[],"type":"NotifyPeer"},{"id":"-1073230141","predicate":"notifyChats","params":[],"type":"NotifyPeer"},{"id":"1959820384","predicate":"notifyAll","params":[],"type":"NotifyPeer"},{"id":"-2131957734","predicate":"updateUserBlocked","params":[{"name":"user_id","type":"int"},{"name":"blocked","type":"Bool"}],"type":"Update"},{"id":"-1094555409","predicate":"updateNotifySettings","params":[{"name":"peer","type":"NotifyPeer"},{"name":"notify_settings","type":"PeerNotifySettings"}],"type":"Update"},{"id":"381645902","predicate":"sendMessageTypingAction","params":[],"type":"SendMessageAction"},{"id":"-44119819","predicate":"sendMessageCancelAction","params":[],"type":"SendMessageAction"},{"id":"-1584933265","predicate":"sendMessageRecordVideoAction","params":[],"type":"SendMessageAction"},{"id":"-378127636","predicate":"sendMessageUploadVideoAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"-718310409","predicate":"sendMessageRecordAudioAction","params":[],"type":"SendMessageAction"},{"id":"-212740181","predicate":"sendMessageUploadAudioAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"-774682074","predicate":"sendMessageUploadPhotoAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"-1441998364","predicate":"sendMessageUploadDocumentAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"393186209","predicate":"sendMessageGeoLocationAction","params":[],"type":"SendMessageAction"},{"id":"1653390447","predicate":"sendMessageChooseContactAction","params":[],"type":"SendMessageAction"},{"id":"446822276","predicate":"contacts.found","params":[{"name":"results","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.Found"},{"id":"942527460","predicate":"updateServiceNotification","params":[{"name":"type","type":"string"},{"name":"message","type":"string"},{"name":"media","type":"MessageMedia"},{"name":"popup","type":"Bool"}],"type":"Update"},{"id":"-496024847","predicate":"userStatusRecently","params":[],"type":"UserStatus"},{"id":"129960444","predicate":"userStatusLastWeek","params":[],"type":"UserStatus"},{"id":"2011940674","predicate":"userStatusLastMonth","params":[],"type":"UserStatus"},{"id":"-298113238","predicate":"updatePrivacy","params":[{"name":"key","type":"PrivacyKey"},{"name":"rules","type":"Vector"}],"type":"Update"},{"id":"1335282456","predicate":"inputPrivacyKeyStatusTimestamp","params":[],"type":"InputPrivacyKey"},{"id":"-1137792208","predicate":"privacyKeyStatusTimestamp","params":[],"type":"PrivacyKey"},{"id":"218751099","predicate":"inputPrivacyValueAllowContacts","params":[],"type":"InputPrivacyRule"},{"id":"407582158","predicate":"inputPrivacyValueAllowAll","params":[],"type":"InputPrivacyRule"},{"id":"320652927","predicate":"inputPrivacyValueAllowUsers","params":[{"name":"users","type":"Vector"}],"type":"InputPrivacyRule"},{"id":"195371015","predicate":"inputPrivacyValueDisallowContacts","params":[],"type":"InputPrivacyRule"},{"id":"-697604407","predicate":"inputPrivacyValueDisallowAll","params":[],"type":"InputPrivacyRule"},{"id":"-1877932953","predicate":"inputPrivacyValueDisallowUsers","params":[{"name":"users","type":"Vector"}],"type":"InputPrivacyRule"},{"id":"-123988","predicate":"privacyValueAllowContacts","params":[],"type":"PrivacyRule"},{"id":"1698855810","predicate":"privacyValueAllowAll","params":[],"type":"PrivacyRule"},{"id":"1297858060","predicate":"privacyValueAllowUsers","params":[{"name":"users","type":"Vector"}],"type":"PrivacyRule"},{"id":"-125240806","predicate":"privacyValueDisallowContacts","params":[],"type":"PrivacyRule"},{"id":"-1955338397","predicate":"privacyValueDisallowAll","params":[],"type":"PrivacyRule"},{"id":"209668535","predicate":"privacyValueDisallowUsers","params":[{"name":"users","type":"Vector"}],"type":"PrivacyRule"},{"id":"1430961007","predicate":"account.privacyRules","params":[{"name":"rules","type":"Vector"},{"name":"users","type":"Vector"}],"type":"account.PrivacyRules"},{"id":"-1194283041","predicate":"accountDaysTTL","params":[{"name":"days","type":"int"}],"type":"AccountDaysTTL"},{"id":"314130811","predicate":"updateUserPhone","params":[{"name":"user_id","type":"int"},{"name":"phone","type":"string"}],"type":"Update"},{"id":"1815593308","predicate":"documentAttributeImageSize","params":[{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"DocumentAttribute"},{"id":"297109817","predicate":"documentAttributeAnimated","params":[],"type":"DocumentAttribute"},{"id":"978674434","predicate":"documentAttributeSticker","params":[{"name":"alt","type":"string"},{"name":"stickerset","type":"InputStickerSet"}],"type":"DocumentAttribute"},{"id":"1494273227","predicate":"documentAttributeVideo","params":[{"name":"duration","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"DocumentAttribute"},{"id":"-1739392570","predicate":"documentAttributeAudio","params":[{"name":"flags","type":"#"},{"name":"voice","type":"flags.10?true"},{"name":"duration","type":"int"},{"name":"title","type":"flags.0?string"},{"name":"performer","type":"flags.1?string"},{"name":"waveform","type":"flags.2?bytes"}],"type":"DocumentAttribute"},{"id":"358154344","predicate":"documentAttributeFilename","params":[{"name":"file_name","type":"string"}],"type":"DocumentAttribute"},{"id":"-244016606","predicate":"messages.stickersNotModified","params":[],"type":"messages.Stickers"},{"id":"-1970352846","predicate":"messages.stickers","params":[{"name":"hash","type":"string"},{"name":"stickers","type":"Vector"}],"type":"messages.Stickers"},{"id":"313694676","predicate":"stickerPack","params":[{"name":"emoticon","type":"string"},{"name":"documents","type":"Vector"}],"type":"StickerPack"},{"id":"-395967805","predicate":"messages.allStickersNotModified","params":[],"type":"messages.AllStickers"},{"id":"-302170017","predicate":"messages.allStickers","params":[{"name":"hash","type":"int"},{"name":"sets","type":"Vector"}],"type":"messages.AllStickers"},{"id":"-1369215196","predicate":"disabledFeature","params":[{"name":"feature","type":"string"},{"name":"description","type":"string"}],"type":"DisabledFeature"},{"id":"-1721631396","predicate":"updateReadHistoryInbox","params":[{"name":"peer","type":"Peer"},{"name":"max_id","type":"int"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"791617983","predicate":"updateReadHistoryOutbox","params":[{"name":"peer","type":"Peer"},{"name":"max_id","type":"int"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-2066640507","predicate":"messages.affectedMessages","params":[{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"messages.AffectedMessages"},{"id":"1599050311","predicate":"contactLinkUnknown","params":[],"type":"ContactLink"},{"id":"-17968211","predicate":"contactLinkNone","params":[],"type":"ContactLink"},{"id":"646922073","predicate":"contactLinkHasPhone","params":[],"type":"ContactLink"},{"id":"-721239344","predicate":"contactLinkContact","params":[],"type":"ContactLink"},{"id":"2139689491","predicate":"updateWebPage","params":[{"name":"webpage","type":"WebPage"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-350980120","predicate":"webPageEmpty","params":[{"name":"id","type":"long"}],"type":"WebPage"},{"id":"-981018084","predicate":"webPagePending","params":[{"name":"id","type":"long"},{"name":"date","type":"int"}],"type":"WebPage"},{"id":"-897446185","predicate":"webPage","params":[{"name":"flags","type":"#"},{"name":"id","type":"long"},{"name":"url","type":"string"},{"name":"display_url","type":"string"},{"name":"type","type":"flags.0?string"},{"name":"site_name","type":"flags.1?string"},{"name":"title","type":"flags.2?string"},{"name":"description","type":"flags.3?string"},{"name":"photo","type":"flags.4?Photo"},{"name":"embed_url","type":"flags.5?string"},{"name":"embed_type","type":"flags.5?string"},{"name":"embed_width","type":"flags.6?int"},{"name":"embed_height","type":"flags.6?int"},{"name":"duration","type":"flags.7?int"},{"name":"author","type":"flags.8?string"},{"name":"document","type":"flags.9?Document"}],"type":"WebPage"},{"id":"-1557277184","predicate":"messageMediaWebPage","params":[{"name":"webpage","type":"WebPage"}],"type":"MessageMedia"},{"id":"2079516406","predicate":"authorization","params":[{"name":"hash","type":"long"},{"name":"flags","type":"int"},{"name":"device_model","type":"string"},{"name":"platform","type":"string"},{"name":"system_version","type":"string"},{"name":"api_id","type":"int"},{"name":"app_name","type":"string"},{"name":"app_version","type":"string"},{"name":"date_created","type":"int"},{"name":"date_active","type":"int"},{"name":"ip","type":"string"},{"name":"country","type":"string"},{"name":"region","type":"string"}],"type":"Authorization"},{"id":"307276766","predicate":"account.authorizations","params":[{"name":"authorizations","type":"Vector"}],"type":"account.Authorizations"},{"id":"-1764049896","predicate":"account.noPassword","params":[{"name":"new_salt","type":"bytes"},{"name":"email_unconfirmed_pattern","type":"string"}],"type":"account.Password"},{"id":"2081952796","predicate":"account.password","params":[{"name":"current_salt","type":"bytes"},{"name":"new_salt","type":"bytes"},{"name":"hint","type":"string"},{"name":"has_recovery","type":"Bool"},{"name":"email_unconfirmed_pattern","type":"string"}],"type":"account.Password"},{"id":"-1212732749","predicate":"account.passwordSettings","params":[{"name":"email","type":"string"}],"type":"account.PasswordSettings"},{"id":"-2037289493","predicate":"account.passwordInputSettings","params":[{"name":"flags","type":"#"},{"name":"new_salt","type":"flags.0?bytes"},{"name":"new_password_hash","type":"flags.0?bytes"},{"name":"hint","type":"flags.0?string"},{"name":"email","type":"flags.1?string"}],"type":"account.PasswordInputSettings"},{"id":"326715557","predicate":"auth.passwordRecovery","params":[{"name":"email_pattern","type":"string"}],"type":"auth.PasswordRecovery"},{"id":"673687578","predicate":"inputMediaVenue","params":[{"name":"geo_point","type":"InputGeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"}],"type":"InputMedia"},{"id":"2031269663","predicate":"messageMediaVenue","params":[{"name":"geo","type":"GeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"}],"type":"MessageMedia"},{"id":"-1551583367","predicate":"receivedNotifyMessage","params":[{"name":"id","type":"int"},{"name":"flags","type":"int"}],"type":"ReceivedNotifyMessage"},{"id":"1776236393","predicate":"chatInviteEmpty","params":[],"type":"ExportedChatInvite"},{"id":"-64092740","predicate":"chatInviteExported","params":[{"name":"link","type":"string"}],"type":"ExportedChatInvite"},{"id":"1516793212","predicate":"chatInviteAlready","params":[{"name":"chat","type":"Chat"}],"type":"ChatInvite"},{"id":"-613092008","predicate":"chatInvite","params":[{"name":"flags","type":"#"},{"name":"channel","type":"flags.0?true"},{"name":"broadcast","type":"flags.1?true"},{"name":"public","type":"flags.2?true"},{"name":"megagroup","type":"flags.3?true"},{"name":"title","type":"string"},{"name":"photo","type":"ChatPhoto"},{"name":"participants_count","type":"int"},{"name":"participants","type":"flags.4?Vector"}],"type":"ChatInvite"},{"id":"-123931160","predicate":"messageActionChatJoinedByLink","params":[{"name":"inviter_id","type":"int"}],"type":"MessageAction"},{"id":"1757493555","predicate":"updateReadMessagesContents","params":[{"name":"messages","type":"Vector"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-4838507","predicate":"inputStickerSetEmpty","params":[],"type":"InputStickerSet"},{"id":"-1645763991","predicate":"inputStickerSetID","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputStickerSet"},{"id":"-2044933984","predicate":"inputStickerSetShortName","params":[{"name":"short_name","type":"string"}],"type":"InputStickerSet"},{"id":"-852477119","predicate":"stickerSet","params":[{"name":"flags","type":"#"},{"name":"installed","type":"flags.0?true"},{"name":"archived","type":"flags.1?true"},{"name":"official","type":"flags.2?true"},{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"title","type":"string"},{"name":"short_name","type":"string"},{"name":"count","type":"int"},{"name":"hash","type":"int"}],"type":"StickerSet"},{"id":"-1240849242","predicate":"messages.stickerSet","params":[{"name":"set","type":"StickerSet"},{"name":"packs","type":"Vector"},{"name":"documents","type":"Vector"}],"type":"messages.StickerSet"},{"id":"-787638374","predicate":"user","params":[{"name":"flags","type":"#"},{"name":"self","type":"flags.10?true"},{"name":"contact","type":"flags.11?true"},{"name":"mutual_contact","type":"flags.12?true"},{"name":"deleted","type":"flags.13?true"},{"name":"bot","type":"flags.14?true"},{"name":"bot_chat_history","type":"flags.15?true"},{"name":"bot_nochats","type":"flags.16?true"},{"name":"verified","type":"flags.17?true"},{"name":"restricted","type":"flags.18?true"},{"name":"min","type":"flags.20?true"},{"name":"bot_inline_geo","type":"flags.21?true"},{"name":"id","type":"int"},{"name":"access_hash","type":"flags.0?long"},{"name":"first_name","type":"flags.1?string"},{"name":"last_name","type":"flags.2?string"},{"name":"username","type":"flags.3?string"},{"name":"phone","type":"flags.4?string"},{"name":"photo","type":"flags.5?UserProfilePhoto"},{"name":"status","type":"flags.6?UserStatus"},{"name":"bot_info_version","type":"flags.14?int"},{"name":"restriction_reason","type":"flags.18?string"},{"name":"bot_inline_placeholder","type":"flags.19?string"}],"type":"User"},{"id":"-1032140601","predicate":"botCommand","params":[{"name":"command","type":"string"},{"name":"description","type":"string"}],"type":"BotCommand"},{"id":"-1729618630","predicate":"botInfo","params":[{"name":"user_id","type":"int"},{"name":"description","type":"string"},{"name":"commands","type":"Vector"}],"type":"BotInfo"},{"id":"-1560655744","predicate":"keyboardButton","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"2002815875","predicate":"keyboardButtonRow","params":[{"name":"buttons","type":"Vector"}],"type":"KeyboardButtonRow"},{"id":"-1606526075","predicate":"replyKeyboardHide","params":[{"name":"flags","type":"#"},{"name":"selective","type":"flags.2?true"}],"type":"ReplyMarkup"},{"id":"-200242528","predicate":"replyKeyboardForceReply","params":[{"name":"flags","type":"#"},{"name":"single_use","type":"flags.1?true"},{"name":"selective","type":"flags.2?true"}],"type":"ReplyMarkup"},{"id":"889353612","predicate":"replyKeyboardMarkup","params":[{"name":"flags","type":"#"},{"name":"resize","type":"flags.0?true"},{"name":"single_use","type":"flags.1?true"},{"name":"selective","type":"flags.2?true"},{"name":"rows","type":"Vector"}],"type":"ReplyMarkup"},{"id":"2072935910","predicate":"inputPeerUser","params":[{"name":"user_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputPeer"},{"id":"-668391402","predicate":"inputUser","params":[{"name":"user_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputUser"},{"id":"-1350696044","predicate":"help.appChangelogEmpty","params":[],"type":"help.AppChangelog"},{"id":"1181279933","predicate":"help.appChangelog","params":[{"name":"text","type":"string"}],"type":"help.AppChangelog"},{"id":"-1148011883","predicate":"messageEntityUnknown","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"-100378723","predicate":"messageEntityMention","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1868782349","predicate":"messageEntityHashtag","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1827637959","predicate":"messageEntityBotCommand","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1859134776","predicate":"messageEntityUrl","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1692693954","predicate":"messageEntityEmail","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"-1117713463","predicate":"messageEntityBold","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"-2106619040","predicate":"messageEntityItalic","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"681706865","predicate":"messageEntityCode","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1938967520","predicate":"messageEntityPre","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"language","type":"string"}],"type":"MessageEntity"},{"id":"1990644519","predicate":"messageEntityTextUrl","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"url","type":"string"}],"type":"MessageEntity"},{"id":"301019932","predicate":"updateShortSentMessage","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"id","type":"int"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"date","type":"int"},{"name":"media","type":"flags.9?MessageMedia"},{"name":"entities","type":"flags.7?Vector"}],"type":"Updates"},{"id":"-292807034","predicate":"inputChannelEmpty","params":[],"type":"InputChannel"},{"id":"-1343524562","predicate":"inputChannel","params":[{"name":"channel_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputChannel"},{"id":"-1109531342","predicate":"peerChannel","params":[{"name":"channel_id","type":"int"}],"type":"Peer"},{"id":"548253432","predicate":"inputPeerChannel","params":[{"name":"channel_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputPeer"},{"id":"-1588737454","predicate":"channel","params":[{"name":"flags","type":"#"},{"name":"creator","type":"flags.0?true"},{"name":"kicked","type":"flags.1?true"},{"name":"left","type":"flags.2?true"},{"name":"editor","type":"flags.3?true"},{"name":"moderator","type":"flags.4?true"},{"name":"broadcast","type":"flags.5?true"},{"name":"verified","type":"flags.7?true"},{"name":"megagroup","type":"flags.8?true"},{"name":"restricted","type":"flags.9?true"},{"name":"democracy","type":"flags.10?true"},{"name":"signatures","type":"flags.11?true"},{"name":"min","type":"flags.12?true"},{"name":"id","type":"int"},{"name":"access_hash","type":"flags.13?long"},{"name":"title","type":"string"},{"name":"username","type":"flags.6?string"},{"name":"photo","type":"ChatPhoto"},{"name":"date","type":"int"},{"name":"version","type":"int"},{"name":"restriction_reason","type":"flags.9?string"}],"type":"Chat"},{"id":"-2059962289","predicate":"channelForbidden","params":[{"name":"flags","type":"#"},{"name":"broadcast","type":"flags.5?true"},{"name":"megagroup","type":"flags.8?true"},{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"title","type":"string"}],"type":"Chat"},{"id":"2131196633","predicate":"contacts.resolvedPeer","params":[{"name":"peer","type":"Peer"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.ResolvedPeer"},{"id":"-1009430225","predicate":"channelFull","params":[{"name":"flags","type":"#"},{"name":"can_view_participants","type":"flags.3?true"},{"name":"can_set_username","type":"flags.6?true"},{"name":"id","type":"int"},{"name":"about","type":"string"},{"name":"participants_count","type":"flags.0?int"},{"name":"admins_count","type":"flags.1?int"},{"name":"kicked_count","type":"flags.2?int"},{"name":"read_inbox_max_id","type":"int"},{"name":"read_outbox_max_id","type":"int"},{"name":"unread_count","type":"int"},{"name":"chat_photo","type":"Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"exported_invite","type":"ExportedChatInvite"},{"name":"bot_info","type":"Vector"},{"name":"migrated_from_chat_id","type":"flags.4?int"},{"name":"migrated_from_max_id","type":"flags.4?int"},{"name":"pinned_msg_id","type":"flags.5?int"}],"type":"ChatFull"},{"id":"182649427","predicate":"messageRange","params":[{"name":"min_id","type":"int"},{"name":"max_id","type":"int"}],"type":"MessageRange"},{"id":"-1725551049","predicate":"messages.channelMessages","params":[{"name":"flags","type":"#"},{"name":"pts","type":"int"},{"name":"count","type":"int"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"messages.Messages"},{"id":"-1781355374","predicate":"messageActionChannelCreate","params":[{"name":"title","type":"string"}],"type":"MessageAction"},{"id":"-352032773","predicate":"updateChannelTooLong","params":[{"name":"flags","type":"#"},{"name":"channel_id","type":"int"},{"name":"pts","type":"flags.0?int"}],"type":"Update"},{"id":"-1227598250","predicate":"updateChannel","params":[{"name":"channel_id","type":"int"}],"type":"Update"},{"id":"1656358105","predicate":"updateNewChannelMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"1108669311","predicate":"updateReadChannelInbox","params":[{"name":"channel_id","type":"int"},{"name":"max_id","type":"int"}],"type":"Update"},{"id":"-1015733815","predicate":"updateDeleteChannelMessages","params":[{"name":"channel_id","type":"int"},{"name":"messages","type":"Vector"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-1734268085","predicate":"updateChannelMessageViews","params":[{"name":"channel_id","type":"int"},{"name":"id","type":"int"},{"name":"views","type":"int"}],"type":"Update"},{"id":"1041346555","predicate":"updates.channelDifferenceEmpty","params":[{"name":"flags","type":"#"},{"name":"final","type":"flags.0?true"},{"name":"pts","type":"int"},{"name":"timeout","type":"flags.1?int"}],"type":"updates.ChannelDifference"},{"id":"1091431943","predicate":"updates.channelDifferenceTooLong","params":[{"name":"flags","type":"#"},{"name":"final","type":"flags.0?true"},{"name":"pts","type":"int"},{"name":"timeout","type":"flags.1?int"},{"name":"top_message","type":"int"},{"name":"read_inbox_max_id","type":"int"},{"name":"read_outbox_max_id","type":"int"},{"name":"unread_count","type":"int"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"updates.ChannelDifference"},{"id":"543450958","predicate":"updates.channelDifference","params":[{"name":"flags","type":"#"},{"name":"final","type":"flags.0?true"},{"name":"pts","type":"int"},{"name":"timeout","type":"flags.1?int"},{"name":"new_messages","type":"Vector"},{"name":"other_updates","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"updates.ChannelDifference"},{"id":"-1798033689","predicate":"channelMessagesFilterEmpty","params":[],"type":"ChannelMessagesFilter"},{"id":"-847783593","predicate":"channelMessagesFilter","params":[{"name":"flags","type":"#"},{"name":"exclude_new_messages","type":"flags.1?true"},{"name":"ranges","type":"Vector"}],"type":"ChannelMessagesFilter"},{"id":"367766557","predicate":"channelParticipant","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1557620115","predicate":"channelParticipantSelf","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1861910545","predicate":"channelParticipantModerator","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1743180447","predicate":"channelParticipantEditor","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1933187430","predicate":"channelParticipantKicked","params":[{"name":"user_id","type":"int"},{"name":"kicked_by","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-471670279","predicate":"channelParticipantCreator","params":[{"name":"user_id","type":"int"}],"type":"ChannelParticipant"},{"id":"-566281095","predicate":"channelParticipantsRecent","params":[],"type":"ChannelParticipantsFilter"},{"id":"-1268741783","predicate":"channelParticipantsAdmins","params":[],"type":"ChannelParticipantsFilter"},{"id":"1010285434","predicate":"channelParticipantsKicked","params":[],"type":"ChannelParticipantsFilter"},{"id":"-1299865402","predicate":"channelRoleEmpty","params":[],"type":"ChannelParticipantRole"},{"id":"-1776756363","predicate":"channelRoleModerator","params":[],"type":"ChannelParticipantRole"},{"id":"-2113143156","predicate":"channelRoleEditor","params":[],"type":"ChannelParticipantRole"},{"id":"-177282392","predicate":"channels.channelParticipants","params":[{"name":"count","type":"int"},{"name":"participants","type":"Vector"},{"name":"users","type":"Vector"}],"type":"channels.ChannelParticipants"},{"id":"-791039645","predicate":"channels.channelParticipant","params":[{"name":"participant","type":"ChannelParticipant"},{"name":"users","type":"Vector"}],"type":"channels.ChannelParticipant"},{"id":"-636267638","predicate":"chatParticipantCreator","params":[{"name":"user_id","type":"int"}],"type":"ChatParticipant"},{"id":"-489233354","predicate":"chatParticipantAdmin","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChatParticipant"},{"id":"1855224129","predicate":"updateChatAdmins","params":[{"name":"chat_id","type":"int"},{"name":"enabled","type":"Bool"},{"name":"version","type":"int"}],"type":"Update"},{"id":"-1232070311","predicate":"updateChatParticipantAdmin","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"is_admin","type":"Bool"},{"name":"version","type":"int"}],"type":"Update"},{"id":"1371385889","predicate":"messageActionChatMigrateTo","params":[{"name":"channel_id","type":"int"}],"type":"MessageAction"},{"id":"-1336546578","predicate":"messageActionChannelMigrateFrom","params":[{"name":"title","type":"string"},{"name":"chat_id","type":"int"}],"type":"MessageAction"},{"id":"-1328445861","predicate":"channelParticipantsBots","params":[],"type":"ChannelParticipantsFilter"},{"id":"-236044656","predicate":"help.termsOfService","params":[{"name":"text","type":"string"}],"type":"help.TermsOfService"},{"id":"1753886890","predicate":"updateNewStickerSet","params":[{"name":"stickerset","type":"messages.StickerSet"}],"type":"Update"},{"id":"-253774767","predicate":"updateStickerSetsOrder","params":[{"name":"order","type":"Vector"}],"type":"Update"},{"id":"1135492588","predicate":"updateStickerSets","params":[],"type":"Update"},{"id":"372165663","predicate":"foundGif","params":[{"name":"url","type":"string"},{"name":"thumb_url","type":"string"},{"name":"content_url","type":"string"},{"name":"content_type","type":"string"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"FoundGif"},{"id":"-1670052855","predicate":"foundGifCached","params":[{"name":"url","type":"string"},{"name":"photo","type":"Photo"},{"name":"document","type":"Document"}],"type":"FoundGif"},{"id":"1212395773","predicate":"inputMediaGifExternal","params":[{"name":"url","type":"string"},{"name":"q","type":"string"}],"type":"InputMedia"},{"id":"1158290442","predicate":"messages.foundGifs","params":[{"name":"next_offset","type":"int"},{"name":"results","type":"Vector"}],"type":"messages.FoundGifs"},{"id":"-402498398","predicate":"messages.savedGifsNotModified","params":[],"type":"messages.SavedGifs"},{"id":"772213157","predicate":"messages.savedGifs","params":[{"name":"hash","type":"int"},{"name":"gifs","type":"Vector"}],"type":"messages.SavedGifs"},{"id":"-1821035490","predicate":"updateSavedGifs","params":[],"type":"Update"},{"id":"691006739","predicate":"inputBotInlineMessageMediaAuto","params":[{"name":"flags","type":"#"},{"name":"caption","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"1036876423","predicate":"inputBotInlineMessageText","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.0?true"},{"name":"message","type":"string"},{"name":"entities","type":"flags.1?Vector"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"750510426","predicate":"inputBotInlineResult","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"title","type":"flags.1?string"},{"name":"description","type":"flags.2?string"},{"name":"url","type":"flags.3?string"},{"name":"thumb_url","type":"flags.4?string"},{"name":"content_url","type":"flags.5?string"},{"name":"content_type","type":"flags.5?string"},{"name":"w","type":"flags.6?int"},{"name":"h","type":"flags.6?int"},{"name":"duration","type":"flags.7?int"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"175419739","predicate":"botInlineMessageMediaAuto","params":[{"name":"flags","type":"#"},{"name":"caption","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"-1937807902","predicate":"botInlineMessageText","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.0?true"},{"name":"message","type":"string"},{"name":"entities","type":"flags.1?Vector"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"-1679053127","predicate":"botInlineResult","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"title","type":"flags.1?string"},{"name":"description","type":"flags.2?string"},{"name":"url","type":"flags.3?string"},{"name":"thumb_url","type":"flags.4?string"},{"name":"content_url","type":"flags.5?string"},{"name":"content_type","type":"flags.5?string"},{"name":"w","type":"flags.6?int"},{"name":"h","type":"flags.6?int"},{"name":"duration","type":"flags.7?int"},{"name":"send_message","type":"BotInlineMessage"}],"type":"BotInlineResult"},{"id":"627509670","predicate":"messages.botResults","params":[{"name":"flags","type":"#"},{"name":"gallery","type":"flags.0?true"},{"name":"query_id","type":"long"},{"name":"next_offset","type":"flags.1?string"},{"name":"switch_pm","type":"flags.2?InlineBotSwitchPM"},{"name":"results","type":"Vector"}],"type":"messages.BotResults"},{"id":"1417832080","predicate":"updateBotInlineQuery","params":[{"name":"flags","type":"#"},{"name":"query_id","type":"long"},{"name":"user_id","type":"int"},{"name":"query","type":"string"},{"name":"geo","type":"flags.0?GeoPoint"},{"name":"offset","type":"string"}],"type":"Update"},{"id":"239663460","predicate":"updateBotInlineSend","params":[{"name":"flags","type":"#"},{"name":"user_id","type":"int"},{"name":"query","type":"string"},{"name":"geo","type":"flags.0?GeoPoint"},{"name":"id","type":"string"},{"name":"msg_id","type":"flags.1?InputBotInlineMessageID"}],"type":"Update"},{"id":"1358283666","predicate":"inputMessagesFilterVoice","params":[],"type":"MessagesFilter"},{"id":"928101534","predicate":"inputMessagesFilterMusic","params":[],"type":"MessagesFilter"},{"id":"-1107622874","predicate":"inputPrivacyKeyChatInvite","params":[],"type":"InputPrivacyKey"},{"id":"1343122938","predicate":"privacyKeyChatInvite","params":[],"type":"PrivacyKey"},{"id":"524838915","predicate":"exportedMessageLink","params":[{"name":"link","type":"string"}],"type":"ExportedMessageLink"},{"id":"-947462709","predicate":"messageFwdHeader","params":[{"name":"flags","type":"#"},{"name":"from_id","type":"flags.0?int"},{"name":"date","type":"int"},{"name":"channel_id","type":"flags.1?int"},{"name":"channel_post","type":"flags.2?int"}],"type":"MessageFwdHeader"},{"id":"457133559","predicate":"updateEditChannelMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-1738988427","predicate":"updateChannelPinnedMessage","params":[{"name":"channel_id","type":"int"},{"name":"id","type":"int"}],"type":"Update"},{"id":"-1799538451","predicate":"messageActionPinMessage","params":[],"type":"MessageAction"},{"id":"1923290508","predicate":"auth.codeTypeSms","params":[],"type":"auth.CodeType"},{"id":"1948046307","predicate":"auth.codeTypeCall","params":[],"type":"auth.CodeType"},{"id":"577556219","predicate":"auth.codeTypeFlashCall","params":[],"type":"auth.CodeType"},{"id":"1035688326","predicate":"auth.sentCodeTypeApp","params":[{"name":"length","type":"int"}],"type":"auth.SentCodeType"},{"id":"-1073693790","predicate":"auth.sentCodeTypeSms","params":[{"name":"length","type":"int"}],"type":"auth.SentCodeType"},{"id":"1398007207","predicate":"auth.sentCodeTypeCall","params":[{"name":"length","type":"int"}],"type":"auth.SentCodeType"},{"id":"-1425815847","predicate":"auth.sentCodeTypeFlashCall","params":[{"name":"pattern","type":"string"}],"type":"auth.SentCodeType"},{"id":"629866245","predicate":"keyboardButtonUrl","params":[{"name":"text","type":"string"},{"name":"url","type":"string"}],"type":"KeyboardButton"},{"id":"1748655686","predicate":"keyboardButtonCallback","params":[{"name":"text","type":"string"},{"name":"data","type":"bytes"}],"type":"KeyboardButton"},{"id":"-1318425559","predicate":"keyboardButtonRequestPhone","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"-59151553","predicate":"keyboardButtonRequestGeoLocation","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"-367298028","predicate":"keyboardButtonSwitchInline","params":[{"name":"text","type":"string"},{"name":"query","type":"string"}],"type":"KeyboardButton"},{"id":"1218642516","predicate":"replyInlineMarkup","params":[{"name":"rows","type":"Vector"}],"type":"ReplyMarkup"},{"id":"-1324486149","predicate":"messages.botCallbackAnswer","params":[{"name":"flags","type":"#"},{"name":"alert","type":"flags.1?true"},{"name":"message","type":"flags.0?string"},{"name":"url","type":"flags.2?string"}],"type":"messages.BotCallbackAnswer"},{"id":"-1500747636","predicate":"updateBotCallbackQuery","params":[{"name":"query_id","type":"long"},{"name":"user_id","type":"int"},{"name":"peer","type":"Peer"},{"name":"msg_id","type":"int"},{"name":"data","type":"bytes"}],"type":"Update"},{"id":"649453030","predicate":"messages.messageEditData","params":[{"name":"flags","type":"#"},{"name":"caption","type":"flags.0?true"}],"type":"messages.MessageEditData"},{"id":"-469536605","predicate":"updateEditMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-190472735","predicate":"inputBotInlineMessageMediaGeo","params":[{"name":"flags","type":"#"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"-1431327288","predicate":"inputBotInlineMessageMediaVenue","params":[{"name":"flags","type":"#"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"766443943","predicate":"inputBotInlineMessageMediaContact","params":[{"name":"flags","type":"#"},{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"982505656","predicate":"botInlineMessageMediaGeo","params":[{"name":"flags","type":"#"},{"name":"geo","type":"GeoPoint"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"1130767150","predicate":"botInlineMessageMediaVenue","params":[{"name":"flags","type":"#"},{"name":"geo","type":"GeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"904770772","predicate":"botInlineMessageMediaContact","params":[{"name":"flags","type":"#"},{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"-1462213465","predicate":"inputBotInlineResultPhoto","params":[{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"photo","type":"InputPhoto"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"-459324","predicate":"inputBotInlineResultDocument","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"title","type":"flags.1?string"},{"name":"description","type":"flags.2?string"},{"name":"document","type":"InputDocument"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"400266251","predicate":"botInlineMediaResult","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"photo","type":"flags.0?Photo"},{"name":"document","type":"flags.1?Document"},{"name":"title","type":"flags.2?string"},{"name":"description","type":"flags.3?string"},{"name":"send_message","type":"BotInlineMessage"}],"type":"BotInlineResult"},{"id":"-1995686519","predicate":"inputBotInlineMessageID","params":[{"name":"dc_id","type":"int"},{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputBotInlineMessageID"},{"id":"750622127","predicate":"updateInlineBotCallbackQuery","params":[{"name":"query_id","type":"long"},{"name":"user_id","type":"int"},{"name":"msg_id","type":"InputBotInlineMessageID"},{"name":"data","type":"bytes"}],"type":"Update"},{"id":"1008755359","predicate":"inlineBotSwitchPM","params":[{"name":"text","type":"string"},{"name":"start_param","type":"string"}],"type":"InlineBotSwitchPM"},{"id":"863093588","predicate":"messages.peerDialogs","params":[{"name":"dialogs","type":"Vector"},{"name":"messages","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"},{"name":"state","type":"updates.State"}],"type":"messages.PeerDialogs"},{"id":"-305282981","predicate":"topPeer","params":[{"name":"peer","type":"Peer"},{"name":"rating","type":"double"}],"type":"TopPeer"},{"id":"-1419371685","predicate":"topPeerCategoryBotsPM","params":[],"type":"TopPeerCategory"},{"id":"344356834","predicate":"topPeerCategoryBotsInline","params":[],"type":"TopPeerCategory"},{"id":"104314861","predicate":"topPeerCategoryCorrespondents","params":[],"type":"TopPeerCategory"},{"id":"-1122524854","predicate":"topPeerCategoryGroups","params":[],"type":"TopPeerCategory"},{"id":"371037736","predicate":"topPeerCategoryChannels","params":[],"type":"TopPeerCategory"},{"id":"-75283823","predicate":"topPeerCategoryPeers","params":[{"name":"category","type":"TopPeerCategory"},{"name":"count","type":"int"},{"name":"peers","type":"Vector"}],"type":"TopPeerCategoryPeers"},{"id":"-567906571","predicate":"contacts.topPeersNotModified","params":[],"type":"contacts.TopPeers"},{"id":"1891070632","predicate":"contacts.topPeers","params":[{"name":"categories","type":"Vector"},{"name":"chats","type":"Vector"},{"name":"users","type":"Vector"}],"type":"contacts.TopPeers"},{"id":"892193368","predicate":"messageEntityMentionName","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"user_id","type":"int"}],"type":"MessageEntity"},{"id":"546203849","predicate":"inputMessageEntityMentionName","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"user_id","type":"InputUser"}],"type":"MessageEntity"},{"id":"975236280","predicate":"inputMessagesFilterChatPhotos","params":[],"type":"MessagesFilter"},{"id":"634833351","predicate":"updateReadChannelOutbox","params":[{"name":"channel_id","type":"int"},{"name":"max_id","type":"int"}],"type":"Update"},{"id":"-299124375","predicate":"updateDraftMessage","params":[{"name":"peer","type":"Peer"},{"name":"draft","type":"DraftMessage"}],"type":"Update"},{"id":"-1169445179","predicate":"draftMessageEmpty","params":[],"type":"DraftMessage"},{"id":"-40996577","predicate":"draftMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"message","type":"string"},{"name":"entities","type":"flags.3?Vector"},{"name":"date","type":"int"}],"type":"DraftMessage"},{"id":"-1615153660","predicate":"messageActionHistoryClear","params":[],"type":"MessageAction"},{"id":"82699215","predicate":"messages.featuredStickersNotModified","params":[],"type":"messages.FeaturedStickers"},{"id":"-123893531","predicate":"messages.featuredStickers","params":[{"name":"hash","type":"int"},{"name":"sets","type":"Vector"},{"name":"unread","type":"Vector"}],"type":"messages.FeaturedStickers"},{"id":"1461528386","predicate":"updateReadFeaturedStickers","params":[],"type":"Update"},{"id":"186120336","predicate":"messages.recentStickersNotModified","params":[],"type":"messages.RecentStickers"},{"id":"1558317424","predicate":"messages.recentStickers","params":[{"name":"hash","type":"int"},{"name":"stickers","type":"Vector"}],"type":"messages.RecentStickers"},{"id":"-1706939360","predicate":"updateRecentStickers","params":[],"type":"Update"},{"id":"1338747336","predicate":"messages.archivedStickers","params":[{"name":"count","type":"int"},{"name":"sets","type":"Vector"}],"type":"messages.ArchivedStickers"},{"id":"946083368","predicate":"messages.stickerSetInstallResultSuccess","params":[],"type":"messages.StickerSetInstallResult"},{"id":"904138920","predicate":"messages.stickerSetInstallResultArchive","params":[{"name":"sets","type":"Vector"}],"type":"messages.StickerSetInstallResult"},{"id":"1678812626","predicate":"stickerSetCovered","params":[{"name":"set","type":"StickerSet"},{"name":"cover","type":"Document"}],"type":"StickerSetCovered"}],"methods":[{"id":"-878758099","method":"invokeAfterMsg","params":[{"name":"msg_id","type":"long"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1036301552","method":"invokeAfterMsgs","params":[{"name":"msg_ids","type":"Vector"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1877286395","method":"auth.checkPhone","params":[{"name":"phone_number","type":"string"}],"type":"auth.CheckedPhone"},{"id":"-2035355412","method":"auth.sendCode","params":[{"name":"flags","type":"#"},{"name":"allow_flashcall","type":"flags.0?true"},{"name":"phone_number","type":"string"},{"name":"current_number","type":"flags.0?Bool"},{"name":"api_id","type":"int"},{"name":"api_hash","type":"string"}],"type":"auth.SentCode"},{"id":"453408308","method":"auth.signUp","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"auth.Authorization"},{"id":"-1126886015","method":"auth.signIn","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"auth.Authorization"},{"id":"1461180992","method":"auth.logOut","params":[],"type":"Bool"},{"id":"-1616179942","method":"auth.resetAuthorizations","params":[],"type":"Bool"},{"id":"1998331287","method":"auth.sendInvites","params":[{"name":"phone_numbers","type":"Vector"},{"name":"message","type":"string"}],"type":"Bool"},{"id":"-440401971","method":"auth.exportAuthorization","params":[{"name":"dc_id","type":"int"}],"type":"auth.ExportedAuthorization"},{"id":"-470837741","method":"auth.importAuthorization","params":[{"name":"id","type":"int"},{"name":"bytes","type":"bytes"}],"type":"auth.Authorization"},{"id":"-841733627","method":"auth.bindTempAuthKey","params":[{"name":"perm_auth_key_id","type":"long"},{"name":"nonce","type":"long"},{"name":"expires_at","type":"int"},{"name":"encrypted_message","type":"bytes"}],"type":"Bool"},{"id":"1669245048","method":"account.registerDevice","params":[{"name":"token_type","type":"int"},{"name":"token","type":"string"}],"type":"Bool"},{"id":"1707432768","method":"account.unregisterDevice","params":[{"name":"token_type","type":"int"},{"name":"token","type":"string"}],"type":"Bool"},{"id":"-2067899501","method":"account.updateNotifySettings","params":[{"name":"peer","type":"InputNotifyPeer"},{"name":"settings","type":"InputPeerNotifySettings"}],"type":"Bool"},{"id":"313765169","method":"account.getNotifySettings","params":[{"name":"peer","type":"InputNotifyPeer"}],"type":"PeerNotifySettings"},{"id":"-612493497","method":"account.resetNotifySettings","params":[],"type":"Bool"},{"id":"2018596725","method":"account.updateProfile","params":[{"name":"flags","type":"#"},{"name":"first_name","type":"flags.0?string"},{"name":"last_name","type":"flags.1?string"},{"name":"about","type":"flags.2?string"}],"type":"User"},{"id":"1713919532","method":"account.updateStatus","params":[{"name":"offline","type":"Bool"}],"type":"Bool"},{"id":"-1068696894","method":"account.getWallPapers","params":[],"type":"Vector"},{"id":"-1374118561","method":"account.reportPeer","params":[{"name":"peer","type":"InputPeer"},{"name":"reason","type":"ReportReason"}],"type":"Bool"},{"id":"227648840","method":"users.getUsers","params":[{"name":"id","type":"Vector"}],"type":"Vector"},{"id":"-902781519","method":"users.getFullUser","params":[{"name":"id","type":"InputUser"}],"type":"UserFull"},{"id":"-995929106","method":"contacts.getStatuses","params":[],"type":"Vector"},{"id":"583445000","method":"contacts.getContacts","params":[{"name":"hash","type":"string"}],"type":"contacts.Contacts"},{"id":"-634342611","method":"contacts.importContacts","params":[{"name":"contacts","type":"Vector"},{"name":"replace","type":"Bool"}],"type":"contacts.ImportedContacts"},{"id":"-1902823612","method":"contacts.deleteContact","params":[{"name":"id","type":"InputUser"}],"type":"contacts.Link"},{"id":"1504393374","method":"contacts.deleteContacts","params":[{"name":"id","type":"Vector"}],"type":"Bool"},{"id":"858475004","method":"contacts.block","params":[{"name":"id","type":"InputUser"}],"type":"Bool"},{"id":"-448724803","method":"contacts.unblock","params":[{"name":"id","type":"InputUser"}],"type":"Bool"},{"id":"-176409329","method":"contacts.getBlocked","params":[{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"contacts.Blocked"},{"id":"-2065352905","method":"contacts.exportCard","params":[],"type":"Vector"},{"id":"1340184318","method":"contacts.importCard","params":[{"name":"export_card","type":"Vector"}],"type":"User"},{"id":"1109588596","method":"messages.getMessages","params":[{"name":"id","type":"Vector"}],"type":"messages.Messages"},{"id":"1799878989","method":"messages.getDialogs","params":[{"name":"offset_date","type":"int"},{"name":"offset_id","type":"int"},{"name":"offset_peer","type":"InputPeer"},{"name":"limit","type":"int"}],"type":"messages.Dialogs"},{"id":"-1347868602","method":"messages.getHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"offset_id","type":"int"},{"name":"offset_date","type":"int"},{"name":"add_offset","type":"int"},{"name":"limit","type":"int"},{"name":"max_id","type":"int"},{"name":"min_id","type":"int"}],"type":"messages.Messages"},{"id":"-732523960","method":"messages.search","params":[{"name":"flags","type":"#"},{"name":"peer","type":"InputPeer"},{"name":"q","type":"string"},{"name":"filter","type":"MessagesFilter"},{"name":"min_date","type":"int"},{"name":"max_date","type":"int"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Messages"},{"id":"238054714","method":"messages.readHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"max_id","type":"int"}],"type":"messages.AffectedMessages"},{"id":"469850889","method":"messages.deleteHistory","params":[{"name":"flags","type":"#"},{"name":"just_clear","type":"flags.0?true"},{"name":"peer","type":"InputPeer"},{"name":"max_id","type":"int"}],"type":"messages.AffectedHistory"},{"id":"-1510897371","method":"messages.deleteMessages","params":[{"name":"id","type":"Vector"}],"type":"messages.AffectedMessages"},{"id":"94983360","method":"messages.receivedMessages","params":[{"name":"max_id","type":"int"}],"type":"Vector"},{"id":"-1551737264","method":"messages.setTyping","params":[{"name":"peer","type":"InputPeer"},{"name":"action","type":"SendMessageAction"}],"type":"Bool"},{"id":"-91733382","method":"messages.sendMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"clear_draft","type":"flags.7?true"},{"name":"peer","type":"InputPeer"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"message","type":"string"},{"name":"random_id","type":"long"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"},{"name":"entities","type":"flags.3?Vector"}],"type":"Updates"},{"id":"-923703407","method":"messages.sendMedia","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"clear_draft","type":"flags.7?true"},{"name":"peer","type":"InputPeer"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"media","type":"InputMedia"},{"name":"random_id","type":"long"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"Updates"},{"id":"1888354709","method":"messages.forwardMessages","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"from_peer","type":"InputPeer"},{"name":"id","type":"Vector"},{"name":"random_id","type":"Vector"},{"name":"to_peer","type":"InputPeer"}],"type":"Updates"},{"id":"-820669733","method":"messages.reportSpam","params":[{"name":"peer","type":"InputPeer"}],"type":"Bool"},{"id":"-1460572005","method":"messages.hideReportSpam","params":[{"name":"peer","type":"InputPeer"}],"type":"Bool"},{"id":"913498268","method":"messages.getPeerSettings","params":[{"name":"peer","type":"InputPeer"}],"type":"PeerSettings"},{"id":"1013621127","method":"messages.getChats","params":[{"name":"id","type":"Vector"}],"type":"messages.Chats"},{"id":"998448230","method":"messages.getFullChat","params":[{"name":"chat_id","type":"int"}],"type":"messages.ChatFull"},{"id":"-599447467","method":"messages.editChatTitle","params":[{"name":"chat_id","type":"int"},{"name":"title","type":"string"}],"type":"Updates"},{"id":"-900957736","method":"messages.editChatPhoto","params":[{"name":"chat_id","type":"int"},{"name":"photo","type":"InputChatPhoto"}],"type":"Updates"},{"id":"-106911223","method":"messages.addChatUser","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"},{"name":"fwd_limit","type":"int"}],"type":"Updates"},{"id":"-530505962","method":"messages.deleteChatUser","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"}],"type":"Updates"},{"id":"164303470","method":"messages.createChat","params":[{"name":"users","type":"Vector"},{"name":"title","type":"string"}],"type":"Updates"},{"id":"-304838614","method":"updates.getState","params":[],"type":"updates.State"},{"id":"168039573","method":"updates.getDifference","params":[{"name":"pts","type":"int"},{"name":"date","type":"int"},{"name":"qts","type":"int"}],"type":"updates.Difference"},{"id":"-285902432","method":"photos.updateProfilePhoto","params":[{"name":"id","type":"InputPhoto"},{"name":"crop","type":"InputPhotoCrop"}],"type":"UserProfilePhoto"},{"id":"-720397176","method":"photos.uploadProfilePhoto","params":[{"name":"file","type":"InputFile"},{"name":"caption","type":"string"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"crop","type":"InputPhotoCrop"}],"type":"photos.Photo"},{"id":"-2016444625","method":"photos.deletePhotos","params":[{"name":"id","type":"Vector"}],"type":"Vector"},{"id":"-1291540959","method":"upload.saveFilePart","params":[{"name":"file_id","type":"long"},{"name":"file_part","type":"int"},{"name":"bytes","type":"bytes"}],"type":"Bool"},{"id":"-475607115","method":"upload.getFile","params":[{"name":"location","type":"InputFileLocation"},{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"upload.File"},{"id":"-990308245","method":"help.getConfig","params":[],"type":"Config"},{"id":"531836966","method":"help.getNearestDc","params":[],"type":"NearestDc"},{"id":"-1372724842","method":"help.getAppUpdate","params":[],"type":"help.AppUpdate"},{"id":"1862465352","method":"help.saveAppLog","params":[{"name":"events","type":"Vector"}],"type":"Bool"},{"id":"1295590211","method":"help.getInviteText","params":[],"type":"help.InviteText"},{"id":"-1848823128","method":"photos.getUserPhotos","params":[{"name":"user_id","type":"InputUser"},{"name":"offset","type":"int"},{"name":"max_id","type":"long"},{"name":"limit","type":"int"}],"type":"photos.Photos"},{"id":"865483769","method":"messages.forwardMessage","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"random_id","type":"long"}],"type":"Updates"},{"id":"-1082919718","method":"messages.sendBroadcast","params":[{"name":"contacts","type":"Vector"},{"name":"random_id","type":"Vector"},{"name":"message","type":"string"},{"name":"media","type":"InputMedia"}],"type":"Updates"},{"id":"651135312","method":"messages.getDhConfig","params":[{"name":"version","type":"int"},{"name":"random_length","type":"int"}],"type":"messages.DhConfig"},{"id":"-162681021","method":"messages.requestEncryption","params":[{"name":"user_id","type":"InputUser"},{"name":"random_id","type":"int"},{"name":"g_a","type":"bytes"}],"type":"EncryptedChat"},{"id":"1035731989","method":"messages.acceptEncryption","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"g_b","type":"bytes"},{"name":"key_fingerprint","type":"long"}],"type":"EncryptedChat"},{"id":"-304536635","method":"messages.discardEncryption","params":[{"name":"chat_id","type":"int"}],"type":"Bool"},{"id":"2031374829","method":"messages.setEncryptedTyping","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"typing","type":"Bool"}],"type":"Bool"},{"id":"2135648522","method":"messages.readEncryptedHistory","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"max_date","type":"int"}],"type":"Bool"},{"id":"-1451792525","method":"messages.sendEncrypted","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"}],"type":"messages.SentEncryptedMessage"},{"id":"-1701831834","method":"messages.sendEncryptedFile","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"},{"name":"file","type":"InputEncryptedFile"}],"type":"messages.SentEncryptedMessage"},{"id":"852769188","method":"messages.sendEncryptedService","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"}],"type":"messages.SentEncryptedMessage"},{"id":"1436924774","method":"messages.receivedQueue","params":[{"name":"max_qts","type":"int"}],"type":"Vector"},{"id":"-562337987","method":"upload.saveBigFilePart","params":[{"name":"file_id","type":"long"},{"name":"file_part","type":"int"},{"name":"file_total_parts","type":"int"},{"name":"bytes","type":"bytes"}],"type":"Bool"},{"id":"1769565673","method":"initConnection","params":[{"name":"api_id","type":"int"},{"name":"device_model","type":"string"},{"name":"system_version","type":"string"},{"name":"app_version","type":"string"},{"name":"lang_code","type":"string"},{"name":"query","type":"!X"}],"type":"X"},{"id":"-1663104819","method":"help.getSupport","params":[],"type":"help.Support"},{"id":"916930423","method":"messages.readMessageContents","params":[{"name":"id","type":"Vector"}],"type":"messages.AffectedMessages"},{"id":"655677548","method":"account.checkUsername","params":[{"name":"username","type":"string"}],"type":"Bool"},{"id":"1040964988","method":"account.updateUsername","params":[{"name":"username","type":"string"}],"type":"User"},{"id":"301470424","method":"contacts.search","params":[{"name":"q","type":"string"},{"name":"limit","type":"int"}],"type":"contacts.Found"},{"id":"-623130288","method":"account.getPrivacy","params":[{"name":"key","type":"InputPrivacyKey"}],"type":"account.PrivacyRules"},{"id":"-906486552","method":"account.setPrivacy","params":[{"name":"key","type":"InputPrivacyKey"},{"name":"rules","type":"Vector"}],"type":"account.PrivacyRules"},{"id":"1099779595","method":"account.deleteAccount","params":[{"name":"reason","type":"string"}],"type":"Bool"},{"id":"150761757","method":"account.getAccountTTL","params":[],"type":"AccountDaysTTL"},{"id":"608323678","method":"account.setAccountTTL","params":[{"name":"ttl","type":"AccountDaysTTL"}],"type":"Bool"},{"id":"-627372787","method":"invokeWithLayer","params":[{"name":"layer","type":"int"},{"name":"query","type":"!X"}],"type":"X"},{"id":"-113456221","method":"contacts.resolveUsername","params":[{"name":"username","type":"string"}],"type":"contacts.ResolvedPeer"},{"id":"149257707","method":"account.sendChangePhoneCode","params":[{"name":"flags","type":"#"},{"name":"allow_flashcall","type":"flags.0?true"},{"name":"phone_number","type":"string"},{"name":"current_number","type":"flags.0?Bool"}],"type":"auth.SentCode"},{"id":"1891839707","method":"account.changePhone","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"User"},{"id":"-1373446075","method":"messages.getStickers","params":[{"name":"emoticon","type":"string"},{"name":"hash","type":"string"}],"type":"messages.Stickers"},{"id":"479598769","method":"messages.getAllStickers","params":[{"name":"hash","type":"int"}],"type":"messages.AllStickers"},{"id":"954152242","method":"account.updateDeviceLocked","params":[{"name":"period","type":"int"}],"type":"Bool"},{"id":"1738800940","method":"auth.importBotAuthorization","params":[{"name":"flags","type":"int"},{"name":"api_id","type":"int"},{"name":"api_hash","type":"string"},{"name":"bot_auth_token","type":"string"}],"type":"auth.Authorization"},{"id":"623001124","method":"messages.getWebPagePreview","params":[{"name":"message","type":"string"}],"type":"MessageMedia"},{"id":"-484392616","method":"account.getAuthorizations","params":[],"type":"account.Authorizations"},{"id":"-545786948","method":"account.resetAuthorization","params":[{"name":"hash","type":"long"}],"type":"Bool"},{"id":"1418342645","method":"account.getPassword","params":[],"type":"account.Password"},{"id":"-1131605573","method":"account.getPasswordSettings","params":[{"name":"current_password_hash","type":"bytes"}],"type":"account.PasswordSettings"},{"id":"-92517498","method":"account.updatePasswordSettings","params":[{"name":"current_password_hash","type":"bytes"},{"name":"new_settings","type":"account.PasswordInputSettings"}],"type":"Bool"},{"id":"174260510","method":"auth.checkPassword","params":[{"name":"password_hash","type":"bytes"}],"type":"auth.Authorization"},{"id":"-661144474","method":"auth.requestPasswordRecovery","params":[],"type":"auth.PasswordRecovery"},{"id":"1319464594","method":"auth.recoverPassword","params":[{"name":"code","type":"string"}],"type":"auth.Authorization"},{"id":"-1080796745","method":"invokeWithoutUpdates","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"2106086025","method":"messages.exportChatInvite","params":[{"name":"chat_id","type":"int"}],"type":"ExportedChatInvite"},{"id":"1051570619","method":"messages.checkChatInvite","params":[{"name":"hash","type":"string"}],"type":"ChatInvite"},{"id":"1817183516","method":"messages.importChatInvite","params":[{"name":"hash","type":"string"}],"type":"Updates"},{"id":"639215886","method":"messages.getStickerSet","params":[{"name":"stickerset","type":"InputStickerSet"}],"type":"messages.StickerSet"},{"id":"-946871200","method":"messages.installStickerSet","params":[{"name":"stickerset","type":"InputStickerSet"},{"name":"archived","type":"Bool"}],"type":"messages.StickerSetInstallResult"},{"id":"-110209570","method":"messages.uninstallStickerSet","params":[{"name":"stickerset","type":"InputStickerSet"}],"type":"Bool"},{"id":"-421563528","method":"messages.startBot","params":[{"name":"bot","type":"InputUser"},{"name":"peer","type":"InputPeer"},{"name":"random_id","type":"long"},{"name":"start_param","type":"string"}],"type":"Updates"},{"id":"-1189013126","method":"help.getAppChangelog","params":[],"type":"help.AppChangelog"},{"id":"-993483427","method":"messages.getMessagesViews","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"Vector"},{"name":"increment","type":"Bool"}],"type":"Vector"},{"id":"-871347913","method":"channels.readHistory","params":[{"name":"channel","type":"InputChannel"},{"name":"max_id","type":"int"}],"type":"Bool"},{"id":"-2067661490","method":"channels.deleteMessages","params":[{"name":"channel","type":"InputChannel"},{"name":"id","type":"Vector"}],"type":"messages.AffectedMessages"},{"id":"-787622117","method":"channels.deleteUserHistory","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"}],"type":"messages.AffectedHistory"},{"id":"-32999408","method":"channels.reportSpam","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"},{"name":"id","type":"Vector"}],"type":"Bool"},{"id":"-1814580409","method":"channels.getMessages","params":[{"name":"channel","type":"InputChannel"},{"name":"id","type":"Vector"}],"type":"messages.Messages"},{"id":"618237842","method":"channels.getParticipants","params":[{"name":"channel","type":"InputChannel"},{"name":"filter","type":"ChannelParticipantsFilter"},{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"channels.ChannelParticipants"},{"id":"1416484774","method":"channels.getParticipant","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"}],"type":"channels.ChannelParticipant"},{"id":"176122811","method":"channels.getChannels","params":[{"name":"id","type":"Vector"}],"type":"messages.Chats"},{"id":"141781513","method":"channels.getFullChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"messages.ChatFull"},{"id":"-192332417","method":"channels.createChannel","params":[{"name":"flags","type":"#"},{"name":"broadcast","type":"flags.0?true"},{"name":"megagroup","type":"flags.1?true"},{"name":"title","type":"string"},{"name":"about","type":"string"}],"type":"Updates"},{"id":"333610782","method":"channels.editAbout","params":[{"name":"channel","type":"InputChannel"},{"name":"about","type":"string"}],"type":"Bool"},{"id":"-344583728","method":"channels.editAdmin","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"},{"name":"role","type":"ChannelParticipantRole"}],"type":"Updates"},{"id":"1450044624","method":"channels.editTitle","params":[{"name":"channel","type":"InputChannel"},{"name":"title","type":"string"}],"type":"Updates"},{"id":"-248621111","method":"channels.editPhoto","params":[{"name":"channel","type":"InputChannel"},{"name":"photo","type":"InputChatPhoto"}],"type":"Updates"},{"id":"283557164","method":"channels.checkUsername","params":[{"name":"channel","type":"InputChannel"},{"name":"username","type":"string"}],"type":"Bool"},{"id":"890549214","method":"channels.updateUsername","params":[{"name":"channel","type":"InputChannel"},{"name":"username","type":"string"}],"type":"Bool"},{"id":"615851205","method":"channels.joinChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"Updates"},{"id":"-130635115","method":"channels.leaveChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"Updates"},{"id":"429865580","method":"channels.inviteToChannel","params":[{"name":"channel","type":"InputChannel"},{"name":"users","type":"Vector"}],"type":"Updates"},{"id":"-1502421484","method":"channels.kickFromChannel","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"},{"name":"kicked","type":"Bool"}],"type":"Updates"},{"id":"-950663035","method":"channels.exportInvite","params":[{"name":"channel","type":"InputChannel"}],"type":"ExportedChatInvite"},{"id":"-1072619549","method":"channels.deleteChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"Updates"},{"id":"-1154295872","method":"updates.getChannelDifference","params":[{"name":"channel","type":"InputChannel"},{"name":"filter","type":"ChannelMessagesFilter"},{"name":"pts","type":"int"},{"name":"limit","type":"int"}],"type":"updates.ChannelDifference"},{"id":"-326379039","method":"messages.toggleChatAdmins","params":[{"name":"chat_id","type":"int"},{"name":"enabled","type":"Bool"}],"type":"Updates"},{"id":"-1444503762","method":"messages.editChatAdmin","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"},{"name":"is_admin","type":"Bool"}],"type":"Bool"},{"id":"363051235","method":"messages.migrateChat","params":[{"name":"chat_id","type":"int"}],"type":"Updates"},{"id":"-1640190800","method":"messages.searchGlobal","params":[{"name":"q","type":"string"},{"name":"offset_date","type":"int"},{"name":"offset_peer","type":"InputPeer"},{"name":"offset_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Messages"},{"id":"889286899","method":"help.getTermsOfService","params":[],"type":"help.TermsOfService"},{"id":"-1613775824","method":"messages.reorderStickerSets","params":[{"name":"order","type":"Vector"}],"type":"Bool"},{"id":"864953444","method":"messages.getDocumentByHash","params":[{"name":"sha256","type":"bytes"},{"name":"size","type":"int"},{"name":"mime_type","type":"string"}],"type":"Document"},{"id":"-1080395925","method":"messages.searchGifs","params":[{"name":"q","type":"string"},{"name":"offset","type":"int"}],"type":"messages.FoundGifs"},{"id":"-2084618926","method":"messages.getSavedGifs","params":[{"name":"hash","type":"int"}],"type":"messages.SavedGifs"},{"id":"846868683","method":"messages.saveGif","params":[{"name":"id","type":"InputDocument"},{"name":"unsave","type":"Bool"}],"type":"Bool"},{"id":"1364105629","method":"messages.getInlineBotResults","params":[{"name":"flags","type":"#"},{"name":"bot","type":"InputUser"},{"name":"peer","type":"InputPeer"},{"name":"geo_point","type":"flags.0?InputGeoPoint"},{"name":"query","type":"string"},{"name":"offset","type":"string"}],"type":"messages.BotResults"},{"id":"-346119674","method":"messages.setInlineBotResults","params":[{"name":"flags","type":"#"},{"name":"gallery","type":"flags.0?true"},{"name":"private","type":"flags.1?true"},{"name":"query_id","type":"long"},{"name":"results","type":"Vector"},{"name":"cache_time","type":"int"},{"name":"next_offset","type":"flags.2?string"},{"name":"switch_pm","type":"flags.3?InlineBotSwitchPM"}],"type":"Bool"},{"id":"-1318189314","method":"messages.sendInlineBotResult","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"clear_draft","type":"flags.7?true"},{"name":"peer","type":"InputPeer"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"random_id","type":"long"},{"name":"query_id","type":"long"},{"name":"id","type":"string"}],"type":"Updates"},{"id":"1231065863","method":"channels.toggleInvites","params":[{"name":"channel","type":"InputChannel"},{"name":"enabled","type":"Bool"}],"type":"Updates"},{"id":"-934882771","method":"channels.exportMessageLink","params":[{"name":"channel","type":"InputChannel"},{"name":"id","type":"int"}],"type":"ExportedMessageLink"},{"id":"527021574","method":"channels.toggleSignatures","params":[{"name":"channel","type":"InputChannel"},{"name":"enabled","type":"Bool"}],"type":"Updates"},{"id":"-1490162350","method":"channels.updatePinnedMessage","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.0?true"},{"name":"channel","type":"InputChannel"},{"name":"id","type":"int"}],"type":"Updates"},{"id":"1056025023","method":"auth.resendCode","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"}],"type":"auth.SentCode"},{"id":"520357240","method":"auth.cancelCode","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"}],"type":"Bool"},{"id":"-39416522","method":"messages.getMessageEditData","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"}],"type":"messages.MessageEditData"},{"id":"-829299510","method":"messages.editMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"message","type":"flags.11?string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"},{"name":"entities","type":"flags.3?Vector"}],"type":"Updates"},{"id":"319564933","method":"messages.editInlineBotMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"id","type":"InputBotInlineMessageID"},{"name":"message","type":"flags.11?string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"},{"name":"entities","type":"flags.3?Vector"}],"type":"Bool"},{"id":"-1494659324","method":"messages.getBotCallbackAnswer","params":[{"name":"peer","type":"InputPeer"},{"name":"msg_id","type":"int"},{"name":"data","type":"bytes"}],"type":"messages.BotCallbackAnswer"},{"id":"-920136629","method":"messages.setBotCallbackAnswer","params":[{"name":"flags","type":"#"},{"name":"alert","type":"flags.1?true"},{"name":"query_id","type":"long"},{"name":"message","type":"flags.0?string"},{"name":"url","type":"flags.2?string"}],"type":"Bool"},{"id":"-728224331","method":"contacts.getTopPeers","params":[{"name":"flags","type":"#"},{"name":"correspondents","type":"flags.0?true"},{"name":"bots_pm","type":"flags.1?true"},{"name":"bots_inline","type":"flags.2?true"},{"name":"groups","type":"flags.10?true"},{"name":"channels","type":"flags.15?true"},{"name":"offset","type":"int"},{"name":"limit","type":"int"},{"name":"hash","type":"int"}],"type":"contacts.TopPeers"},{"id":"451113900","method":"contacts.resetTopPeerRating","params":[{"name":"category","type":"TopPeerCategory"},{"name":"peer","type":"InputPeer"}],"type":"Bool"},{"id":"764901049","method":"messages.getPeerDialogs","params":[{"name":"peers","type":"Vector"}],"type":"messages.PeerDialogs"},{"id":"-1137057461","method":"messages.saveDraft","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"peer","type":"InputPeer"},{"name":"message","type":"string"},{"name":"entities","type":"flags.3?Vector"}],"type":"Bool"},{"id":"1782549861","method":"messages.getAllDrafts","params":[],"type":"Updates"},{"id":"766298703","method":"messages.getFeaturedStickers","params":[{"name":"hash","type":"int"}],"type":"messages.FeaturedStickers"},{"id":"14818491","method":"messages.readFeaturedStickers","params":[],"type":"Bool"},{"id":"-1726383060","method":"messages.getRecentStickers","params":[{"name":"hash","type":"int"}],"type":"messages.RecentStickers"},{"id":"881736127","method":"messages.saveRecentSticker","params":[{"name":"id","type":"InputDocument"},{"name":"unsave","type":"Bool"}],"type":"Bool"},{"id":"-1425873454","method":"messages.clearRecentStickers","params":[],"type":"Bool"},{"id":"1124718171","method":"messages.getUnusedStickers","params":[{"name":"limit","type":"int"}],"type":"Vector"},{"id":"-1871829985","method":"messages.getArchivedStickers","params":[{"name":"offset_id","type":"long"},{"name":"limit","type":"int"}],"type":"messages.ArchivedStickers"},{"id":"353818557","method":"account.sendConfirmPhoneCode","params":[{"name":"flags","type":"#"},{"name":"allow_flashcall","type":"flags.0?true"},{"name":"hash","type":"string"},{"name":"current_number","type":"flags.0?Bool"}],"type":"auth.SentCode"},{"id":"1596029123","method":"account.confirmPhone","params":[{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"Bool"}]}. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Conversion { public static function random($length) { return $length === 0 ? '' : \phpseclib\Crypt\Random::string($length); } public static function unpack_signed_int($value) { if (strlen($value) !== 4) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_4']); } return unpack('l', !\danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1]; } public static function pack_signed_int($value) { if ($value > 2147483647) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_2147483647'], $value)); } if ($value < -2147483648) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_2147483648'], $value)); } $res = pack('l', $value); return !\danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($res) : $res; } public static function old_aes_calculate($msg_key, $auth_key, $to_server = true) { $x = $to_server ? 0 : 8; $sha1_a = sha1($msg_key.substr($auth_key, $x, 32), true); $sha1_b = sha1(substr($auth_key, 32 + $x, 16).$msg_key.substr($auth_key, 48 + $x, 16), true); $sha1_c = sha1(substr($auth_key, 64 + $x, 32).$msg_key, true); $sha1_d = sha1($msg_key.substr($auth_key, 96 + $x, 32), true); $aes_key = substr($sha1_a, 0, 8).substr($sha1_b, 8, 12).substr($sha1_c, 4, 12); $aes_iv = substr($sha1_a, 8, 12).substr($sha1_b, 0, 8).substr($sha1_c, 16, 4).substr($sha1_d, 0, 8); return [$aes_key, $aes_iv]; } public static function ige_decrypt($message, $key, $iv) { $cipher = new \phpseclib\Crypt\AES('ige'); $cipher->setKey($key); $cipher->setIV($iv); return @$cipher->decrypt($message); } public static function telethon($session, $new_session, $settings = []) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); if (!extension_loaded('sqlite3')) { throw new Exception(['extension', 'sqlite3']); } if (!isset(pathinfo($session)['extension'])) { $session .= '.session'; } $session = Absolute::absolute($session); $sqlite = new \PDO("sqlite:$session"); $sqlite->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING); $sessions = $sqlite->query('SELECT * FROM sessions')->fetchAll(); $MadelineProto = new \danog\MadelineProto\API($new_session, $settings); foreach ($sessions as $dc) { $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->auth_key = ['server_salt' => '', 'connection_inited' => true, 'id' => substr(sha1($dc['auth_key'], true), -8), 'auth_key' => $dc['auth_key']]; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->temp_auth_key = null; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->ip = $dc['server_address']; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->port = $dc['port']; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->authorized = true; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->session_id = $MadelineProto->random(8); $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->session_in_seq_no = 0; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->session_out_seq_no = 0; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->incoming_messages = []; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->outgoing_messages = []; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->new_outgoing = []; $MadelineProto->API->datacenter->sockets[$dc['dc_id']]->incoming = []; } $MadelineProto->API->authorized = MTProto::LOGGED_IN; $MadelineProto->API->init_authorization(); return $MadelineProto; } public static function pyrogram($session, $new_session, $settings = []) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); if (!isset(pathinfo($session)['extension'])) { $session .= '.session'; } $session = Absolute::absolute($session); $session = json_decode(file_get_contents($session), true); $session['auth_key'] = base64_decode(implode('', $session['auth_key'])); $settings['connection_settings']['all']['test_mode'] = $session['test_mode']; $MadelineProto = new \danog\MadelineProto\API($new_session, $settings); $MadelineProto->API->datacenter->sockets[$session['dc_id']]->auth_key = ['server_salt' => '', 'connection_inited' => true, 'id' => substr(sha1($session['auth_key'], true), -8), 'auth_key' => $session['auth_key']]; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->temp_auth_key = null; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->authorized = true; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->session_id = $MadelineProto->random(8); $MadelineProto->API->datacenter->sockets[$session['dc_id']]->session_in_seq_no = 0; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->session_out_seq_no = 0; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->incoming_messages = []; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->outgoing_messages = []; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->new_outgoing = []; $MadelineProto->API->datacenter->sockets[$session['dc_id']]->incoming = []; $MadelineProto->API->authorized = MTProto::LOGGED_IN; $MadelineProto->API->init_authorization(); return $MadelineProto; } public static function zerobias($session, $new_session, $settings = []) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); if (is_string($session)) { $session = json_decode($session, true); } $dc = $session['dc']; $session['auth_key'] = hex2bin($session["dc$dc".'_auth_key']); $MadelineProto = new \danog\MadelineProto\API($new_session, $settings); $MadelineProto->API->datacenter->sockets[$dc]->auth_key = ['server_salt' => '', 'connection_inited' => true, 'id' => substr(sha1($session['auth_key'], true), -8), 'auth_key' => $session['auth_key']]; $MadelineProto->API->datacenter->sockets[$dc]->temp_auth_key = null; $MadelineProto->API->datacenter->sockets[$dc]->authorized = true; $MadelineProto->API->datacenter->sockets[$dc]->session_id = $MadelineProto->random(8); $MadelineProto->API->datacenter->sockets[$dc]->session_in_seq_no = 0; $MadelineProto->API->datacenter->sockets[$dc]->session_out_seq_no = 0; $MadelineProto->API->datacenter->sockets[$dc]->incoming_messages = []; $MadelineProto->API->datacenter->sockets[$dc]->outgoing_messages = []; $MadelineProto->API->datacenter->sockets[$dc]->new_outgoing = []; $MadelineProto->API->datacenter->sockets[$dc]->incoming = []; $MadelineProto->API->authorized = MTProto::LOGGED_IN; $MadelineProto->API->init_authorization(); return $MadelineProto; } public static function tdesktop_md5($data) { $result = ''; foreach (str_split(md5($data), 2) as $byte) { $result .= strrev($byte); } return strtoupper($result); } const FILEOPTION_SAFE = 1; const FILEOPTION_USER = 2; public static $tdesktop_base_path; public static $tdesktop_user_base_path; public static $tdesktop_key; public static function tdesktop_fopen($fileName, $options = 3) { $name = ($options & self::FILEOPTION_USER ? self::$tdesktop_user_base_path : self::$tdesktop_base_path).$fileName; $totry = []; for ($x = 0; $x <= 1; $x++) { if (file_exists($name.$x)) { $totry[] = fopen($name.$x, 'rb'); } } foreach ($totry as $fp) { if (stream_get_contents($fp, 4) !== 'TDF$') { \danog\MadelineProto\Logger::log('Wrong magic', Logger::ERROR); continue; } $versionBytes = stream_get_contents($fp, 4); $version = self::unpack_signed_int($versionBytes); \danog\MadelineProto\Logger::log("TDesktop version: $version"); $data = stream_get_contents($fp); $md5 = substr($data, -16); $data = substr($data, 0, -16); $length = pack('l', strlen($data)); $length = \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($length) : $length; if (md5($data.$length.$versionBytes.'TDF$', true) !== $md5) { \danog\MadelineProto\Logger::log('Wrong MD5', Logger::ERROR); } $res = fopen('php://memory', 'rw+b'); fwrite($res, $data); fseek($res, 0); return $res; } throw new Exception("Could not open $fileName"); } public static function tdesktop_fopen_encrypted($fileName, $options = 3) { $f = self::tdesktop_fopen($fileName, $options); $data = self::tdesktop_read_bytearray($f); $res = self::tdesktop_decrypt($data, self::$tdesktop_key); $length = unpack('V', stream_get_contents($res, 4))[1]; if ($length > fstat($res)['size'] || $length < 4) { throw new \danog\MadelineProto\Exception('Wrong length'); } return $res; } public static function tdesktop_read_bytearray($fp) { $length = self::unpack_signed_int(stream_get_contents($fp, 4)); $data = $length ? stream_get_contents($fp, $length) : ''; $res = fopen('php://memory', 'rw+b'); fwrite($res, $data); fseek($res, 0); return $res; } public static function tdesktop_decrypt($data, $auth_key) { $message_key = stream_get_contents($data, 16); $encrypted_data = stream_get_contents($data); list($aes_key, $aes_iv) = self::old_aes_calculate($message_key, $auth_key, false); $decrypted_data = self::ige_decrypt($encrypted_data, $aes_key, $aes_iv); if ($message_key != substr(sha1($decrypted_data, true), 0, 16)) { throw new \danog\MadelineProto\SecurityException('msg_key mismatch'); } $res = fopen('php://memory', 'rw+b'); fwrite($res, $decrypted_data); fseek($res, 0); return $res; } const dbiKey = 0x00; const dbiUser = 0x01; const dbiDcOptionOldOld = 0x02; const dbiChatSizeMax = 0x03; const dbiMutePeer = 0x04; const dbiSendKey = 0x05; const dbiAutoStart = 0x06; const dbiStartMinimized = 0x07; const dbiSoundNotify = 0x08; const dbiWorkMode = 0x09; const dbiSeenTrayTooltip = 0x0a; const dbiDesktopNotify = 0x0b; const dbiAutoUpdate = 0x0c; const dbiLastUpdateCheck = 0x0d; const dbiWindowPosition = 0x0e; const dbiConnectionTypeOld = 0x0f; // 0x10 reserved const dbiDefaultAttach = 0x11; const dbiCatsAndDogs = 0x12; const dbiReplaceEmojis = 0x13; const dbiAskDownloadPath = 0x14; const dbiDownloadPathOld = 0x15; const dbiScale = 0x16; const dbiEmojiTabOld = 0x17; const dbiRecentEmojiOldOld = 0x18; const dbiLoggedPhoneNumber = 0x19; const dbiMutedPeers = 0x1a; // 0x1b reserved const dbiNotifyView = 0x1c; const dbiSendToMenu = 0x1d; const dbiCompressPastedImage = 0x1e; const dbiLangOld = 0x1f; const dbiLangFileOld = 0x20; const dbiTileBackground = 0x21; const dbiAutoLock = 0x22; const dbiDialogLastPath = 0x23; const dbiRecentEmojiOld = 0x24; const dbiEmojiVariantsOld = 0x25; const dbiRecentStickers = 0x26; const dbiDcOptionOld = 0x27; const dbiTryIPv6 = 0x28; const dbiSongVolume = 0x29; const dbiWindowsNotificationsOld = 0x30; const dbiIncludeMuted = 0x31; const dbiMegagroupSizeMax = 0x32; const dbiDownloadPath = 0x33; const dbiAutoDownload = 0x34; const dbiSavedGifsLimit = 0x35; const dbiShowingSavedGifsOld = 0x36; const dbiAutoPlay = 0x37; const dbiAdaptiveForWide = 0x38; const dbiHiddenPinnedMessages = 0x39; const dbiRecentEmoji = 0x3a; const dbiEmojiVariants = 0x3b; const dbiDialogsMode = 0x40; const dbiModerateMode = 0x41; const dbiVideoVolume = 0x42; const dbiStickersRecentLimit = 0x43; const dbiNativeNotifications = 0x44; const dbiNotificationsCount = 0x45; const dbiNotificationsCorner = 0x46; const dbiThemeKey = 0x47; const dbiDialogsWidthRatioOld = 0x48; const dbiUseExternalVideoPlayer = 0x49; const dbiDcOptions = 0x4a; const dbiMtpAuthorization = 0x4b; const dbiLastSeenWarningSeenOld = 0x4c; const dbiAuthSessionSettings = 0x4d; const dbiLangPackKey = 0x4e; const dbiConnectionType = 0x4f; const dbiStickersFavedLimit = 0x50; const dbiSuggestStickersByEmoji = 0x51; const dbiEncryptedWithSalt = 333; const dbiEncrypted = 444; // 500-600 reserved const dbiVersion = 666; public static function tdesktop($session, $new_session, $settings = []) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); if (!isset($settings['old_session_key'])) { $settings['old_session_key'] = 'data'; } if (!isset($settings['old_session_passcode'])) { $settings['old_session_passcode'] = ''; } if (basename($session) !== 'tdata') { $session .= '/tdata'; } list($part_one_md5, $part_two_md5) = str_split(self::tdesktop_md5($settings['old_session_key']), 16); self::$tdesktop_base_path = $session.'/'; self::$tdesktop_user_base_path = self::$tdesktop_base_path.$part_one_md5.'/'; $data = self::tdesktop_fopen('map'); $salt = self::tdesktop_read_bytearray($data); $salt = fstat($salt)['size'] ? $salt : self::random(32); $encryptedKey = self::tdesktop_read_bytearray($data); $keyIterCount = strlen($settings['old_session_passcode']) ? 4000 : 4; $passKey = openssl_pbkdf2($settings['old_session_passcode'], stream_get_contents($salt), 256, $keyIterCount); self::$tdesktop_key = stream_get_contents(self::tdesktop_read_bytearray(self::tdesktop_decrypt($encryptedKey, $passKey))); $main = self::tdesktop_fopen_encrypted($part_one_md5, self::FILEOPTION_SAFE); $auth_keys = []; while (true) { $magic = self::unpack_signed_int(stream_get_contents($main, 4)); switch ($magic) { case self::dbiDcOptionOldOld: stream_get_contents($main, 4); self::tdesktop_read_bytearray($main); self::tdesktop_read_bytearray($main); stream_get_contents($main, 4); break; case self::dbiDcOptionOld: stream_get_contents($main, 8); self::tdesktop_read_bytearray($main); stream_get_contents($main, 4); break; case self::dbiDcOptions: self::tdesktop_read_bytearray($main); break; case self::dbiUser: stream_get_contents($main, 4); $main_dc_id = self::unpack_signed_int(stream_get_contents($main, 4)); break; case self::dbiKey: $auth_keys[self::unpack_signed_int(stream_get_contents($main, 4))] = stream_get_contents($main, 256); break; case self::dbiMtpAuthorization: $main = self::tdesktop_read_bytearray($main); //stream_get_contents($main, 4); $user_id = self::unpack_signed_int(stream_get_contents($main, 4)); $main_dc_id = self::unpack_signed_int(stream_get_contents($main, 4)); $length = self::unpack_signed_int(stream_get_contents($main, 4)); for ($x = 0; $x < $length; $x++) { $auth_keys[self::unpack_signed_int(stream_get_contents($main, 4))] = stream_get_contents($main, 256); } break 2; case self::dbiAutoDownload: stream_get_contents($main, 12); break; case self::dbiDialogsMode: stream_get_contents($main, 8); break; case self::dbiAuthSessionSettings: self::tdesktop_read_bytearray($main); break; case self::dbiConnectionTypeOld: switch (self::unpack_signed_int(stream_get_contents($main, 4))) { case 2: case 3: self::tdesktop_read_bytearray($main); stream_get_contents($main, 4); self::tdesktop_read_bytearray($main); self::tdesktop_read_bytearray($main); break; } break; case self::dbiConnectionType: stream_get_contents($main, 8); self::tdesktop_read_bytearray($main); stream_get_contents($main, 4); self::tdesktop_read_bytearray($main); self::tdesktop_read_bytearray($main); break; case self::dbiThemeKey: case self::dbiLangPackKey: case self::dbiMutePeer: stream_get_contents($main, 8); break; case self::dbiWindowPosition: stream_get_contents($main, 24); break; case self::dbiLoggedPhoneNumber: self::tdesktop_read_bytearray($main); break; case self::dbiMutedPeers: $length = self::unpack_signed_int(stream_get_contents($main, 4)); for ($x = 0; $x < $length; $x++) { stream_get_contents($main, 8); } case self::dbiDownloadPathOld: self::tdesktop_read_bytearray($main); break; case self::dbiDialogLastPath: self::tdesktop_read_bytearray($main); break; case self::dbiDownloadPath: self::tdesktop_read_bytearray($main); self::tdesktop_read_bytearray($main); break; default: stream_get_contents($main, 4); break; } } $MadelineProto = new \danog\MadelineProto\API($new_session, $settings); foreach ($auth_keys as $dc => $auth_key) { $MadelineProto->API->datacenter->sockets[$dc]->auth_key = ['server_salt' => '', 'connection_inited' => true, 'id' => substr(sha1($auth_key, true), -8), 'auth_key' => $auth_key]; $MadelineProto->API->datacenter->sockets[$dc]->temp_auth_key = null; $MadelineProto->API->datacenter->sockets[$dc]->authorized = true; $MadelineProto->API->datacenter->sockets[$dc]->session_id = $MadelineProto->random(8); $MadelineProto->API->datacenter->sockets[$dc]->session_in_seq_no = 0; $MadelineProto->API->datacenter->sockets[$dc]->session_out_seq_no = 0; $MadelineProto->API->datacenter->sockets[$dc]->incoming_messages = []; $MadelineProto->API->datacenter->sockets[$dc]->outgoing_messages = []; $MadelineProto->API->datacenter->sockets[$dc]->new_outgoing = []; $MadelineProto->API->datacenter->sockets[$dc]->incoming = []; } $MadelineProto->API->authorized = MTProto::LOGGED_IN; $MadelineProto->API->authorized_dc = $main_dc_id; $MadelineProto->API->init_authorization(); return $MadelineProto; } } ---types--- ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#edd2a791 flags:# id:int participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#22893b26 chat_id:int id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; documentEmpty#36f8c871 id:long = Document; document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyBroadcasts#d612e8ef = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; textSubscript#ed6a8504 text:RichText = RichText; textSuperscript#c7fb5e01 text:RichText = RichText; textMarked#34b8621 text:RichText = RichText; textPhone#1ccb966a text:RichText phone:string = RichText; textImage#81ccf4f document_id:long w:int h:int = RichText; textAnchor#35553762 text:RichText name:string = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#e4e88011 items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; pageBlockKicker#1e148390 text:RichText = PageBlock; pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; help.passportConfigNotModified#bfb9f457 = help.PassportConfig; help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; pageCaption#6f747657 text:RichText credit:RichText = PageCaption; pageListItemText#b92fb6cd text:RichText = PageListItem; pageListItemBlocks#25e073fc blocks:Vector = PageListItem; pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; page#ae891bec flags:# part:flags.0?true rtl:flags.1?true url:string blocks:Vector photos:Vector documents:Vector = Page; help.supportName#8c05f1c9 name:string = help.SupportName; help.userInfoEmpty#f3ae2eed = help.UserInfo; help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; account.confirmPasswordEmail#8fdf1920 code:string = Bool; account.resendPasswordEmail#7a7f2a15 = Bool; account.cancelPasswordEmail#c1cbd5b6 = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; contacts.getContactIDs#2caa4a42 hash:int = Vector; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector; messages.clearAllDrafts#7e58ee9c = Bool; messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#522d5a7d source:string = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; help.getSupportName#d360e72c = help.SupportName; help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; langpack.getDifference#9d51e814 lang_code:string from_version:int = LangPackDifference; langpack.getLanguages#42c6978f lang_pack:string = Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; // LAYER 89 // Core types (no need to gen) //vector#1cb5c415 {t:Type} # [ t ] = Vector t; /////////////////////////////// /////////////////// Layer cons /////////////////////////////// //invokeAfterMsg#cb9f372d msg_id:long query:!X = X; //invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; //invokeWithLayer1#53835315 query:!X = X; //invokeWithLayer2#289dd1f6 query:!X = X; //invokeWithLayer3#b7475268 query:!X = X; //invokeWithLayer4#dea0d430 query:!X = X; //invokeWithLayer5#417a57ae query:!X = X; //invokeWithLayer6#3a64d54d query:!X = X; //invokeWithLayer7#a5be56d3 query:!X = X; //invokeWithLayer8#e9abd9fd query:!X = X; //invokeWithLayer9#76715a63 query:!X = X; //invokeWithLayer10#39620c41 query:!X = X; //invokeWithLayer11#a6b88fdf query:!X = X; //invokeWithLayer12#dda60d3c query:!X = X; //invokeWithLayer13#427c8ea2 query:!X = X; //invokeWithLayer14#2b9b08fa query:!X = X; //invokeWithLayer15#b4418b64 query:!X = X; //invokeWithLayer16#cf5f0987 query:!X = X; //invokeWithLayer17#50858a19 query:!X = X; //invokeWithLayer18#1c900537 query:!X = X; //invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer /////////////////////////////// /// Authorization key creation /////////////////////////////// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ////////////// System messages /////////////////////////////// ---types--- msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; //message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually //msg_container#73f1f8dc messages:vector = MessageContainer; // parsed manually //msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container //gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ipPort ipv4:int port:int = IpPort; help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple; ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#630c9af1 flags:# file:InputFile caption:string stickers:flags.0?Vector = InputMedia; inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#d070f1e9 flags:# file:InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector = InputMedia; inputMediaUploadedThumbDocument#50d88cae flags:# file:InputFile thumb:InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector = InputMedia; inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia; inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#cb44b1c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#95cb5f57 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#c09be45f flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; dialog#66ffba14 flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; contacts.importedContacts#ad524315 imported:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#1508485a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; config#7feec888 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#410dee07 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#c786ddcb flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#f288a275 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#2e7a2020 file_token:bytes request_token:bytes = Bool; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#4255934 sticker:InputDocument = Bool; stickers.changeStickerPosition#4ed705ca sticker:InputDocument position:int = Bool; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector; // LAYER 68 { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "-652419756", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "admins_enabled", "type": "flags.3?true" }, { "name": "admin", "type": "flags.4?true" }, { "name": "deactivated", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "migrated_to", "type": "flags.6?InputChannel" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "1061556205", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-1063525281", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "post", "type": "flags.14?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from", "type": "flags.2?MessageFwdHeader" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" }, { "name": "views", "type": "flags.10?int" }, { "name": "edit_date", "type": "flags.15?int" } ], "type": "Message" }, { "id": "-1642487306", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "post", "type": "flags.14?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1217033015", "predicate": "messageActionChatAddUser", "params": [ { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "949182130", "predicate": "inputPeerNotifySettings", "params": [ { "name": "flags", "type": "#" }, { "name": "show_previews", "type": "flags.0?true" }, { "name": "silent", "type": "flags.1?true" }, { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1697798976", "predicate": "peerNotifySettings", "params": [ { "name": "flags", "type": "#" }, { "name": "show_previews", "type": "flags.0?true" }, { "name": "silent", "type": "flags.1?true" }, { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" } ], "type": "PeerNotifySettings" }, { "id": "-2122045747", "predicate": "peerSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "report_spam", "type": "flags.0?true" } ], "type": "PeerSettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1490799288", "predicate": "inputReportReasonSpam", "params": [], "type": "ReportReason" }, { "id": "505595789", "predicate": "inputReportReasonViolence", "params": [], "type": "ReportReason" }, { "id": "777640226", "predicate": "inputReportReasonPornography", "params": [], "type": "ReportReason" }, { "id": "-512463606", "predicate": "inputReportReasonOther", "params": [ { "name": "text", "type": "string" } ], "type": "ReportReason" }, { "id": "1496513539", "predicate": "userFull", "params": [ { "name": "flags", "type": "#" }, { "name": "blocked", "type": "flags.0?true" }, { "name": "user", "type": "User" }, { "name": "about", "type": "flags.1?string" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "flags.2?Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "bot_info", "type": "flags.3?BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "-3644025", "predicate": "inputMessagesFilterGif", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-1857044719", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from", "type": "flags.2?MessageFwdHeader" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "377562760", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from", "type": "flags.2?MessageFwdHeader" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "ipv6", "type": "flags.0?true" }, { "name": "media_only", "type": "flags.1?true" }, { "name": "tcpo_only", "type": "flags.2?true" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "830271220", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "megagroup_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "saved_gifs_limit", "type": "int" }, { "name": "edit_time_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "495530093", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1386138479", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "444068508", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-203411800", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-1739392570", "predicate": "documentAttributeAudio", "params": [ { "name": "flags", "type": "#" }, { "name": "voice", "type": "flags.10?true" }, { "name": "duration", "type": "int" }, { "name": "title", "type": "flags.0?string" }, { "name": "performer", "type": "flags.1?string" }, { "name": "waveform", "type": "flags.2?bytes" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-302170017", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "int" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-2037289493", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "channel", "type": "flags.0?true" }, { "name": "broadcast", "type": "flags.1?true" }, { "name": "public", "type": "flags.2?true" }, { "name": "megagroup", "type": "flags.3?true" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "installed", "type": "flags.0?true" }, { "name": "disabled", "type": "flags.1?true" }, { "name": "official", "type": "flags.2?true" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "-787638374", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "self", "type": "flags.10?true" }, { "name": "contact", "type": "flags.11?true" }, { "name": "mutual_contact", "type": "flags.12?true" }, { "name": "deleted", "type": "flags.13?true" }, { "name": "bot", "type": "flags.14?true" }, { "name": "bot_chat_history", "type": "flags.15?true" }, { "name": "bot_nochats", "type": "flags.16?true" }, { "name": "verified", "type": "flags.17?true" }, { "name": "restricted", "type": "flags.18?true" }, { "name": "min", "type": "flags.20?true" }, { "name": "bot_inline_geo", "type": "flags.21?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" }, { "name": "restriction_reason", "type": "flags.18?string" }, { "name": "bot_inline_placeholder", "type": "flags.19?string" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1729618630", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "resize", "type": "flags.0?true" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-1588737454", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "editor", "type": "flags.3?true" }, { "name": "moderator", "type": "flags.4?true" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "verified", "type": "flags.7?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "restricted", "type": "flags.9?true" }, { "name": "democracy", "type": "flags.10?true" }, { "name": "signatures", "type": "flags.11?true" }, { "name": "min", "type": "flags.12?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.13?long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "restriction_reason", "type": "flags.9?string" } ], "type": "Chat" }, { "id": "763724588", "predicate": "channelForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1749097118", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "can_view_participants", "type": "flags.3?true" }, { "name": "can_set_username", "type": "flags.6?true" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" }, { "name": "migrated_from_chat_id", "type": "flags.4?int" }, { "name": "migrated_from_max_id", "type": "flags.4?int" }, { "name": "pinned_msg_id", "type": "flags.5?int" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "-352032773", "predicate": "updateChannelTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "channel_id", "type": "int" }, { "name": "pts", "type": "flags.0?int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1016324548", "predicate": "updateChannelGroup", "params": [ { "name": "channel_id", "type": "int" }, { "name": "group", "type": "MessageGroup" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "exclude_new_messages", "type": "flags.1?true" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" }, { "id": "-100588754", "predicate": "channelMessagesFilterCollapsed", "params": [], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipant" }, { "id": "-636267638", "predicate": "chatParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-489233354", "predicate": "chatParticipantAdmin", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "1855224129", "predicate": "updateChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1232070311", "predicate": "updateChatParticipantAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "is_admin", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1371385889", "predicate": "messageActionChatMigrateTo", "params": [ { "name": "channel_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1336546578", "predicate": "messageActionChannelMigrateFrom", "params": [ { "name": "title", "type": "string" }, { "name": "chat_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1328445861", "predicate": "channelParticipantsBots", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-236044656", "predicate": "help.termsOfService", "params": [ { "name": "text", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "1753886890", "predicate": "updateNewStickerSet", "params": [ { "name": "stickerset", "type": "messages.StickerSet" } ], "type": "Update" }, { "id": "-253774767", "predicate": "updateStickerSetsOrder", "params": [ { "name": "order", "type": "Vector" } ], "type": "Update" }, { "id": "1135492588", "predicate": "updateStickerSets", "params": [], "type": "Update" }, { "id": "372165663", "predicate": "foundGif", "params": [ { "name": "url", "type": "string" }, { "name": "thumb_url", "type": "string" }, { "name": "content_url", "type": "string" }, { "name": "content_type", "type": "string" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "FoundGif" }, { "id": "-1670052855", "predicate": "foundGifCached", "params": [ { "name": "url", "type": "string" }, { "name": "photo", "type": "Photo" }, { "name": "document", "type": "Document" } ], "type": "FoundGif" }, { "id": "1212395773", "predicate": "inputMediaGifExternal", "params": [ { "name": "url", "type": "string" }, { "name": "q", "type": "string" } ], "type": "InputMedia" }, { "id": "1158290442", "predicate": "messages.foundGifs", "params": [ { "name": "next_offset", "type": "int" }, { "name": "results", "type": "Vector" } ], "type": "messages.FoundGifs" }, { "id": "-402498398", "predicate": "messages.savedGifsNotModified", "params": [], "type": "messages.SavedGifs" }, { "id": "772213157", "predicate": "messages.savedGifs", "params": [ { "name": "hash", "type": "int" }, { "name": "gifs", "type": "Vector" } ], "type": "messages.SavedGifs" }, { "id": "-1821035490", "predicate": "updateSavedGifs", "params": [], "type": "Update" }, { "id": "691006739", "predicate": "inputBotInlineMessageMediaAuto", "params": [ { "name": "flags", "type": "#" }, { "name": "caption", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "1036876423", "predicate": "inputBotInlineMessageText", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.0?true" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.1?Vector" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "750510426", "predicate": "inputBotInlineResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "url", "type": "flags.3?string" }, { "name": "thumb_url", "type": "flags.4?string" }, { "name": "content_url", "type": "flags.5?string" }, { "name": "content_type", "type": "flags.5?string" }, { "name": "w", "type": "flags.6?int" }, { "name": "h", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "175419739", "predicate": "botInlineMessageMediaAuto", "params": [ { "name": "flags", "type": "#" }, { "name": "caption", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "-1937807902", "predicate": "botInlineMessageText", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.0?true" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.1?Vector" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "-1679053127", "predicate": "botInlineResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "url", "type": "flags.3?string" }, { "name": "thumb_url", "type": "flags.4?string" }, { "name": "content_url", "type": "flags.5?string" }, { "name": "content_type", "type": "flags.5?string" }, { "name": "w", "type": "flags.6?int" }, { "name": "h", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "627509670", "predicate": "messages.botResults", "params": [ { "name": "flags", "type": "#" }, { "name": "gallery", "type": "flags.0?true" }, { "name": "query_id", "type": "long" }, { "name": "next_offset", "type": "flags.1?string" }, { "name": "switch_pm", "type": "flags.2?InlineBotSwitchPM" }, { "name": "results", "type": "Vector" } ], "type": "messages.BotResults" }, { "id": "1417832080", "predicate": "updateBotInlineQuery", "params": [ { "name": "flags", "type": "#" }, { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "query", "type": "string" }, { "name": "geo", "type": "flags.0?GeoPoint" }, { "name": "offset", "type": "string" } ], "type": "Update" }, { "id": "239663460", "predicate": "updateBotInlineSend", "params": [ { "name": "flags", "type": "#" }, { "name": "user_id", "type": "int" }, { "name": "query", "type": "string" }, { "name": "geo", "type": "flags.0?GeoPoint" }, { "name": "id", "type": "string" }, { "name": "msg_id", "type": "flags.1?InputBotInlineMessageID" } ], "type": "Update" }, { "id": "1358283666", "predicate": "inputMessagesFilterVoice", "params": [], "type": "MessagesFilter" }, { "id": "928101534", "predicate": "inputMessagesFilterMusic", "params": [], "type": "MessagesFilter" }, { "id": "-1107622874", "predicate": "inputPrivacyKeyChatInvite", "params": [], "type": "InputPrivacyKey" }, { "id": "1343122938", "predicate": "privacyKeyChatInvite", "params": [], "type": "PrivacyKey" }, { "id": "524838915", "predicate": "exportedMessageLink", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedMessageLink" }, { "id": "-947462709", "predicate": "messageFwdHeader", "params": [ { "name": "flags", "type": "#" }, { "name": "from_id", "type": "flags.0?int" }, { "name": "date", "type": "int" }, { "name": "channel_id", "type": "flags.1?int" }, { "name": "channel_post", "type": "flags.2?int" } ], "type": "MessageFwdHeader" }, { "id": "457133559", "predicate": "updateEditChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1738988427", "predicate": "updateChannelPinnedMessage", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" } ], "type": "Update" }, { "id": "-1799538451", "predicate": "messageActionPinMessage", "params": [], "type": "MessageAction" }, { "id": "1923290508", "predicate": "auth.codeTypeSms", "params": [], "type": "auth.CodeType" }, { "id": "1948046307", "predicate": "auth.codeTypeCall", "params": [], "type": "auth.CodeType" }, { "id": "577556219", "predicate": "auth.codeTypeFlashCall", "params": [], "type": "auth.CodeType" }, { "id": "1035688326", "predicate": "auth.sentCodeTypeApp", "params": [ { "name": "length", "type": "int" } ], "type": "auth.SentCodeType" }, { "id": "-1073693790", "predicate": "auth.sentCodeTypeSms", "params": [ { "name": "length", "type": "int" } ], "type": "auth.SentCodeType" }, { "id": "1398007207", "predicate": "auth.sentCodeTypeCall", "params": [ { "name": "length", "type": "int" } ], "type": "auth.SentCodeType" }, { "id": "-1425815847", "predicate": "auth.sentCodeTypeFlashCall", "params": [ { "name": "pattern", "type": "string" } ], "type": "auth.SentCodeType" }, { "id": "1577067778", "predicate": "auth.sentCode", "params": [ { "name": "flags", "type": "#" }, { "name": "phone_registered", "type": "flags.0?true" }, { "name": "type", "type": "auth.SentCodeType" }, { "name": "phone_code_hash", "type": "string" }, { "name": "next_type", "type": "flags.1?auth.CodeType" }, { "name": "timeout", "type": "flags.2?int" } ], "type": "auth.SentCode" }, { "id": "629866245", "predicate": "keyboardButtonUrl", "params": [ { "name": "text", "type": "string" }, { "name": "url", "type": "string" } ], "type": "KeyboardButton" }, { "id": "1748655686", "predicate": "keyboardButtonCallback", "params": [ { "name": "text", "type": "string" }, { "name": "data", "type": "bytes" } ], "type": "KeyboardButton" }, { "id": "-1318425559", "predicate": "keyboardButtonRequestPhone", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "-59151553", "predicate": "keyboardButtonRequestGeoLocation", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "-367298028", "predicate": "keyboardButtonSwitchInline", "params": [ { "name": "text", "type": "string" }, { "name": "query", "type": "string" } ], "type": "KeyboardButton" }, { "id": "1218642516", "predicate": "replyInlineMarkup", "params": [ { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "308605382", "predicate": "messages.botCallbackAnswer", "params": [ { "name": "flags", "type": "#" }, { "name": "alert", "type": "flags.1?true" }, { "name": "message", "type": "flags.0?string" } ], "type": "messages.BotCallbackAnswer" }, { "id": "-1500747636", "predicate": "updateBotCallbackQuery", "params": [ { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "peer", "type": "Peer" }, { "name": "msg_id", "type": "int" }, { "name": "data", "type": "bytes" } ], "type": "Update" }, { "id": "649453030", "predicate": "messages.messageEditData", "params": [ { "name": "flags", "type": "#" }, { "name": "caption", "type": "flags.0?true" } ], "type": "messages.MessageEditData" }, { "id": "-469536605", "predicate": "updateEditMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-190472735", "predicate": "inputBotInlineMessageMediaGeo", "params": [ { "name": "flags", "type": "#" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "-1431327288", "predicate": "inputBotInlineMessageMediaVenue", "params": [ { "name": "flags", "type": "#" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "766443943", "predicate": "inputBotInlineMessageMediaContact", "params": [ { "name": "flags", "type": "#" }, { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "982505656", "predicate": "botInlineMessageMediaGeo", "params": [ { "name": "flags", "type": "#" }, { "name": "geo", "type": "GeoPoint" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "1130767150", "predicate": "botInlineMessageMediaVenue", "params": [ { "name": "flags", "type": "#" }, { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "904770772", "predicate": "botInlineMessageMediaContact", "params": [ { "name": "flags", "type": "#" }, { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "-1462213465", "predicate": "inputBotInlineResultPhoto", "params": [ { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "photo", "type": "InputPhoto" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "-459324", "predicate": "inputBotInlineResultDocument", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "document", "type": "InputDocument" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "400266251", "predicate": "botInlineMediaResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "photo", "type": "flags.0?Photo" }, { "name": "document", "type": "flags.1?Document" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "-1995686519", "predicate": "inputBotInlineMessageID", "params": [ { "name": "dc_id", "type": "int" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputBotInlineMessageID" }, { "id": "750622127", "predicate": "updateInlineBotCallbackQuery", "params": [ { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "msg_id", "type": "InputBotInlineMessageID" }, { "name": "data", "type": "bytes" } ], "type": "Update" }, { "id": "1008755359", "predicate": "inlineBotSwitchPM", "params": [ { "name": "text", "type": "string" }, { "name": "start_param", "type": "string" } ], "type": "InlineBotSwitchPM" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "-855805745", "method": "auth.sendCode", "params": [ { "name": "flags", "type": "#" }, { "name": "allow_flashcall", "type": "flags.0?true" }, { "name": "phone_number", "type": "string" }, { "name": "current_number", "type": "flags.0?Bool" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "2018596725", "method": "account.updateProfile", "params": [ { "name": "flags", "type": "#" }, { "name": "first_name", "type": "flags.0?string" }, { "name": "last_name", "type": "flags.1?string" }, { "name": "about", "type": "flags.2?string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "-1374118561", "method": "account.reportPeer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reason", "type": "ReportReason" } ], "type": "Bool" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1799878989", "method": "messages.getDialogs", "params": [ { "name": "offset_date", "type": "int" }, { "name": "offset_id", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1347868602", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "offset_date", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "238054714", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "-1212072999", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "-1460572005", "method": "messages.hideReportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "913498268", "method": "messages.getPeerSettings", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "PeerSettings" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "149257707", "method": "account.sendChangePhoneCode", "params": [ { "name": "flags", "type": "#" }, { "name": "allow_flashcall", "type": "flags.0?true" }, { "name": "phone_number", "type": "string" }, { "name": "current_number", "type": "flags.0?Bool" } ], "type": "auth.SentCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "479598769", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-421563528", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "increment", "type": "Bool" } ], "type": "Vector" }, { "id": "-1445735863", "method": "channels.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1891021902", "method": "channels.getImportantHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "offset_id", "type": "int" }, { "name": "offset_date", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "-192332417", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.0?true" }, { "name": "megagroup", "type": "flags.1?true" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "-344583728", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Updates" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-1432183160", "method": "channels.toggleComments", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" }, { "id": "-326379039", "method": "messages.toggleChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1444503762", "method": "messages.editChatAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "is_admin", "type": "Bool" } ], "type": "Bool" }, { "id": "363051235", "method": "messages.migrateChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Updates" }, { "id": "-1640190800", "method": "messages.searchGlobal", "params": [ { "name": "q", "type": "string" }, { "name": "offset_date", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "936873859", "method": "help.getTermsOfService", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "-1613775824", "method": "messages.reorderStickerSets", "params": [ { "name": "order", "type": "Vector" } ], "type": "Bool" }, { "id": "864953444", "method": "messages.getDocumentByHash", "params": [ { "name": "sha256", "type": "bytes" }, { "name": "size", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "Document" }, { "id": "-1080395925", "method": "messages.searchGifs", "params": [ { "name": "q", "type": "string" }, { "name": "offset", "type": "int" } ], "type": "messages.FoundGifs" }, { "id": "-2084618926", "method": "messages.getSavedGifs", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.SavedGifs" }, { "id": "846868683", "method": "messages.saveGif", "params": [ { "name": "id", "type": "InputDocument" }, { "name": "unsave", "type": "Bool" } ], "type": "Bool" }, { "id": "1364105629", "method": "messages.getInlineBotResults", "params": [ { "name": "flags", "type": "#" }, { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "geo_point", "type": "flags.0?InputGeoPoint" }, { "name": "query", "type": "string" }, { "name": "offset", "type": "string" } ], "type": "messages.BotResults" }, { "id": "-346119674", "method": "messages.setInlineBotResults", "params": [ { "name": "flags", "type": "#" }, { "name": "gallery", "type": "flags.0?true" }, { "name": "private", "type": "flags.1?true" }, { "name": "query_id", "type": "long" }, { "name": "results", "type": "Vector" }, { "name": "cache_time", "type": "int" }, { "name": "next_offset", "type": "flags.2?string" }, { "name": "switch_pm", "type": "flags.3?InlineBotSwitchPM" } ], "type": "Bool" }, { "id": "-1318189314", "method": "messages.sendInlineBotResult", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "random_id", "type": "long" }, { "name": "query_id", "type": "long" }, { "name": "id", "type": "string" } ], "type": "Updates" }, { "id": "1231065863", "method": "channels.toggleInvites", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-934882771", "method": "channels.exportMessageLink", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "int" } ], "type": "ExportedMessageLink" }, { "id": "527021574", "method": "channels.toggleSignatures", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1490162350", "method": "channels.updatePinnedMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "silent", "type": "flags.0?true" }, { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "int" } ], "type": "Updates" }, { "id": "1056025023", "method": "auth.resendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "auth.SentCode" }, { "id": "520357240", "method": "auth.cancelCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "-39416522", "method": "messages.getMessageEditData", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" } ], "type": "messages.MessageEditData" }, { "id": "-829299510", "method": "messages.editMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "message", "type": "flags.11?string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "319564933", "method": "messages.editInlineBotMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "id", "type": "InputBotInlineMessageID" }, { "name": "message", "type": "flags.11?string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Bool" }, { "id": "-1494659324", "method": "messages.getBotCallbackAnswer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "msg_id", "type": "int" }, { "name": "data", "type": "bytes" } ], "type": "messages.BotCallbackAnswer" }, { "id": "1209817370", "method": "messages.setBotCallbackAnswer", "params": [ { "name": "flags", "type": "#" }, { "name": "alert", "type": "flags.1?true" }, { "name": "query_id", "type": "long" }, { "name": "message", "type": "flags.0?string" } ], "type": "Bool" } ] }. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Connection; use danog\MadelineProto\Connection; use danog\MadelineProto\Logger; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Magic; use danog\MadelineProto\MTProtoTools\Crypt; use danog\MadelineProto\Tools; /** * Socket write loop. * * @author Daniil Gentili */ class WriteLoop extends ResumableSignalLoop { use Crypt; use Tools; protected $connection; protected $datacenter; public function __construct($API, $datacenter) { $this->API = $API; $this->datacenter = $datacenter; $this->connection = $API->datacenter->sockets[$datacenter]; } public function loop(): \Generator { $API = $this->API; $connection = $this->connection; $datacenter = $this->datacenter; $please_wait = false; while (true) { while (empty($connection->pending_outgoing) || $please_wait) { $please_wait = false; $API->logger->logger("Waiting in $this", Logger::ULTRA_VERBOSE); if (yield $this->waitSignal($this->pause())) { return; } $API->logger->logger("Done waiting in $this", Logger::ULTRA_VERBOSE); } try { $please_wait = yield $this->{$connection->temp_auth_key === null ? 'unencryptedWriteLoopAsync' : 'encryptedWriteLoopAsync'}(); } catch (\Amp\ByteStream\StreamException $e) { if (isset($connection->old)) { return; } $API->logger($e); $API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR); yield $connection->reconnect(); continue; } //$connection->waiter->resume(); } } public function unencryptedWriteLoopAsync() { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; while ($connection->pending_outgoing) { $skipped_all = true; foreach ($connection->pending_outgoing as $k => $message) { if ($connection->temp_auth_key !== null) { return; } if (!$message['unencrypted']) { continue; } $skipped_all = false; $API->logger->logger("Sending {$message['_']} as unencrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generate_message_id(); $length = strlen($message['serialized_body']); $pad_length = -$length & 15; $pad_length += 16 * $this->random_int($modulus = 16); $pad = $this->random($pad_length); $buffer = yield $connection->stream->getWriteBuffer(8 + 8 + 4 + $pad_length + $length); yield $buffer->bufferWrite("\0\0\0\0\0\0\0\0".$message_id.$this->pack_unsigned_int($length).$message['serialized_body'].$pad); //var_dump("plain ".bin2hex($message_id)); $connection->http_req_count++; $connection->outgoing_messages[$message_id] = $message; $connection->outgoing_messages[$message_id]['sent'] = time(); $connection->outgoing_messages[$message_id]['tries'] = 0; $connection->outgoing_messages[$message_id]['unencrypted'] = true; $connection->new_outgoing[$message_id] = $message_id; unset($connection->pending_outgoing[$k]); $API->logger->logger("Sent {$message['_']} as unencrypted message to DC {$datacenter}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $message['send_promise']->resolve(isset($message['promise']) ? $message['promise'] : true); unset($message['send_promise']); } if ($skipped_all) { return true; } } } public function encryptedWriteLoopAsync(): \Generator { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all'; do { if ($connection->temp_auth_key === null) { return; } if ($this->API->is_http($datacenter) && empty($connection->pending_outgoing)) { return; } if (count($to_ack = $connection->ack_queue)) { foreach (array_chunk($connection->ack_queue, 8192) as $acks) { $connection->pending_outgoing[$connection->pending_outgoing_key++] = ['_' => 'msgs_ack', 'serialized_body' => yield $this->API->serialize_object_async(['type' => 'msgs_ack'], ['msg_ids' => $acks], 'msgs_ack'), 'content_related' => false, 'unencrypted' => false, 'method' => false]; $connection->pending_outgoing_key %= Connection::PENDING_MAX; } } $has_http_wait = false; $messages = []; $keys = []; foreach ($connection->pending_outgoing as $message) { if ($message['_'] === 'http_wait') { $has_http_wait = true; break; } } if ($API->is_http($datacenter) && !$has_http_wait) { $connection->pending_outgoing[$connection->pending_outgoing_key++] = ['_' => 'http_wait', 'serialized_body' => yield $this->API->serialize_object_async(['type' => ''], ['_' => 'http_wait', 'max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'http_wait'), 'content_related' => true, 'unencrypted' => false, 'method' => true]; $connection->pending_outgoing_key %= Connection::PENDING_MAX; $has_http_wait = true; } $total_length = 0; $count = 0; ksort($connection->pending_outgoing); $skipped = false; foreach ($connection->pending_outgoing as $k => $message) { if ($message['unencrypted']) { continue; } if (isset($message['container'])) { unset($connection->pending_outgoing[$k]); continue; } if ($API->settings['connection_settings'][$dc_config_number]['pfs'] && !isset($connection->temp_auth_key['bound']) && !strpos($datacenter, 'cdn') && !in_array($message['_'], ['http_wait', 'auth.bindTempAuthKey']) && $message['method']) { $API->logger->logger("Skipping {$message['_']} due to unbound keys in DC {$datacenter}"); $skipped = true; continue; } $body_length = strlen($message['serialized_body']); $actual_length = $body_length + 32; if ($total_length && $total_length + $actual_length > 32760 || $count >= 1020) { $API->logger->logger('Length overflow, postponing part of payload', \danog\MadelineProto\Logger::NOTICE); break; } $message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generate_message_id($datacenter); $API->logger->logger("Sending {$message['_']} as encrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $message['serialized_body'], 'seqno' => $connection->generate_out_seq_no($message['content_related'])]; if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') { if ((!isset($connection->temp_auth_key['connection_inited']) || $connection->temp_auth_key['connection_inited'] === false) && $message['_'] !== 'auth.bindTempAuthKey') { $API->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['write_client_info'], $message['_']), \danog\MadelineProto\Logger::NOTICE); $MTmessage['body'] = yield $API->serialize_method_async( 'invokeWithLayer', [ 'layer' => $API->settings['tl_schema']['layer'], 'query' => yield $API->serialize_method_async( 'initConnection', [ 'api_id' => $API->settings['app_info']['api_id'], 'api_hash' => $API->settings['app_info']['api_hash'], 'device_model' => strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['device_model'] : 'n/a', 'system_version' => strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['system_version'] : 'n/a', 'app_version' => $API->settings['app_info']['app_version'], 'system_lang_code' => $API->settings['app_info']['lang_code'], 'lang_code' => $API->settings['app_info']['lang_code'], 'lang_pack' => $API->settings['app_info']['lang_pack'], 'query' => $MTmessage['body'], ] ), ] ); } else { if (isset($message['queue'])) { if (!isset($connection->call_queue[$message['queue']])) { $connection->call_queue[$message['queue']] = []; } $MTmessage['body'] = yield $API->serialize_method_async('invokeAfterMsgs', ['msg_ids' => $connection->call_queue[$message['queue']], 'query' => $MTmessage['body']]); $connection->call_queue[$message['queue']][$message_id] = $message_id; if (count($connection->call_queue[$message['queue']]) > $API->settings['msg_array_limit']['call_queue']) { reset($connection->call_queue[$message['queue']]); $key = key($connection->call_queue[$message['queue']]); unset($connection->call_queue[$message['queue']][$key]); } } // TODO /* if ($API->settings['requests']['gzip_encode_if_gt'] !== -1 && ($l = strlen($MTmessage['body'])) > $API->settings['requests']['gzip_encode_if_gt']) { if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) { $MTmessage['body'] = yield $API->serialize_object_async(['type' => 'gzip_packed'], ['packed_data' => $gzipped], 'gzipped data'); $API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } unset($gzipped); }*/ } } $body_length = strlen($MTmessage['body']); $actual_length = $body_length + 32; if ($total_length && $total_length + $actual_length > 32760) { $API->logger->logger('Length overflow, postponing part of payload', \danog\MadelineProto\Logger::NOTICE); break; } $count++; $total_length += $actual_length; $MTmessage['bytes'] = $body_length; $messages[] = $MTmessage; $keys[$k] = $message_id; } $MTmessage = null; if ($count > 1) { $API->logger->logger("Wrapping in msg_container ($count messages of total size $total_length) as encrypted message for DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $message_id = $connection->generate_message_id($datacenter); $connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => array_values($keys), 'content_related' => false, 'method' => false, 'unencrypted' => false]; //var_dumP("container ".bin2hex($message_id)); $keys[$connection->pending_outgoing_key++] = $message_id; $connection->pending_outgoing_key %= Connection::PENDING_MAX; $message_data = yield $API->serialize_object_async(['type' => ''], ['_' => 'msg_container', 'messages' => $messages], 'container'); $message_data_length = strlen($message_data); $seq_no = $connection->generate_out_seq_no(false); } elseif ($count) { $message = $messages[0]; $message_data = $message['body']; $message_data_length = $message['bytes']; $message_id = $message['msg_id']; $seq_no = $message['seqno']; } else { $API->logger->logger("NO MESSAGE SENT in DC $datacenter", \danog\MadelineProto\Logger::WARNING); return true; } unset($messages); $plaintext = $connection->temp_auth_key['server_salt'].$connection->session_id.$message_id.pack('VV', $seq_no, $message_data_length).$message_data; $padding = $this->posmod(-strlen($plaintext), 16); if ($padding < 12) { $padding += 16; } $padding = $this->random($padding); $message_key = substr(hash('sha256', substr($connection->temp_auth_key['auth_key'], 88, 32).$plaintext.$padding, true), 8, 16); list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $connection->temp_auth_key['auth_key']); $message = $connection->temp_auth_key['id'].$message_key.$this->ige_encrypt($plaintext.$padding, $aes_key, $aes_iv); $buffer = yield $connection->stream->getWriteBuffer($len = strlen($message)); $t = microtime(true); yield $buffer->bufferWrite($message); $connection->http_req_count++; $API->logger->logger("Sent encrypted payload to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $sent = time(); if ($to_ack) { $connection->ack_queue = []; } if ($has_http_wait) { $connection->last_http_wait = $sent; } elseif (Magic::$altervista) { $connection->last_http_wait = PHP_INT_MAX; } foreach ($keys as $key => $message_id) { $connection->outgoing_messages[$message_id] = &$connection->pending_outgoing[$key]; if (isset($connection->outgoing_messages[$message_id]['promise'])) { $connection->new_outgoing[$message_id] = $message_id; $connection->outgoing_messages[$message_id]['sent'] = $sent; $connection->outgoing_messages[$message_id]['tries'] = 0; } if (isset($connection->outgoing_messages[$message_id]['send_promise'])) { $connection->outgoing_messages[$message_id]['send_promise']->resolve(isset($connection->outgoing_messages[$message_id]['promise']) ? $connection->outgoing_messages[$message_id]['promise'] : true); unset($connection->outgoing_messages[$message_id]['send_promise']); } //var_dumP("encrypted ".bin2hex($message_id)." ".$connection->outgoing_messages[$message_id]['_']); unset($connection->pending_outgoing[$key]); } //if (!empty($connection->pending_outgoing)) $connection->select(); } while (!empty($connection->pending_outgoing) && !$skipped); $connection->pending_outgoing_key = 0; return $skipped; } public function __toString(): string { return "write loop in DC {$this->datacenter}"; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Connection; use Amp\Deferred; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; /** * RPC call status check loop. * * @author Daniil Gentili */ class CheckLoop extends ResumableSignalLoop { protected $connection; protected $datacenter; public function __construct($API, $datacenter) { $this->API = $API; $this->datacenter = $datacenter; $this->connection = $API->datacenter->sockets[$datacenter]; } public function loop() { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; $dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all'; $timeout = $API->settings['connection_settings'][$dc_config_number]['timeout']; while (true) { while (empty($connection->new_outgoing)) { if (yield $this->waitSignal($this->pause())) { return; } } if ($connection->hasPendingCalls()) { $last_recv = $connection->get_max_id(true); if ($connection->temp_auth_key !== null) { $full_message_ids = $connection->getPendingCalls(); //array_values($connection->new_outgoing); foreach (array_chunk($full_message_ids, 8192) as $message_ids) { $deferred = new Deferred(); $deferred->promise()->onResolve( function ($e, $result) use ($message_ids, $API, $connection, $datacenter) { if ($e) { $API->logger("Got exception in check loop for DC $datacenter"); $API->logger((string) $e); return; } $reply = []; foreach (str_split($result['info']) as $key => $chr) { $message_id = $message_ids[$key]; if (!isset($connection->outgoing_messages[$message_id])) { $API->logger->logger('Already got response for and forgot about message ID '.($message_id)); continue; } if (!isset($connection->new_outgoing[$message_id])) { $API->logger->logger('Already got response for '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id)); continue; } $chr = ord($chr); switch ($chr & 7) { case 0: $API->logger->logger('Wrong message status 0 for '.$connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR); break; case 1: case 2: case 3: if ($connection->outgoing_messages[$message_id]['_'] === 'msgs_state_req') { $API->got_response_for_outgoing_message_id($message_id, $datacenter); break; } $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' not received by server, resending...', \danog\MadelineProto\Logger::ERROR); $API->method_recall('watcherId', ['message_id' => $message_id, 'datacenter' => $datacenter, 'postpone' => true]); break; case 4: if ($chr & 32) { $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR); } elseif ($chr & 64) { $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR); $reply[] = $message_id; } elseif ($chr & 128) { $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR); $reply[] = $message_id; } else { $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.($message_id).' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR); $reply[] = $message_id; } } } if ($reply) { $this->callFork($API->object_call_async('msg_resend_ans_req', ['msg_ids' => $reply], ['datacenter' => $datacenter, 'postpone' => true])); } $connection->writer->resume(); } ); $list = ''; // Don't edit this here pls foreach ($message_ids as $message_id) { $list .= $connection->outgoing_messages[$message_id]['_'].', '; } $API->logger->logger("Still missing $list on DC $datacenter, sending state request", \danog\MadelineProto\Logger::ERROR); yield $API->object_call_async('msgs_state_req', ['msg_ids' => $message_ids], ['datacenter' => $datacenter, 'promise' => $deferred]); } } else { foreach ($connection->new_outgoing as $message_id) { if (isset($connection->outgoing_messages[$message_id]['sent']) && $connection->outgoing_messages[$message_id]['sent'] + $timeout < time() && $connection->outgoing_messages[$message_id]['unencrypted'] ) { $API->logger->logger('Still missing '.$connection->outgoing_messages[$message_id]['_'].' with message id '.($message_id)." on DC $datacenter, resending", \danog\MadelineProto\Logger::ERROR); $API->method_recall('', ['message_id' => $message_id, 'datacenter' => $datacenter, 'postpone' => true]); } } $connection->writer->resume(); } if (yield $this->waitSignal($this->pause($timeout))) { return; } if ($connection->get_max_id(true) === $last_recv) { $API->logger->logger("We did not receive a response for $timeout seconds: reconnecting and exiting check loop on DC $datacenter"); $this->exitedLoop(); yield $connection->reconnect(); return; } } else { if (yield $this->waitSignal($this->pause($timeout))) { return; } } } } public function __toString(): string { return "check loop in DC {$this->datacenter}"; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Connection; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpStream; /** * HttpWait loop. * * @author Daniil Gentili */ class HttpWaitLoop extends ResumableSignalLoop { protected $connection; protected $datacenter; public function __construct($API, $datacenter) { $this->API = $API; $this->datacenter = $datacenter; $this->connection = $API->datacenter->sockets[$datacenter]; } public function loop() { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; if (!in_array($connection->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()])) { return; } $timeout = $API->settings['connection_settings'][isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all']['timeout']; while (true) { if (yield $this->waitSignal($this->pause())) { return; } if (!in_array($connection->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()])) { return; } while ($connection->temp_auth_key === null) { if (yield $this->waitSignal($this->pause())) { return; } } $API->logger->logger("DC $datacenter: request {$connection->http_req_count}, response {$connection->http_res_count}"); if ($connection->http_req_count === $connection->http_res_count && (!empty($connection->pending_outgoing) || (!empty($connection->new_outgoing) && !$connection->hasPendingCalls()))) { yield $connection->sendMessage(['_' => 'http_wait', 'body' => ['max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'content_related' => true, 'unencrypted' => false, 'method' => false]); } $API->logger->logger("DC $datacenter: request {$connection->http_req_count}, response {$connection->http_res_count}"); } } public function __toString(): string { return "HTTP wait loop in DC {$this->datacenter}"; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Connection; use Amp\Loop; use Amp\Websocket\ClosedException; use danog\MadelineProto\Logger; use danog\MadelineProto\Loop\Impl\SignalLoop; use danog\MadelineProto\MTProtoTools\Crypt; use danog\MadelineProto\NothingInTheSocketException; use danog\MadelineProto\Tools; /** * Socket read loop. * * @author Daniil Gentili */ class ReadLoop extends SignalLoop { use Tools; use Crypt; protected $connection; protected $datacenter; public function __construct($API, $datacenter) { $this->API = $API; $this->datacenter = $datacenter; $this->connection = $API->datacenter->sockets[$datacenter]; } public function loop() { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; //$timeout = $API->settings['connection_settings'][isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all']['timeout']; while (true) { try { $error = yield $this->waitSignal($this->readMessage()); } catch (NothingInTheSocketException $e) { if (isset($connection->old)) { return; } $API->logger->logger("Got nothing in the socket in DC {$datacenter}, reconnecting...", Logger::ERROR); yield $connection->reconnect(); continue; } catch (ClosedException $e) { $API->logger->logger($e->getMessage(), Logger::FATAL_ERROR); throw $e; } if (is_int($error)) { $this->exitedLoop(); if ($error === -404) { if ($connection->temp_auth_key !== null) { $API->logger->logger("WARNING: Resetting auth key in DC {$datacenter}...", \danog\MadelineProto\Logger::WARNING); $connection->temp_auth_key = null; $connection->session_id = null; foreach ($connection->new_outgoing as $message_id) { $connection->outgoing_messages[$message_id]['sent'] = 0; } yield $connection->reconnect(); yield $API->init_authorization_async(); } else { yield $connection->reconnect(); } } elseif ($error === -1) { yield $connection->reconnect(); $API->logger->logger("WARNING: Got quick ack from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING); } elseif ($error === 0) { yield $connection->reconnect(); $API->logger->logger("Got NOOP from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING); } else { yield $connection->reconnect(); throw new \danog\MadelineProto\RPCErrorException($error, $error); } return; } $connection->http_res_count++; Loop::defer([$API, 'handle_messages'], $datacenter); if ($this->API->is_http($datacenter)) { Loop::defer([$connection->waiter, 'resume']); } } } public function readMessage() { $API = $this->API; $datacenter = $this->datacenter; $connection = $this->connection; if (isset($this->connection->old)) { $API->logger->logger('Not reading because connection is old'); throw new NothingInTheSocketException(); } try { $buffer = yield $connection->stream->getReadBuffer($payload_length); } catch (ClosedException $e) { $API->logger->logger($e->getReason()); if (strpos($e->getReason(), ' ') === 0) { $payload = -substr($e->getReason(), 7); $API->logger->logger("Received $payload from DC ".$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); return $payload; } throw $e; } if ($payload_length === 4) { $payload = $this->unpack_signed_int(yield $buffer->bufferRead(4)); $API->logger->logger("Received $payload from DC ".$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); return $payload; } $auth_key_id = yield $buffer->bufferRead(8); if ($auth_key_id === "\0\0\0\0\0\0\0\0") { $message_id = yield $buffer->bufferRead(8); if (!in_array($message_id, [1, 0])) { $connection->check_message_id($message_id, ['outgoing' => false, 'container' => false]); } $message_length = unpack('V', yield $buffer->bufferRead(4))[1]; $message_data = yield $buffer->bufferRead($message_length); $left = $payload_length - $message_length - 4 - 8 - 8; if ($left) { $API->logger->logger('Padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($left < (-$message_length & 15)) { $API->logger->logger('Protocol padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } yield $buffer->bufferRead($left); } $connection->incoming_messages[$message_id] = []; } elseif ($auth_key_id === $connection->temp_auth_key['id']) { $message_key = yield $buffer->bufferRead(16); list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $connection->temp_auth_key['auth_key'], false); $encrypted_data = yield $buffer->bufferRead($payload_length - 24); $protocol_padding = strlen($encrypted_data) % 16; if ($protocol_padding) { $encrypted_data = substr($encrypted_data, 0, -$protocol_padding); } $decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv); /* $server_salt = substr($decrypted_data, 0, 8); if ($server_salt != $connection->temp_auth_key['server_salt']) { $API->logger->logger('WARNING: Server salt mismatch (my server salt '.$connection->temp_auth_key['server_salt'].' is not equal to server server salt '.$server_salt.').', \danog\MadelineProto\Logger::WARNING); } */ $session_id = substr($decrypted_data, 8, 8); if ($session_id != $connection->session_id) { throw new \danog\MadelineProto\Exception('Session id mismatch.'); } $message_id = substr($decrypted_data, 16, 8); $connection->check_message_id($message_id, ['outgoing' => false, 'container' => false]); $seq_no = unpack('V', substr($decrypted_data, 24, 4))[1]; $message_data_length = unpack('V', substr($decrypted_data, 28, 4))[1]; if ($message_data_length > strlen($decrypted_data)) { throw new \danog\MadelineProto\SecurityException('message_data_length is too big'); } if (strlen($decrypted_data) - 32 - $message_data_length < 12) { throw new \danog\MadelineProto\SecurityException('padding is too small'); } if (strlen($decrypted_data) - 32 - $message_data_length > 1024) { throw new \danog\MadelineProto\SecurityException('padding is too big'); } if ($message_data_length < 0) { throw new \danog\MadelineProto\SecurityException('message_data_length not positive'); } if ($message_data_length % 4 != 0) { throw new \danog\MadelineProto\SecurityException('message_data_length not divisible by 4'); } $message_data = substr($decrypted_data, 32, $message_data_length); if ($message_key != substr(hash('sha256', substr($connection->temp_auth_key['auth_key'], 96, 32).$decrypted_data, true), 8, 16)) { throw new \danog\MadelineProto\SecurityException('msg_key mismatch'); } $connection->incoming_messages[$message_id] = ['seq_no' => $seq_no]; } else { $API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR); return -404; } $deserialized = $API->deserialize($message_data, ['type' => '', 'datacenter' => $datacenter]); $API->referenceDatabase->reset(); $connection->incoming_messages[$message_id]['content'] = $deserialized; $connection->incoming_messages[$message_id]['response'] = -1; $connection->new_incoming[$message_id] = $message_id; $connection->last_recv = time(); $connection->last_http_wait = 0; $API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); return true; } public function __toString(): string { return "read loop in DC {$this->datacenter}"; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop; use Amp\Promise; /** * Signal loop interface. * * @author Daniil Gentili */ interface SignalLoopInterface extends LoopInterface { /** * Resolve the promise or return|throw the signal. * * @param Promise $promise The origin promise * * @return Promise */ public function waitSignal($promise): Promise; /** * Send a signal to the the loop. * * @param Exception|any $data Signal to send * * @return void */ public function signal($data); } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop; /** * Loop interface. * * @author Daniil Gentili */ interface LoopInterface { /** * Start the loop. * * @return void */ public function start(); /** * The actual loop. * * @return void */ public function loop(); /** * Get name of the loop. * * @return string */ public function __toString(): string; } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop; use Amp\Promise; /** * Resumable loop interface. * * @author Daniil Gentili */ interface ResumableLoopInterface extends LoopInterface { /** * Pause the loop. * * @param int $time For how long to pause the loop, if null will pause forever (until resume is called from outside of the loop) * * @return Promise */ public function pause($time = null): Promise; /** * Resume the loop. * * @return void */ public function resume(); } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Impl; use Amp\Promise; use danog\MadelineProto\Logger; use danog\MadelineProto\Loop\LoopInterface; /** * Loop helper trait. * * Wraps the asynchronous generator methods with asynchronous promise-based methods * * @author Daniil Gentili */ abstract class Loop implements LoopInterface { use \danog\MadelineProto\Tools; private $count = 0; public $API; public function __construct($API) { $this->API = $API; } public function start() { if ($this->count) { //$this->API->logger->logger("NOT entering $this with running count {$this->count}", Logger::ERROR); return false; } return $this->callFork($this->loopImpl()); } private function loopImpl() { //yield ['my_trace' => debug_backtrace(0, 1)[0], (string) $this]; $this->startedLoop(); $this->API->logger->logger("Entered $this", Logger::ULTRA_VERBOSE); try { yield $this->loop(); } finally { $this->exitedLoop(); $this->API->logger->logger("Exited $this", Logger::ULTRA_VERBOSE); //return null; } } public function exitedLoop() { if ($this->count) { $this->count--; } } public function startedLoop() { $this->count++; } public function isRunning() { return $this->count; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Impl; use Amp\Deferred; use Amp\Loop; use Amp\Promise; use Amp\Success; use danog\MadelineProto\Loop\ResumableLoopInterface; use danog\MadelineProto\Tools; /** * Resumable signal loop helper trait. * * @author Daniil Gentili */ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopInterface { use Tools; private $resume; private $pause; private $resumeWatcher; public function pause($time = null): Promise { if (!is_null($time)) { if ($time <= 0) { return new Success(0); } else { $resume = microtime(true) + $time; if ($this->resumeWatcher) { Loop::cancel($this->resumeWatcher); $this->resumeWatcher = null; } $this->resumeWatcher = Loop::delay($time * 1000, [$this, 'resume'], $resume); } } $this->resume = new Deferred(); $pause = $this->pause; $this->pause = new Deferred(); if ($pause) { Loop::defer([$pause, 'resolve']); } return $this->resume->promise(); } public function resume($watcherId = null, $expected = 0) { if ($this->resumeWatcher) { $storedWatcherId = $this->resumeWatcher; Loop::cancel($storedWatcherId); $this->resumeWatcher = null; if ($watcherId && $storedWatcherId !== $watcherId) { return; } } if ($this->resume) { $resume = $this->resume; $this->resume = null; $resume->resolve(); return $this->pause ? $this->pause->promise() : null; } } public function resumeDefer() { Loop::defer([$this, 'resume']); return $this->pause ? $this->pause->promise() : null; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Impl; use Amp\Deferred; use Amp\Promise; use danog\MadelineProto\Coroutine; use danog\MadelineProto\Loop\SignalLoopInterface; /** * Signal loop helper trait. * * @author Daniil Gentili */ abstract class SignalLoop extends Loop implements SignalLoopInterface { private $signalDeferred; public function signal($what) { if ($this->signalDeferred) { $deferred = $this->signalDeferred; $this->signalDeferred = null; if ($what instanceof \Exception || $what instanceof \Throwable) { $deferred->fail($what); } else { $deferred->resolve($what); } } } public function waitSignal($promise): Promise { if ($promise instanceof \Generator) { $promise = new Coroutine($promise); } $this->signalDeferred = new Deferred(); $dpromise = $this->signalDeferred->promise(); $promise->onResolve(function () use ($promise) { if ($this->signalDeferred !== null) { $deferred = $this->signalDeferred; $this->signalDeferred = null; $deferred->resolve($promise); } }); return $dpromise; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Update; use Amp\Loop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\RPCErrorException; use danog\MadelineProto\Exception; /** * Update loop. * * @author Daniil Gentili */ class UpdateLoop extends ResumableSignalLoop { use \danog\MadelineProto\Tools; private $toPts; private $channelId; private $feeder; public function __construct($API, $channelId) { $this->API = $API; $this->channelId = $channelId; } public function loop() { $API = $this->API; $feeder = $this->feeder = $API->feeders[$this->channelId]; while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { $API->logger->logger("Exiting $this due to signal"); return; } } $this->state = $state = $this->channelId === false ? (yield $API->load_update_state_async()) : $API->loadChannelState($this->channelId); $timeout = $API->settings['updates']['getdifference_interval']; $first = true; while (true) { while (!$API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { $API->logger->logger("Exiting $this due to signal"); return; } } $result = []; $toPts = $this->toPts; $this->toPts = null; while (true) { if ($this->channelId) { $API->logger->logger('Resumed and fetching '.$this->channelId.' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($state->pts() <= 1) { $limit = 10; } elseif ($API->authorization['user']['bot']) { $limit = 100000; } else { $limit = 100; } $request_pts = $state->pts(); try { $difference = yield $API->method_call_async_read('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]); } catch (RPCErrorException $e) { if (in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN'])) { $feeder->signal(true); unset($API->updaters[$this->channelId]); unset($API->feeders[$this->channelId]); $API->getChannelStates()->remove($this->channelId); $API->logger->logger("Channel private, exiting $this"); return true; } throw $e; } catch (Exception $e) { if (in_array($e->getMessage(), ['This peer is not present in the internal peer database'])) { $feeder->signal(true); $API->getChannelStates()->remove($this->channelId); unset($API->updaters[$this->channelId]); unset($API->feeders[$this->channelId]); $API->logger->logger("Channel private, exiting $this"); return true; } throw $e; } if (isset($difference['timeout'])) { $timeout = $difference['timeout']; } $API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::VERBOSE); switch ($difference['_']) { case 'updates.channelDifferenceEmpty': $state->update($difference); unset($difference); break 2; case 'updates.channelDifference': if ($request_pts >= $difference['pts'] && $request_pts > 1) { $API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested ".$state->pts().', using '.($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE); $difference['pts'] = $request_pts + 1; } $state->update($difference); $result += yield $feeder->feed($difference['other_updates']); $feeder->saveMessages($difference['new_messages']); if (!$difference['final']) { if ($difference['pts'] >= $toPts) { unset($difference); break 2; } unset($difference); break; } unset($difference); break 2; case 'updates.channelDifferenceTooLong': $state->update($difference); $feeder->saveMessages($difference['messages']); unset($difference); break; default: throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference, true)); } } else { $API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $difference = yield $API->method_call_async_read('updates.getDifference', ['pts' => $state->pts(), 'date' => $state->date(), 'qts' => $state->qts()], ['datacenter' => $API->settings['connection_settings']['default_dc']]); $API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); switch ($difference['_']) { case 'updates.differenceEmpty': $state->update($difference); unset($difference); break 2; case 'updates.difference': foreach ($difference['new_encrypted_messages'] as &$encrypted) { $encrypted = ['_' => 'updateNewEncryptedMessage', 'message' => $encrypted]; } $result += yield $feeder->feed($difference['other_updates']); $result += yield $feeder->feed($difference['new_encrypted_messages']); $feeder->saveMessages($difference['new_messages']); $state->update($difference['state']); unset($difference); break 2; case 'updates.differenceSlice': foreach ($difference['new_encrypted_messages'] as &$encrypted) { $encrypted = ['_' => 'updateNewEncryptedMessage', 'message' => $encrypted]; } $result += yield $feeder->feed($difference['other_updates']); $result += yield $feeder->feed($difference['new_encrypted_messages']); $feeder->saveMessages($difference['new_messages']); $state->update($difference['intermediate_state']); if ($difference['intermediate_state']['pts'] >= $toPts) { unset($difference); break 2; } unset($difference); break; case 'updates.differenceTooLong': $state->update($difference); unset($difference); break; default: throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference, true)); } } } foreach ($result as $channelId => $boh) { $API->feeders[$channelId]->resumeDefer(); } $API->signalUpdate(); $first = false; if (yield $this->waitSignal($this->pause($timeout))) { $API->logger->logger("Exiting $this due to signal"); return; } } } public function setLimit($toPts) { $this->toPts = $toPts; } public function __toString(): string { return !$this->channelId ? 'getUpdate loop generic' : "getUpdate loop channel {$this->channelId}"; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Update; use Amp\Loop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; /** * update feed loop. * * @author Daniil Gentili */ class FeedLoop extends ResumableSignalLoop { use \danog\MadelineProto\Tools; private $incomingUpdates = []; private $parsedUpdates = []; private $channelId; private $updater; public function __construct($API, $channelId = false) { $this->API = $API; $this->channelId = $channelId; } public function loop() { $API = $this->API; $this->updater = $API->updaters[$this->channelId]; if (!$this->API->settings['updates']['handle_updates']) { return false; } while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { return; } } $this->state = $this->channelId === false ? (yield $API->load_update_state_async()) : $API->loadChannelState($this->channelId); while (true) { while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { return; } } if (yield $this->waitSignal($this->pause())) { return; } if (!$this->API->settings['updates']['handle_updates']) { return; } $API->logger->logger("Resumed $this"); while ($this->incomingUpdates) { $updates = $this->incomingUpdates; $this->incomingUpdates = []; yield $this->parse($updates); $updates = null; } while ($this->parsedUpdates) { $parsedUpdates = $this->parsedUpdates; $this->parsedUpdates = []; foreach ($parsedUpdates as $update) { yield $API->save_update_async($update); } $parsedUpdates = null; $this->API->signalUpdate(); } } } public function parse($updates) { reset($updates); while ($updates) { $key = key($updates); $update = $updates[$key]; unset($updates[$key]); if ($update['_'] === 'updateChannelTooLong') { $this->API->logger->logger('Got channel too long update, getting difference...', \danog\MadelineProto\Logger::VERBOSE); yield $this->updater->resume(); continue; } if (isset($update['pts'])) { $logger = function ($msg) use ($update) { $pts_count = $update['pts_count']; $double = isset($update['message']['id']) ? $update['message']['id'] * 2 : '-'; $mid = isset($update['message']['id']) ? $update['message']['id'] : '-'; $mypts = $this->state->pts(); $computed = $mypts + $pts_count; $this->API->logger->logger("$msg. My pts: {$mypts}, remote pts: {$update['pts']}, computed pts: $computed, msg id: {$mid} (*2=$double), channel id: {$this->channelId}", \danog\MadelineProto\Logger::ERROR); }; $result = $this->state->checkPts($update); if ($result < 0) { $logger('PTS duplicate'); continue; } if ($result > 0) { $logger('PTS hole'); $this->updater->setLimit($this->state->pts() + $result); yield $this->updater->resume(); $updates = array_merge($this->incomingUpdates, $updates); $this->incomingUpdates = []; continue; } if (isset($update['message']['id'], $update['message']['to_id']) && !in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage'])) { if (!$this->API->check_msg_id($update['message'])) { $logger('MSGID duplicate'); continue; } } $logger('PTS OK'); $this->state->pts($update['pts']); } $this->save($update); } } public function feed($updates) { $result = []; foreach ($updates as $update) { $res = $this->feedSingle($update); if ($res instanceof \Generator) { $res = yield $res; } $result[$res] = true; } return $result; } public function feedSingle($update) { $channelId = false; switch ($update['_']) { case 'updateNewChannelMessage': case 'updateEditChannelMessage': $channelId = isset($update['message']['to_id']['channel_id']) ? $update['message']['to_id']['channel_id'] : false; break; case 'updateChannelWebPage': case 'updateDeleteChannelMessages': $channelId = $update['channel_id']; break; case 'updateChannelTooLong': $channelId = isset($update['channel_id']) ? $update['channel_id'] : false; if (!isset($update['pts'])) { $update['pts'] = 1; } break; } if ($channelId && !$this->API->getChannelStates()->has($channelId)) { $this->API->loadChannelState($channelId, $update); if (!isset($this->API->feeders[$channelId])) { $this->API->feeders[$channelId] = new self($this->API, $channelId); } if (!isset($this->API->updaters[$channelId])) { $this->API->updaters[$channelId] = new UpdateLoop($this->API, $channelId); } $this->API->feeders[$channelId]->start(); $this->API->updaters[$channelId]->start(); } switch ($update['_']) { case 'updateNewMessage': case 'updateEditMessage': case 'updateNewChannelMessage': case 'updateEditChannelMessage': $to = false; $from = false; $via_bot = false; $entities = false; if ($update['message']['_'] !== 'messageEmpty' && ( ($from = isset($update['message']['from_id']) && !yield $this->API->peer_isset_async($update['message']['from_id'])) || ($to = !yield $this->API->peer_isset_async($update['message']['to_id'])) || ($via_bot = isset($update['message']['via_bot_id']) && !yield $this->API->peer_isset_async($update['message']['via_bot_id'])) || ($entities = isset($update['message']['entities']) && !yield $this->API->entities_peer_isset_async($update['message']['entities'])) // || //isset($update['message']['fwd_from']) && !yield $this->fwd_peer_isset_async($update['message']['fwd_from']) )) { $log = ''; if ($from) { $log .= "from_id {$update['message']['from_id']}, "; } if ($to) { $log .= 'to_id '.json_encode($update['message']['to_id']).', '; } if ($via_bot) { $log .= "via_bot {$update['message']['via_bot_id']}, "; } if ($entities) { $log .= 'entities '.json_encode($update['message']['entities']).', '; } $this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE); $update = ['_' => 'updateChannelTooLong']; if ($channelId && $to) { $channelId = false; } } break; default: if ($channelId && !yield $this->API->peer_isset_async($this->API->to_supergroup($channelId))) { $this->API->logger->logger('Skipping update, I do not have the channel id '.$channelId, \danog\MadelineProto\Logger::ERROR); return; } break; } if ($channelId !== $this->channelId) { if (isset($this->API->feeders[$channelId])) { return yield $this->API->feeders[$channelId]->feedSingle($update); } else if ($this->channelId) { return yield $this->API->feeders[false]->feedSingle($update); } } $this->API->logger->logger('Was fed an update of type '.$update['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE); $this->incomingUpdates[] = $update; return $this->channelId; } public function save($update) { $this->parsedUpdates[] = $update; } public function saveMessages($messages) { foreach ($messages as $message) { if (!$this->API->check_msg_id($message)) { $this->API->logger->logger("MSGID duplicate ({$message['id']}) in $this"); continue; } $this->API->logger->logger('Getdiff fed me message of type '.$message['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE); $this->parsedUpdates[] = ['_' => $this->channelId === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => -1, 'pts_count' => -1]; } } public function __toString(): string { return !$this->channelId ? 'update feed loop generic' : "update feed loop channel {$this->channelId}"; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Update; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; /** * update feed loop. * * @author Daniil Gentili */ class SeqLoop extends ResumableSignalLoop { use \danog\MadelineProto\Tools; private $incomingUpdates = []; private $feeder; private $pendingWakeups = []; public function __construct($API) { $this->API = $API; } public function loop() { $API = $this->API; $this->feeder = $API->feeders[false]; if (!$this->API->settings['updates']['handle_updates']) { return false; } while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { return; } } $this->state = yield $API->load_update_state_async(); while (true) { while (!$this->API->settings['updates']['handle_updates'] || !$API->hasAllAuth()) { if (yield $this->waitSignal($this->pause())) { return; } } if (yield $this->waitSignal($this->pause())) { return; } if (!$this->API->settings['updates']['handle_updates']) { return; } while ($this->incomingUpdates) { $updates = $this->incomingUpdates; $this->incomingUpdates = []; yield $this->parse($updates); $updates = null; } while ($this->pendingWakeups) { reset($this->pendingWakeups); $channelId = key($this->pendingWakeups); unset($this->pendingWakeups[$channelId]); $this->API->feeders[$channelId]->resume(); } } } public function parse($updates) { reset($updates); while ($updates) { $options = []; $key = key($updates); $update = $updates[$key]; unset($updates[$key]); $options = $update['options']; $seq_start = $options['seq_start']; $seq_end = $options['seq_end']; $result = $this->state->checkSeq($seq_start); if ($result > 0) { $this->API->logger->logger('Seq hole. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); yield $this->pause(1.0); if (!$this->incomingUpdates) { yield $this->API->updaters[false]->resume(); } $this->incomingUpdates = array_merge($this->incomingUpdates, [$update], $updates); continue; } if ($result < 0) { $this->API->logger->logger('Seq too old. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); continue; } $this->state->seq($seq_end); if (isset($options['date'])) { $this->state->date($options['date']); } yield $this->save($update); } } public function feed($updates) { $this->API->logger->logger('Was fed updates of type '.$updates['_'].'...', \danog\MadelineProto\Logger::VERBOSE); $this->incomingUpdates[] = $updates; } public function save($updates) { $this->pendingWakeups += yield $this->feeder->feed($updates['updates']); } public function addPendingWakeups($wakeups) { $this->pendingWakeups += $wakeups; } public function __toString(): string { return 'update seq loop'; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Loop\Generic; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; /** * Generic loop. * * @author Daniil Gentili */ class GenericLoop extends ResumableSignalLoop { const STOP = -1; const PAUSE = null; const CONTINUE = 0; protected $callback; protected $name; /** * Constructor. * * The callback will be bound to the GenericLoop instance: this means that you will be able to use `$this` as if the callback were actually the `loop` function (you can access the API property, use the pause/waitSignal methods & so on). * The return value of the callable can be: * A number - the loop will be paused for the specified number of seconds * GenericLoop::STOP - The loop will stop * GenericLoop::PAUSE - The loop will pause forever (or until the `resume` method is called on the loop object from outside the loop) * GenericLoop::CONTINUE - Return this if you want to rerun the loop without waiting * * @param \danog\MadelineProto\API $API Instance of MadelineProto * @param callable $callback Callback to run * @param string $name Fetcher name */ public function __construct($API, $callback, $name) { $this->API = $API; $this->callback = $callback->bindTo($this); $this->name = $name; } public function loop() { $callback = $this->callback; while (true) { $timeout = yield $callback(); if ($timeout === self::PAUSE) { $this->API->logger->logger("Pausing $this", \danog\MadelineProto\Logger::VERBOSE); } elseif ($timeout > 0) { $this->API->logger->logger("Pausing $this for $timeout", \danog\MadelineProto\Logger::VERBOSE); } if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) { return; } } } public function __toString(): string { return $this->name; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\Deferred; use Amp\Failure; use Amp\Loop; use Amp\Promise; use Amp\Success; use function Amp\Promise\all; use function Amp\Promise\any; use function Amp\Promise\first; use function Amp\Promise\some; use function Amp\Promise\timeout; use function Amp\Promise\wait; use function Amp\ByteStream\getStdin; use function Amp\ByteStream\getStdout; use function Amp\ByteStream\getOutputBufferStream; /** * Some tools. */ trait Tools { public static function gen_vector_hash($ints) { //sort($ints, SORT_NUMERIC); if (\danog\MadelineProto\Magic::$bigint) { $hash = new \phpseclib\Math\BigInteger(0); foreach ($ints as $int) { $hash = $hash->multiply(\danog\MadelineProto\Magic::$twozerotwosixone)->add(\danog\MadelineProto\Magic::$zeroeight)->add(new \phpseclib\Math\BigInteger($int))->divide(\danog\MadelineProto\Magic::$zeroeight)[1]; } $hash = self::unpack_signed_int(strrev(str_pad($hash->toBytes(), 4, "\0", STR_PAD_LEFT))); } else { $hash = 0; foreach ($ints as $int) { $hash = ((($hash * 20261) & 0x7FFFFFFF) + $int) & 0x7FFFFFFF; } } return $hash; } public static function random_int($modulus = false) { if ($modulus === false) { $modulus = PHP_INT_MAX; } try { return \random_int(0, PHP_INT_MAX) % $modulus; } catch (\Exception $e) { // random_compat will throw an Exception, which in PHP 5 does not implement Throwable } catch (\Throwable $e) { // If a sufficient source of randomness is unavailable, random_bytes() will throw an // object that implements the Throwable interface (Exception, TypeError, Error). // We don't actually need to do anything here. The string() method should just continue // as normal. Note, however, that if we don't have a sufficient source of randomness for // random_bytes(), most of the other calls here will fail too, so we'll end up using // the PHP implementation. } if (Magic::$bigint) { $number = self::unpack_signed_int(self::random(4)); } else { $number = self::unpack_signed_long(self::random(8)); } return ($number & PHP_INT_MAX) % $modulus; } public static function random($length) { return $length === 0 ? '' : \phpseclib\Crypt\Random::string($length); } /** * posmod(numeric,numeric) : numeric * Works just like the % (modulus) operator, only returns always a postive number. */ public static function posmod($a, $b) { $resto = $a % $b; return $resto < 0 ? $resto + abs($b) : $resto; } public static function unpack_signed_int($value) { if (strlen($value) !== 4) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_4']); } return unpack('l', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1]; } public static function unpack_signed_long($value) { if (strlen($value) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']); } return unpack('q', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1]; } public static function pack_signed_int($value) { if ($value > 2147483647) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_2147483647'], $value)); } if ($value < -2147483648) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_2147483648'], $value)); } $res = pack('l', $value); return \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($res) : $res; } public static function pack_signed_long($value) { if ($value > 9223372036854775807) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_9223372036854775807'], $value)); } if ($value < -9.223372036854776E+18) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_9223372036854775808'], $value)); } $res = \danog\MadelineProto\Magic::$bigint ? self::pack_signed_int($value)."\0\0\0\0" : (\danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev(pack('q', $value)) : pack('q', $value)); return $res; } public static function pack_unsigned_int($value) { if ($value > 4294967295) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_bigger_than_4294967296'], $value)); } if ($value < 0) { throw new TL\Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['value_smaller_than_0'], $value)); } return pack('V', $value); } public static function pack_double($value) { $res = pack('d', $value); if (strlen($res) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['encode_double_error']); } return \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($res) : $res; } public static function unpack_double($value) { if (strlen($value) !== 8) { throw new TL\Exception(\danog\MadelineProto\Lang::$current_lang['length_not_8']); } return unpack('d', \danog\MadelineProto\Magic::$BIG_ENDIAN ? strrev($value) : $value)[1]; } public static function wait($promise) { if ($promise instanceof \Generator) { $promise = new Coroutine($promise); } elseif (!($promise instanceof Promise)) { return $promise; } $exception = null; $value = null; $resolved = false; do { try { Loop::run(function () use (&$resolved, &$value, &$exception, $promise) { $promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) { Loop::stop(); $resolved = true; $exception = $e; $value = $v; }); }); } catch (\Throwable $throwable) { throw new \Error('Loop exceptionally stopped without resolving the promise', 0, $throwable); } } while (!$resolved); if ($exception) { throw $exception; } return $value; } public static function all($promises) { foreach ($promises as &$promise) { $promise = self::call($promise); } return all($promises); } public static function any($promises) { foreach ($promises as &$promise) { $promise = self::call($promise); } return any($promises); } public static function some($promises) { foreach ($promises as &$promise) { $promise = self::call($promise); } return some($promises); } public static function first($promises) { foreach ($promises as &$promise) { $promise = self::call($promise); } return first($promises); } public static function timeout($promise, $timeout) { return timeout(self::call($promise), $timeout); } public static function call($promise) { if ($promise instanceof \Generator) { $promise = new Coroutine($promise); } elseif (!($promise instanceof Promise)) { return new Success($promise); } return $promise; } public static function callFork($promise, $actual = null, $file = '') { if ($actual) { $promise = $actual; } else { $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]; $file = ''; if (isset($trace['file'])) { $file .= basename($trace['file'], '.php'); } if (isset($trace['line'])) { $file .= ":{$trace['line']}"; } } if ($promise instanceof \Generator) { $promise = new Coroutine($promise); } if ($promise instanceof Promise) { $promise->onResolve(function ($e, $res) use ($file) { if ($e) { if (isset($this)) { $this->rethrow($e, $file); } else { self::rethrow($e, $file); } } }); } return $promise; } public static function callForkDefer($promise) { Loop::defer([__CLASS__, 'callFork'], $promise); } public static function rethrow($e, $file = '') { $zis = isset($this) ? $this : null; $logger = isset($zis->logger) ? $zis->logger : Logger::$default; if ($file) { $file = " started @ $file"; } $logger->logger("Got the following exception within a forked strand$file, trying to rethrow"); if ($e->getMessage() === "Cannot get return value of a generator that hasn't returned") { $logger->logger("Well you know, this might actually not be the actual exception, scroll up in the logs to see the actual exception"); if (!$zis || !$zis->destructing) Promise\rethrow(new Failure($e)); } else { $logger->logger($e); Promise\rethrow(new Failure($e)); } } public static function after($a, $b) { $a = self::call($a()); $deferred = new Deferred(); $a->onResolve(static function ($e, $res) use ($b, $deferred) { if ($e) { if (isset($this)) { $this->rethrow($e, $file); } else { self::rethrow($e, $file); } return; } $b = self::call($b()); $b->onResolve(static function ($e, $res) use ($deferred) { if ($e) { if (isset($this)) { $this->rethrow($e, $file); } else { self::rethrow($e, $file); } return; } $deferred->resolve($res); }); }); return $deferred->promise(); } public static function sleep($time) { return new \Amp\Delayed($time * 1000); } public static function readLine($prompt = '') { return self::call(Tools::readLineAsync($prompt)); } public static function readLineAsync($prompt = '') { $stdin = getStdin(); $stdout = getStdout(); if ($prompt) { yield $stdout->write($prompt); } static $lines = ['']; while (count($lines) < 2 && ($chunk = yield $stdin->read()) !== null) { $chunk = explode("\n", str_replace(["\r", "\n\n"], "\n", $chunk)); $lines[count($lines) - 1] .= array_shift($chunk); $lines = array_merge($lines, $chunk); } return array_shift($lines); } public static function echo($string) { return getOutputBufferStream()->write($string); } public static function is_array_or_alike($var) { return is_array($var) || ($var instanceof ArrayAccess && $var instanceof Traversable && $var instanceof Countable); } } // Core types (no need to gen) //vector#1cb5c415 {t:Type} # [ t ] = Vector t; /////////////////////////////// /////////////////// Layer cons /////////////////////////////// //invokeAfterMsg#cb9f372d msg_id:long query:!X = X; //invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; //invokeWithLayer1#53835315 query:!X = X; //invokeWithLayer2#289dd1f6 query:!X = X; //invokeWithLayer3#b7475268 query:!X = X; //invokeWithLayer4#dea0d430 query:!X = X; //invokeWithLayer5#417a57ae query:!X = X; //invokeWithLayer6#3a64d54d query:!X = X; //invokeWithLayer7#a5be56d3 query:!X = X; //invokeWithLayer8#e9abd9fd query:!X = X; //invokeWithLayer9#76715a63 query:!X = X; //invokeWithLayer10#39620c41 query:!X = X; //invokeWithLayer11#a6b88fdf query:!X = X; //invokeWithLayer12#dda60d3c query:!X = X; //invokeWithLayer13#427c8ea2 query:!X = X; //invokeWithLayer14#2b9b08fa query:!X = X; //invokeWithLayer15#b4418b64 query:!X = X; //invokeWithLayer16#cf5f0987 query:!X = X; //invokeWithLayer17#50858a19 query:!X = X; //invokeWithLayer18#1c900537 query:!X = X; //invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer /////////////////////////////// /// Authorization key creation /////////////////////////////// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ////////////// System messages /////////////////////////////// ---types--- msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; //message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually //msg_container#73f1f8dc messages:vector = MessageContainer; // parsed manually //msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container //gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ipPort ipv4:int port:int = IpPort; help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple; ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#e39621fd flags:# file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#cb44b1c flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#90dddc11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#b5223b0f flags:# photo:flags.0?Photo caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; config#9c840964 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#fadff4ac flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#39e9ea0 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.getRecentLocations#249431e2 peer:InputPeer limit:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector; // LAYER 72 ---types--- help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple; ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia; inputMediaPoll#6b3765b poll:Poll = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#22a235da flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int = ChatFull; channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonChildAbuse#adf44ee3 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; documentEmpty#36f8c871 id:long = Document; document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyBroadcasts#d612e8ef = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; privacyKeyForwards#69ec56a3 = PrivacyKey; privacyKeyProfilePhoto#96151fed = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#6a90bcb7 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant; channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; textSubscript#ed6a8504 text:RichText = RichText; textSuperscript#c7fb5e01 text:RichText = RichText; textMarked#34b8621 text:RichText = RichText; textPhone#1ccb966a text:RichText phone:string = RichText; textImage#81ccf4f document_id:long w:int h:int = RichText; textAnchor#35553762 text:RichText name:string = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#e4e88011 items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; pageBlockKicker#1e148390 text:RichText = PageBlock; pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; help.passportConfigNotModified#bfb9f457 = help.PassportConfig; help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; jsonNull#3f6d7b68 = JSONValue; jsonBool#c7345e6a value:Bool = JSONValue; jsonNumber#2be0dfa4 value:double = JSONValue; jsonString#b71e767a value:string = JSONValue; jsonArray#f7444763 value:Vector = JSONValue; jsonObject#99c1d49d value:Vector = JSONValue; pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; pageCaption#6f747657 text:RichText credit:RichText = PageCaption; pageListItemText#b92fb6cd text:RichText = PageListItem; pageListItemBlocks#25e073fc blocks:Vector = PageListItem; pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector = Page; help.supportName#8c05f1c9 name:string = help.SupportName; help.userInfoEmpty#f3ae2eed = help.UserInfo; help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer; poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector = Poll; pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters; pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int = PollResults; chatOnlines#f041e250 onlines:int = ChatOnlines; statsURL#47a971e0 url:string = StatsURL; chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights; chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights; inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; inputWallPaperSlug#72091c80 slug:string = InputWallPaper; account.wallPapersNotModified#1c199183 = account.WallPapers; account.wallPapers#702b65a9 hash:int wallpapers:Vector = account.WallPapers; codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings; wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings; autoDownloadSettings#d246fd47 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int = AutoDownloadSettings; account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; emojiURL#a575739d url:string = EmojiURL; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#aabb1763 hash:int = account.WallPapers; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; account.confirmPasswordEmail#8fdf1920 code:string = Bool; account.resendPasswordEmail#7a7f2a15 = Bool; account.cancelPasswordEmail#c1cbd5b6 = Bool; account.getContactSignUpNotification#9f07c728 = Bool; account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates; account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; account.resetWallPapers#bb3b9804 = Bool; account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; contacts.getContactIDs#2caa4a42 hash:int = Vector; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.deleteByPhones#1013fd9e phones:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector; messages.clearAllDrafts#7e58ee9c = Bool; messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates; messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL; messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#522d5a7d source:string = help.AppUpdate; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; help.getAppConfig#98914110 = JSONValue; help.saveAppLog#6f02f748 events:Vector = Bool; help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; help.getSupportName#d360e72c = help.SupportName; help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; langpack.getLanguages#42c6978f lang_pack:string = Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; // LAYER 97 . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\Loop; use danog\MadelineProto\Async\AsyncConstruct; use danog\MadelineProto\Loop\Update\FeedLoop; use danog\MadelineProto\Loop\Update\SeqLoop; use danog\MadelineProto\Loop\Update\UpdateLoop; use danog\MadelineProto\MTProtoTools\CombinedUpdatesState; use danog\MadelineProto\MTProtoTools\ReferenceDatabase; use danog\MadelineProto\MTProtoTools\UpdatesState; use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpStream; use danog\MadelineProto\TL\TLCallback; /** * Manages all of the mtproto stuff. */ class MTProto extends AsyncConstruct implements TLCallback { use \danog\Serializable; use \danog\MadelineProto\MTProtoTools\AckHandler; use \danog\MadelineProto\MTProtoTools\AuthKeyHandler; use \danog\MadelineProto\MTProtoTools\CallHandler; use \danog\MadelineProto\MTProtoTools\Crypt; use \danog\MadelineProto\MTProtoTools\PeerHandler; use \danog\MadelineProto\MTProtoTools\ResponseHandler; use \danog\MadelineProto\MTProtoTools\SeqNoHandler; use \danog\MadelineProto\MTProtoTools\UpdateHandler; use \danog\MadelineProto\MTProtoTools\Files; use \danog\MadelineProto\SecretChats\AuthKeyHandler; use \danog\MadelineProto\SecretChats\MessageHandler; use \danog\MadelineProto\SecretChats\ResponseHandler; use \danog\MadelineProto\SecretChats\SeqNoHandler; use \danog\MadelineProto\TL\TL; use \danog\MadelineProto\TL\Conversion\BotAPI; use \danog\MadelineProto\TL\Conversion\BotAPIFiles; use \danog\MadelineProto\TL\Conversion\Extension; use \danog\MadelineProto\TL\Conversion\TD; use \danog\MadelineProto\Tools; use \danog\MadelineProto\VoIP\AuthKeyHandler; use \danog\MadelineProto\Wrappers\DialogHandler; use \danog\MadelineProto\Wrappers\Events; use \danog\MadelineProto\Wrappers\Webhook; use \danog\MadelineProto\Wrappers\Callback; use \danog\MadelineProto\Wrappers\Login; use \danog\MadelineProto\Wrappers\Loop; use \danog\MadelineProto\Wrappers\Noop; use \danog\MadelineProto\Wrappers\Start; use \danog\MadelineProto\Wrappers\Templates; use \danog\MadelineProto\Wrappers\TOS; /* const V = 71; */ const V = 122; const RELEASE = '4.0'; const NOT_LOGGED_IN = 0; const WAITING_CODE = 1; const WAITING_SIGNUP = -1; const WAITING_PASSWORD = 2; const LOGGED_IN = 3; const DISALLOWED_METHODS = ['account.updatePasswordSettings' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'account.getPasswordSettings' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'messages.receivedQueue' => 'You cannot use this method directly', 'messages.getDhConfig' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'auth.bindTempAuthKey' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'auth.exportAuthorization' => 'You cannot use this method directly, use $MadelineProto->export_authorization() instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'auth.importAuthorization' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'auth.logOut' => 'You cannot use this method directly, use the logout method instead (see https://docs.madelineproto.xyz for more info)', 'auth.importBotAuthorization' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'auth.sendCode' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'auth.signIn' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'auth.checkPassword' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'auth.signUp' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'users.getFullUser' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'channels.getFullChannel' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'messages.getFullChat' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'contacts.resolveUsername' => 'You cannot use this method directly, use the resolve_username, get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'messages.acceptEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'messages.discardEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'messages.requestEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'phone.requestCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'phone.acceptCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'phone.confirmCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'phone.discardCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'updates.getChannelDifference' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'updates.getDifference' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'updates.getState' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'upload.getCdnFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'upload.getFileHashes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'upload.getCdnFileHashes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'upload.reuploadCdnFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'upload.getFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'upload.saveFilePart' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'upload.saveBigFilePart' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info']; const BAD_MSG_ERROR_CODES = [16 => 'msg_id too low (most likely, client time is wrong; it would be worthwhile to synchronize it using msg_id notifications and re-send the original message with the “correct” msg_id or wrap it in a container with a new msg_id if the original message had waited too long on the client to be transmitted)', 17 => 'msg_id too high (similar to the previous case, the client time has to be synchronized, and the message re-sent with the correct msg_id)', 18 => 'incorrect two lower order msg_id bits (the server expects client message msg_id to be divisible by 4)', 19 => 'container msg_id is the same as msg_id of a previously received message (this must never happen)', 20 => 'message too old, and it cannot be verified whether the server has received a message with this msg_id or not', 32 => 'msg_seqno too low (the server has already received a message with a lower msg_id but with either a higher or an equal and odd seqno)', 33 => 'msg_seqno too high (similarly, there is a message with a higher msg_id but with either a lower or an equal and odd seqno)', 34 => 'an even msg_seqno expected (irrelevant message), but odd received', 35 => 'odd msg_seqno expected (relevant message), but even received', 48 => 'incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)', 64 => 'invalid container.']; const MSGS_INFO_FLAGS = [1 => 'nothing is known about the message (msg_id too low, the other party may have forgotten it)', 2 => 'message not received (msg_id falls within the range of stored identifiers; however, the other party has certainly not received a message like that)', 3 => 'message not received (msg_id too high; however, the other party has certainly not received it yet)', 4 => 'message received (note that this response is also at the same time a receipt acknowledgment)', 8 => ' and message already acknowledged', 16 => ' and message not requiring acknowledgment', 32 => ' and RPC query contained in message being processed or processing already complete', 64 => ' and content-related response to message already generated', 128 => ' and other party knows for a fact that message is already received']; const REQUESTED = 0; const ACCEPTED = 1; const CONFIRMED = 2; const READY = 3; const TD_PARAMS_CONVERSION = ['updateNewMessage' => ['_' => 'updateNewMessage', 'disable_notification' => ['message', 'silent'], 'message' => ['message']], 'message' => ['_' => 'message', 'id' => ['id'], 'sender_user_id' => ['from_id'], 'chat_id' => ['to_id', 'choose_chat_id_from_botapi'], 'send_state' => ['choose_incoming_or_sent'], 'can_be_edited' => ['choose_can_edit'], 'can_be_deleted' => ['choose_can_delete'], 'is_post' => ['post'], 'date' => ['date'], 'edit_date' => ['edit_date'], 'forward_info' => ['fwd_info', 'choose_forward_info'], 'reply_to_message_id' => ['reply_to_msg_id'], 'ttl' => ['choose_ttl'], 'ttl_expires_in' => ['choose_ttl_expires_in'], 'via_bot_user_id' => ['via_bot_id'], 'views' => ['views'], 'content' => ['choose_message_content'], 'reply_markup' => ['reply_markup']], 'messages.sendMessage' => ['chat_id' => ['peer'], 'reply_to_message_id' => ['reply_to_msg_id'], 'disable_notification' => ['silent'], 'from_background' => ['background'], 'input_message_content' => ['choose_message_content'], 'reply_markup' => ['reply_markup']]]; const TD_REVERSE = ['sendMessage' => 'messages.sendMessage']; const TD_IGNORE = ['updateMessageID']; const BOTAPI_PARAMS_CONVERSION = ['disable_web_page_preview' => 'no_webpage', 'disable_notification' => 'silent', 'reply_to_message_id' => 'reply_to_msg_id', 'chat_id' => 'peer', 'text' => 'message']; const NOT_CONTENT_RELATED = [ //'rpc_result', //'rpc_error', 'rpc_drop_answer', 'rpc_answer_unknown', 'rpc_answer_dropped_running', 'rpc_answer_dropped', 'get_future_salts', 'future_salt', 'future_salts', 'ping', 'pong', 'ping_delay_disconnect', 'destroy_session', 'destroy_session_ok', 'destroy_session_none', //'new_session_created', 'msg_container', 'msg_copy', 'gzip_packed', 'http_wait', 'msgs_ack', 'bad_msg_notification', 'bad_server_salt', 'msgs_state_req', 'msgs_state_info', 'msgs_all_info', 'msg_detailed_info', 'msg_new_detailed_info', 'msg_resend_req', 'msg_resend_ans_req', ]; const DEFAULT_GETUPDATES_PARAMS = ['offset' => 0, 'limit' => null, 'timeout' => 0]; public $wrapper; public $hook_url = false; public $settings = []; private $config = ['expires' => -1]; private $tos = ['expires' => 0, 'accepted' => true]; private $initing_authorization = false; public $authorization = null; public $authorized = 0; public $authorized_dc = -1; private $rsa_keys = []; private $dh_config = ['version' => 0]; public $chats = []; public $channel_participants = []; public $last_stored = 0; public $qres = []; public $full_chats = []; private $msg_ids = []; private $v = 0; private $dialog_params = ['_' => 'MadelineProto.dialogParams', 'limit' => 0, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0]; public $setdem = false; public $storage = []; private $supportUser = 0; public $referenceDatabase; public $phoneConfigWatcherId; public $feeders = []; public $updaters = []; public $destructing = false; // Avoid problems with exceptions thrown by forked strands, see tools public function __magic_construct($settings = []) { $this->setInitPromise($this->__construct_async($settings)); } public function __construct_async($settings = []) { \danog\MadelineProto\Magic::class_exists(); // Parse settings $this->parse_settings($settings); if (!defined('\\phpseclib\\Crypt\\Common\\SymmetricKey::MODE_IGE') || \phpseclib\Crypt\Common\SymmetricKey::MODE_IGE !== 7) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['phpseclib_fork']); } if (!extension_loaded('xml')) { throw new Exception(['extension', 'xml']); } if (!extension_loaded('fileinfo')) { throw new Exception(['extension', 'fileinfo']); } if (!extension_loaded('json')) { throw new Exception(['extension', 'json']); } if (!extension_loaded('mbstring')) { throw new Exception(['extension', 'mbstring']); } // Connect to servers $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE); if (!($this->channels_state instanceof CombinedUpdatesState)) { $this->channels_state = new CombinedUpdatesState($this->channels_state); } if (isset($this->updates_state)) { if (!($this->updates_state instanceof UpdatesState)) { $this->updates_state = new UpdatesState($this->updates_state); } $this->channels_state->__construct([false => $this->updates_state]); unset($this->updates_state); } if (!isset($this->datacenter)) { $this->datacenter = new DataCenter($this, $this->settings['connection'], $this->settings['connection_settings']); } if (!isset($this->referenceDatabase)) { $this->referenceDatabase = new ReferenceDatabase($this); } // Load rsa keys $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['load_rsa'], Logger::ULTRA_VERBOSE); foreach ($this->settings['authorization']['rsa_keys'] as $key) { $key = yield (new RSA())->load($key); $this->rsa_keys[$key->fp] = $key; } /* * *********************************************************************** * Define some needed numbers for BigInteger */ $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_translation'], Logger::ULTRA_VERBOSE); $this->construct_TL($this->settings['tl_schema']['src'], [$this, $this->referenceDatabase]); yield $this->connect_to_all_dcs_async(); $this->datacenter->curdc = 2; if ((!isset($this->authorization['user']['bot']) || !$this->authorization['user']['bot']) && $this->datacenter->sockets[$this->datacenter->curdc]->temp_auth_key !== null) { try { $nearest_dc = yield $this->method_call_async_read('help.getNearestDc', [], ['datacenter' => $this->datacenter->curdc]); $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['nearest_dc'], $nearest_dc['country'], $nearest_dc['nearest_dc']), Logger::NOTICE); if ($nearest_dc['nearest_dc'] != $nearest_dc['this_dc']) { $this->settings['connection_settings']['default_dc'] = $this->datacenter->curdc = (int) $nearest_dc['nearest_dc']; } } catch (RPCErrorException $e) { if ($e->rpc !== 'BOT_METHOD_INVALID') { throw $e; } } } yield $this->get_config_async([], ['datacenter' => $this->datacenter->curdc]); $this->startUpdateSystem(true); $this->v = self::V; } public function __sleep() { return ['supportUser', 'referenceDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'dh_config', 'chats', 'last_stored', 'qres', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos']; } public function logger($param, $level = Logger::NOTICE, $file = null) { if ($file === null) { $file = basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); } return isset($this->logger) ? $this->logger->logger($param, $level, $file) : Logger::$default->logger($param, $level, $file); } public function isAltervista() { return Magic::$altervista; } public function isInitingAuthorization() { return $this->initing_authorization; } public function getHTTPClient() { return $this->datacenter->getHTTPClient(); } public function getDNSClient() { return $this->datacenter->getDNSClient(); } public function fileGetContents($url): \Generator { return $this->datacenter->fileGetContents($url); } public function hasAllAuth() { if ($this->isInitingAuthorization()) { return false; } foreach ($this->datacenter->sockets as $dc) { if (!$dc->authorized || $dc->temp_auth_key === null) { return false; } } return true; } public function __wakeup() { $backtrace = debug_backtrace(0, 3); $this->asyncInitPromise = true; $this->setInitPromise($this->__wakeup_async($backtrace)); } public function __wakeup_async($backtrace) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']); $this->setup_logger(); if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread())) { return; } Lang::$current_lang = &Lang::$lang['en']; if (isset($this->settings['app_info']['lang_code']) && isset(Lang::$lang[$this->settings['app_info']['lang_code']])) { Lang::$current_lang = &Lang::$lang[$this->settings['app_info']['lang_code']]; } if (!defined('\\phpseclib\\Crypt\\AES::MODE_IGE')) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['phpseclib_fork']); } if (!extension_loaded('xml')) { throw new Exception(['extension', 'xml']); } if (!extension_loaded('fileinfo')) { throw new Exception(['extension', 'fileinfo']); } if (!extension_loaded('mbstring')) { throw new Exception(['extension', 'mbstring']); } if (!extension_loaded('json')) { throw new Exception(['extension', 'json']); } if (!isset($this->referenceDatabase)) { $this->referenceDatabase = new ReferenceDatabase($this); } $this->update_callbacks([$this, $this->referenceDatabase]); $this->settings['connection_settings']['all']['ipv6'] = \danog\MadelineProto\Magic::$ipv6; /*if (isset($this->settings['pwr']['update_handler']) && $this->settings['pwr']['update_handler'] === $this->settings['updates']['callback']) { unset($this->settings['pwr']['update_handler']); $this->updates = []; }*/ /*$keys = array_keys((array) get_object_vars($this)); if (count($keys) !== count(array_unique($keys))) { throw new Bug74586Exception(); } if (isset($this->data)) { foreach ($this->data as $k => $v) { $this->{$k} = $v; } unset($this->data); }*/ if ($this->authorized === true) { $this->authorized = self::LOGGED_IN; } if (!($this->channels_state instanceof CombinedUpdatesState)) { $this->channels_state = new CombinedUpdatesState($this->channels_state); } if (isset($this->updates_state)) { if (!($this->updates_state instanceof UpdatesState)) { $this->updates_state = new UpdatesState($this->updates_state); } $this->channels_state->__construct([false => $this->updates_state]); unset($this->updates_state); } if ($this->event_handler && class_exists($this->event_handler) && is_subclass_of($this->event_handler, '\danog\MadelineProto\EventHandler')) { $this->setEventHandler($this->event_handler); } $force = false; $this->reset_session(); if (isset($backtrace[2]['function'], $backtrace[2]['class'], $backtrace[2]['args']) && $backtrace[2]['class'] === 'danog\\MadelineProto\\API' && $backtrace[2]['function'] === '__construct_async') { if (count($backtrace[2]['args']) >= 2) { $this->parse_settings(array_replace_recursive($this->settings, $backtrace[2]['args'][1])); } } if (isset($this->settings['tl_schema']['src']['botAPI']) && $this->settings['tl_schema']['src']['botAPI'] !== __DIR__.'/TL_botAPI.tl') { unset($this->v); } if (!isset($this->v) || $this->v !== self::V) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['serialization_ofd'], Logger::WARNING); foreach ($this->datacenter->sockets as $dc_id => $socket) { if ($this->authorized === self::LOGGED_IN && strpos($dc_id, '_') === false && $socket->auth_key !== null && $socket->temp_auth_key !== null) { $socket->authorized = true; } } $settings = $this->settings; if (isset($settings['updates']['callback'][0]) && $settings['updates']['callback'][0] === $this) { $settings['updates']['callback'] = 'get_updates_update_handler'; } if (isset($settings['updates']['getdifference_interval']) && $settings['updates']['getdifference_interval'] === -1) { unset($settings['updates']['getdifference_interval']); } unset($settings['tl_schema']); if (isset($settings['authorization']['rsa_key'])) { unset($settings['authorization']['rsa_key']); } if (!isset($this->full_chats)) { $this->full_chats = []; } if (!isset($this->secret_chats)) { $this->secret_chats = []; } foreach ($this->full_chats as $id => $full) { if (isset($full['full'], $full['last_update'])) { $this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']]; } } foreach ($this->secret_chats as $key => &$chat) { if (!is_array($chat)) { unset($this->secret_chats[$key]); continue; } if ($chat['layer'] >= 73) { $chat['mtproto'] = 2; } else { $chat['mtproto'] = 1; } } foreach ($settings['connection_settings'] as $key => &$connection) { if (!is_array($connection)) { unset($settings['connection_settings'][$key]); continue; } if (!isset($connection['proxy'])) { $connection['proxy'] = '\\Socket'; } if (!isset($connection['proxy_extra'])) { $connection['proxy_extra'] = []; } if (!isset($connection['pfs'])) { $connection['pfs'] = extension_loaded('gmp'); } if ($connection['protocol'] === 'obfuscated2') { $connection['protocol'] = 'tcp_intermediate_padded'; $connection['obfuscated'] = true; } } if ($settings['app_info']['api_id'] === 6) { unset($settings['app_info']); } $this->reset_session(true, true); $this->config = ['expires' => -1]; $this->dh_config = ['version' => 0]; yield $this->__construct_async($settings); $force = true; foreach ($this->secret_chats as $chat => $data) { try { if (isset($this->secret_chats[$chat]) && $this->secret_chats[$chat]['InputEncryptedChat'] !== null) { yield $this->notify_layer_async($chat); } } catch (\danog\MadelineProto\RPCErrorException $e) { } } } if (!$this->settings['updates']['handle_old_updates']) { $this->channels_state = new CombinedUpdatesState(); $this->msg_ids = []; $this->got_state = false; } yield $this->connect_to_all_dcs_async(); foreach ($this->calls as $id => $controller) { if (!is_object($controller)) { unset($this->calls[$id]); } elseif ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->setMadeline($this); $controller->discard(); } else { $controller->setMadeline($this); } } if (yield $this->get_self_async()) { $this->authorized = self::LOGGED_IN; } if ($this->authorized === self::LOGGED_IN) { yield $this->get_cdn_config_async($this->datacenter->curdc); $this->setup_logger(); } $this->startUpdateSystem(true); if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot'] && $this->settings['peer']['cache_all_peers_on_startup']) { yield $this->get_dialogs_async($force); } if ($this->authorized === self::LOGGED_IN && $this->settings['updates']['handle_updates']) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getupdates_deserialization'], Logger::NOTICE); yield $this->updaters[false]->resume(); } $this->updaters[false]->start(); } public function __destruct() { if ($this->phoneConfigWatcherId) { Loop::cancel($this->phoneConfigWatcherId); } if (isset($this->seqUpdater)) { $this->seqUpdater->signal(true); } $channelIds = []; foreach ($this->channels_state->get() as $state) { $channelIds[] = $state->getChannel(); } sort($channelIds); foreach ($channelIds as $channelId) { if (isset($this->feeders[$channelId])) { $this->feeders[$channelId]->signal(true); } if (!isset($this->updaters[$channelId])) { $this->updaters[$channelId]->signal(true); } } foreach ($this->datacenter->sockets as $datacenter) { $datacenter->disconnect(); } $this->logger("Successfully destroyed MadelineProto"); } public function serialize() { if ($this->wrapper instanceof \danog\MadelineProto\API && isset($this->wrapper->session) && !is_null($this->wrapper->session)) { $this->wrapper->serialize($this->wrapper->session); } } public function parse_settings($settings) { if (isset($this->settings['connection_settings']['default_dc'])) { $settings['connection_settings']['default_dc'] = $this->settings['connection_settings']['default_dc']; } if (!isset($settings['app_info']['api_id']) || !$settings['app_info']['api_id']) { if (isset($this->settings['app_info']['api_id']) && $this->settings['app_info']['api_id']) { $settings['app_info']['api_id'] = $this->settings['app_info']['api_id']; $settings['app_info']['api_hash'] = $this->settings['app_info']['api_hash']; } else { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1); } } // Detect device model try { $device_model = php_uname('s'); } catch (\danog\MadelineProto\Exception $e) { $device_model = 'Web server'; } if ($settings['app_info']['api_id'] === 6) { // TG DEV NOTICE: these app info spoofing measures were implemented for NON-MALICIOUS purposes. // All accounts registered with a custom API ID require manual verification through recover@telegram.org, to avoid instant permabans. // This makes usage of all MTProto libraries very difficult, at least for new users. // To help a bit, when the android API ID is used, the android app infos are spoofed too. // THE ANDROID API HASH IS NOT PRESENT IN THIS REPOSITORY, AND WILL NOT BE GIVEN TO EVERYONE. // This measure was NOT created with the intent to aid spammers, flooders, and other scum. // // I understand that automated account registration through headless libraries may indicate the creation of a botnet, //...and I understand why these automatic bans were implemented in the first place. // Manual requests to activate numbers through recover@telegram.org will still be required for the majority of users of this library, //...those that choose to user their own API ID for their application. // // To be honest, I wrote this feature just for me, since I honestly don't want to //...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) $device_model = 'LGENexus 5'; } // Detect system version try { $system_version = php_uname('r'); } catch (\danog\MadelineProto\Exception $e) { $system_version = phpversion(); } if ($settings['app_info']['api_id'] === 6) { // TG DEV NOTICE: these app info spoofing measures were implemented for NON-MALICIOUS purposes. // All accounts registered with a custom API ID require manual verification through recover@telegram.org, to avoid instant permabans. // This makes usage of all MTProto libraries very difficult, at least for new users. // To help a bit, when the android API ID is used, the android app infos are spoofed too. // THE ANDROID API HASH IS NOT PRESENT IN THIS REPOSITORY, AND WILL NOT BE GIVEN TO EVERYONE. // This measure was NOT created with the intent to aid spammers, flooders, and other scum. // // I understand that automated account registration through headless libraries may indicate the creation of a botnet, //...and I understand why these automatic bans were implemented in the first place. // Manual requests to activate numbers through recover@telegram.org will still be required for the majority of users of this library, //...and in particular those that choose to user their own API ID for their application. // // To be honest, I wrote this feature just for me, since I honestly don't want to //...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) $system_version = 'SDK 28'; } // Detect language $lang_code = 'en'; Lang::$current_lang = &Lang::$lang[$lang_code]; if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $lang_code = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); } elseif (isset($_SERVER['LANG'])) { $lang_code = explode('_', $_SERVER['LANG'])[0]; } if (isset(Lang::$lang[$lang_code])) { Lang::$current_lang = &Lang::$lang[$lang_code]; } // Detect language pack $lang_pack = ''; if ($settings['app_info']['api_id'] === 6) { // TG DEV NOTICE: these app info spoofing measures were implemented for NON-MALICIOUS purposes. // All accounts registered with a custom API ID require manual verification through recover@telegram.org, to avoid instant permabans. // This makes usage of all MTProto libraries very difficult, at least for new users. // To help a bit, when the android API ID is used, the android app infos are spoofed too. // THE ANDROID API HASH IS NOT PRESENT IN THIS REPOSITORY, AND WILL NOT BE GIVEN TO EVERYONE. // This measure was NOT created with the intent to aid spammers, flooders, and other scum. // // I understand that automated account registration through headless libraries may indicate the creation of a botnet, //...and I understand why these automatic bans were implemented in the first place. // Manual requests to activate numbers through recover@telegram.org will still be required for the majority of users of this library, //...and in particular those that choose to user their own API ID for their application. // // To be honest, I wrote this feature just for me, since I honestly don't want to //...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) $lang_pack = 'android'; } // Detect app version $app_version = self::RELEASE.' ('.self::V.', '.Magic::$revision.')'; if ($settings['app_info']['api_id'] === 6) { // TG DEV NOTICE: these app info spoofing measures were implemented for NON-MALICIOUS purposes. // All accounts registered with a custom API ID require manual verification through recover@telegram.org, to avoid instant permabans. // This makes usage of all MTProto libraries very difficult, at least for new users. // To help a bit, when the android API ID is used, the android app infos are spoofed too. // THE ANDROID API HASH IS NOT PRESENT IN THIS REPOSITORY, AND WILL NOT BE GIVEN TO EVERYONE. // This measure was NOT created with the intent to aid spammers, flooders, and other scum. // // I understand that automated account registration through headless libraries may indicate the creation of a botnet, //...and I understand why these automatic bans were implemented in the first place. // Manual requests to activate numbers through recover@telegram.org will still be required for the majority of users of this library, //...and in particular those that choose to user their own API ID for their application. // // To be honest, I wrote this feature just for me, since I honestly don't want to //...go through the hassle of registering => recovering => logging in to every account I use for my services (mainly webradios and test userbots) $app_version = '4.9.1 (13613)'; } // Set default settings $default_settings = ['authorization' => [ // Authorization settings 'default_temp_auth_key_expires_in' => 1 * 24 * 60 * 60, // validity of temporary keys and the binding of the temporary and permanent keys 'rsa_keys' => ["-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\nlyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\nan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw\nEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n-----END RSA PUBLIC KEY-----", "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAxq7aeLAqJR20tkQQMfRn+ocfrtMlJsQ2Uksfs7Xcoo77jAid0bRt\nksiVmT2HEIJUlRxfABoPBV8wY9zRTUMaMA654pUX41mhyVN+XoerGxFvrs9dF1Ru\nvCHbI02dM2ppPvyytvvMoefRoL5BTcpAihFgm5xCaakgsJ/tH5oVl74CdhQw8J5L\nxI/K++KJBUyZ26Uba1632cOiq05JBUW0Z2vWIOk4BLysk7+U9z+SxynKiZR3/xdi\nXvFKk01R3BHV+GUKM2RYazpS/P8v7eyKhAbKxOdRcFpHLlVwfjyM1VlDQrEZxsMp\nNTLYXb6Sce1Uov0YtNx5wEowlREH1WOTlwIDAQAB\n-----END RSA PUBLIC KEY-----", "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAsQZnSWVZNfClk29RcDTJQ76n8zZaiTGuUsi8sUhW8AS4PSbPKDm+\nDyJgdHDWdIF3HBzl7DHeFrILuqTs0vfS7Pa2NW8nUBwiaYQmPtwEa4n7bTmBVGsB\n1700/tz8wQWOLUlL2nMv+BPlDhxq4kmJCyJfgrIrHlX8sGPcPA4Y6Rwo0MSqYn3s\ng1Pu5gOKlaT9HKmE6wn5Sut6IiBjWozrRQ6n5h2RXNtO7O2qCDqjgB2vBxhV7B+z\nhRbLbCmW0tYMDsvPpX5M8fsO05svN+lKtCAuz1leFns8piZpptpSCFn7bWxiA9/f\nx5x17D7pfah3Sy2pA+NDXyzSlGcKdaUmwQIDAQAB\n-----END RSA PUBLIC KEY-----", "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAwqjFW0pi4reKGbkc9pK83Eunwj/k0G8ZTioMMPbZmW99GivMibwa\nxDM9RDWabEMyUtGoQC2ZcDeLWRK3W8jMP6dnEKAlvLkDLfC4fXYHzFO5KHEqF06i\nqAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc\n/n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks\nWV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t\nUiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB\n-----END RSA PUBLIC KEY-----"], ], 'connection' => [ // List of datacenters/subdomains where to connect 'ssl_subdomains' => [ // Subdomains of web.telegram.org for https protocol 1 => 'pluto', 2 => 'venus', 3 => 'aurora', 4 => 'vesta', 5 => 'flora', ], 'test' => [ // Test datacenters 'ipv4' => [ // ipv4 addresses 2 => [ // The rest will be fetched using help.getConfig 'ip_address' => '149.154.167.40', 'port' => 443, 'media_only' => false, 'tcpo_only' => false, ], ], 'ipv6' => [ // ipv6 addresses 2 => [ // The rest will be fetched using help.getConfig 'ip_address' => '2001:067c:04e8:f002:0000:0000:0000:000e', 'port' => 443, 'media_only' => false, 'tcpo_only' => false, ], ], ], 'main' => [ // Main datacenters 'ipv4' => [ // ipv4 addresses 2 => [ // The rest will be fetched using help.getConfig 'ip_address' => '149.154.167.51', 'port' => 443, 'media_only' => false, 'tcpo_only' => false, ], ], 'ipv6' => [ // ipv6 addresses 2 => [ // The rest will be fetched using help.getConfig 'ip_address' => '2001:067c:04e8:f002:0000:0000:0000:000a', 'port' => 443, 'media_only' => false, 'tcpo_only' => false, ], ], ], ], 'connection_settings' => [ // connection settings 'all' => [ // These settings will be applied on every datacenter that hasn't a custom settings subarray... 'protocol' => 'tcp_abridged', // can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported) 'test_mode' => false, // decides whether to connect to the main telegram servers or to the testing servers (deep telegram) 'ipv6' => \danog\MadelineProto\Magic::$ipv6, // decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean 'timeout' => 2, // timeout for sockets 'proxy' => Magic::$altervista ? '\\HttpProxy' : '\\Socket', // The proxy class to use 'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [], // Extra parameters to pass to the proxy class using setExtra 'obfuscated' => false, 'transport' => 'tcp', 'pfs' => extension_loaded('gmp'), ], 'default_dc' => 2, ], 'app_info' => [ // obtained in https://my.telegram.org //'api_id' => you should put an API id in the settings array you provide //'api_hash' => you should put an API hash in the settings array you provide 'device_model' => $device_model, 'system_version' => $system_version, 'app_version' => $app_version, // 🌚 // 'app_version' => self::V, 'lang_code' => $lang_code, 'lang_pack' => $lang_pack, ], 'tl_schema' => [ // TL scheme files 'layer' => 97, // layer version 'src' => [ 'mtproto' => __DIR__.'/TL_mtproto_v1.tl', // mtproto TL scheme 'telegram' => __DIR__.'/TL_telegram_v97.tl', // telegram TL scheme 'secret' => __DIR__.'/TL_secret.tl', // secret chats TL scheme 'calls' => __DIR__.'/TL_calls.tl', // calls TL scheme //'td' => __DIR__.'/TL_td.tl', // telegram-cli TL scheme 'botAPI' => __DIR__.'/TL_botAPI.tl', ], ], 'logger' => [ // Logger settings /* * logger modes: * 0 - No logger * 1 - Log to the default logger destination * 2 - Log to file defined in second parameter * 3 - Echo logs * 4 - Call callable provided in logger_param. logger_param must accept two parameters: array $message, int $level * $message is an array containing the messages the log, $level, is the logging level */ // write to 'logger_param' => Magic::$script_cwd.'/MadelineProto.log', 'logger' => php_sapi_name() === 'cli' ? 3 : 2, // overwrite previous setting and echo logs 'logger_level' => Logger::VERBOSE, 'max_size' => 100 * 1024 * 1024, // Logging level, available logging levels are: ULTRA_VERBOSE, VERBOSE, NOTICE, WARNING, ERROR, FATAL_ERROR. Can be provided as last parameter to the logging function. 'rollbar_token' => '', ], 'max_tries' => [ 'query' => 5, // How many times should I try to call a method or send an object before throwing an exception 'authorization' => 5, // How many times should I try to generate an authorization key before throwing an exception 'response' => 5, ], 'flood_timeout' => ['wait_if_lt' => 10 * 60], 'msg_array_limit' => [ // How big should be the arrays containing the incoming and outgoing messages? 'incoming' => 100, 'outgoing' => 100, 'call_queue' => 200, ], 'peer' => [ 'full_info_cache_time' => 3600, // Full peer info cache validity 'full_fetch' => false, // Should madeline fetch the full member list of every group it meets? 'cache_all_peers_on_startup' => false, ], 'requests' => ['gzip_encode_if_gt' => 1024 * 1024], 'updates' => [ 'handle_updates' => false, // Should I handle updates? 'handle_old_updates' => true, // Should I handle old updates on startup? 'getdifference_interval' => 10, // Getdifference manual polling interval 'callback' => 'get_updates_update_handler', // Update callback 'run_callback' => true, ], 'secret_chats' => ['accept_chats' => true], 'serialization' => ['serialization_interval' => 30], 'threading' => [ 'allow_threading' => false, // Should I use threading, if it is enabled? 'handler_workers' => 10, ], 'upload' => [ 'allow_automatic_upload' => true, 'part_size' => 512 * 1024, ], 'download' => [ 'report_broken_media' => true, 'part_size' => 1024 * 1024, ], 'pwr' => [ 'pwr' => false, // Need info ? 'db_token' => false, // Need info ? 'strict' => false, // Need info ? 'requests' => true, ]]; if (!is_array($settings)) { $settings = []; } $settings = array_replace_recursive($default_settings, $settings); if (isset(Lang::$lang[$settings['app_info']['lang_code']])) { Lang::$current_lang = &Lang::$lang[$settings['app_info']['lang_code']]; } /*if ($settings['app_info']['api_id'] < 20) { $settings['connection_settings']['all']['protocol'] = 'obfuscated2'; }*/ switch ($settings['logger']['logger_level']) { case 'ULTRA_VERBOSE': $settings['logger']['logger_level'] = 5; break; case 'VERBOSE': $settings['logger']['logger_level'] = 4; break; case 'NOTICE': $settings['logger']['logger_level'] = 3; break; case 'WARNING': $settings['logger']['logger_level'] = 2; break; case 'ERROR': $settings['logger']['logger_level'] = 1; break; case 'FATAL ERROR': $settings['logger']['logger_level'] = 0; break; } $this->settings = $settings; if (!$this->settings['updates']['handle_updates']) { $this->updates = []; } // Setup logger $this->setup_logger(); } public function setup_logger() { if (isset($this->settings['logger']['rollbar_token']) && $this->settings['logger']['rollbar_token'] !== '' && class_exists('\\Rollbar\\Rollbar')) { @\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => isset($this->settings['logger']['rollbar_token']) && !in_array($this->settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718', '11a8c2fe4c474328b40a28193f8d63f5', 'beef2d426496462ba34dcaad33d44a14']) || $this->settings['pwr']['pwr'] ? $this->settings['logger']['rollbar_token'] : 'c07d9b2f73c2461297b0beaef6c1662f'], false, false); } else { Exception::$rollbar = false; RPCErrorException::$rollbar = false; } if (php_sapi_name() !== 'cli') { if (isset($this->settings['logger']['logger_param']) && basename($this->settings['logger']['logger_param']) === 'MadelineProto.log') { $this->settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log'; } } $this->logger = new \danog\MadelineProto\Logger($this->settings['logger']['logger'], isset($this->settings['logger']['logger_param']) ? $this->settings['logger']['logger_param'] : '', isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : '', isset($this->settings['logger']['logger_level']) ? $this->settings['logger']['logger_level'] : Logger::VERBOSE, isset($this->settings['logger']['max_size']) ? $this->settings['logger']['max_size'] : 100 * 1024 * 1024); if (!\danog\MadelineProto\Logger::$default) { \danog\MadelineProto\Logger::constructor($this->settings['logger']['logger'], $this->settings['logger']['logger_param'], isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : '', isset($this->settings['logger']['logger_level']) ? $this->settings['logger']['logger_level'] : Logger::VERBOSE, isset($this->settings['logger']['max_size']) ? $this->settings['logger']['max_size'] : 100 * 1024 * 1024); } if (php_sapi_name() !== 'cli') { try { error_reporting(E_ALL); ini_set('log_errors', 1); ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log'); error_log('Enabled PHP logging'); } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('Could not enable PHP logging'); } } } public function reset_session($de = true, $auth_key = false) { if (!is_object($this->datacenter)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['session_corrupted']); } foreach ($this->datacenter->sockets as $id => $socket) { if ($de) { //$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['reset_session_seqno'], $id), Logger::VERBOSE); $socket->session_id = $this->random(8); $socket->session_in_seq_no = 0; $socket->session_out_seq_no = 0; $socket->max_incoming_id = null; $socket->max_outgoing_id = null; } if ($auth_key) { $socket->temp_auth_key = null; } /* $socket->incoming_messages = []; $socket->outgoing_messages = []; $socket->new_outgoing = []; $socket->new_incoming = []; */ } } public function is_http($datacenter) { return in_array($this->datacenter->sockets[$datacenter]->getCtx()->getStreamName(), [HttpStream::getName(), HttpsStream::getName()]); } // Connects to all datacenters and if necessary creates authorization keys, binds them and writes client info public function connect_to_all_dcs_async(): \Generator { foreach ($this->channels_state->get() as $state) { $channelId = $state->getChannel(); if (!isset($this->feeders[$channelId])) { $this->feeders[$channelId] = new FeedLoop($this, $channelId); } if (!isset($this->updaters[$channelId])) { $this->updaters[$channelId] = new UpdateLoop($this, $channelId); } } if (!isset($this->seqUpdater)) { $this->seqUpdater = new SeqLoop($this); } $this->datacenter->__construct($this, $this->settings['connection'], $this->settings['connection_settings']); $dcs = []; foreach ($this->datacenter->get_dcs() as $new_dc) { $dcs[] = $this->datacenter->dcConnectAsync($new_dc); } yield $this->all($dcs); yield $this->init_authorization_async(); $dcs = []; foreach ($this->datacenter->get_dcs(false) as $new_dc) { $dcs[] = $this->datacenter->dcConnectAsync($new_dc); } yield $this->all($dcs); yield $this->init_authorization_async(); if (!$this->phoneConfigWatcherId) { $this->phoneConfigWatcherId = Loop::repeat(24 * 3600 * 1000, [$this, 'get_phone_config_async']); } yield $this->get_phone_config_async(); } public function resetSession() { if (isset($this->seqUpdater)) { $this->seqUpdater->signal(true); unset($this->seqUpdater); } $channelIds = []; foreach ($this->channels_state->get() as $state) { $channelIds[] = $state->getChannel(); } sort($channelIds); foreach ($channelIds as $channelId) { if (isset($this->feeders[$channelId])) { $this->feeders[$channelId]->signal(true); unset($this->feeders[$channelId]); } if (!isset($this->updaters[$channelId])) { $this->updaters[$channelId]->signal(true); unset($this->updaters[$channelId]); } } foreach ($this->datacenter->sockets as $socket) { $socket->authorized = false; } $this->channels_state = new CombinedUpdatesState(); $this->got_state = false; $this->msg_ids = []; $this->authorized = self::NOT_LOGGED_IN; $this->authorized_dc = -1; $this->authorization = null; $this->updates = []; $this->secret_chats = []; $this->chats = []; $this->users = []; $this->tos = ['expires' => 0, 'accepted' => true]; $this->referenceDatabase = new ReferenceDatabase($this); $this->dialog_params = ['_' => 'MadelineProto.dialogParams', 'limit' => 0, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0]; $this->full_chats = []; } public function resetUpdateSystem() { foreach ($this->channels_state->get() as $state) { $channelId = $state->getChannel(); $this->channels_state->__construct([$channelId => new UpdatesState()]); } $this->startUpdateSystem(); } public function startUpdateSystem($anyway = false) { if ($this->asyncInitPromise && !$anyway) { $this->logger("Not starting update system"); return; } $this->logger("Starting update system"); if (!isset($this->seqUpdater)) { $this->seqUpdater = new SeqLoop($this); } $channelIds = []; foreach ($this->channels_state->get() as $state) { $channelIds[] = $state->getChannel(); } sort($channelIds); foreach ($channelIds as $channelId) { if (!isset($this->feeders[$channelId])) { $this->feeders[$channelId] = new FeedLoop($this, $channelId); } if (!isset($this->updaters[$channelId])) { $this->updaters[$channelId] = new UpdateLoop($this, $channelId); } if ($this->feeders[$channelId]->start() && isset($this->feeders[$channelId])) { $this->feeders[$channelId]->resume(); } if ($this->updaters[$channelId]->start() && isset($this->updaters[$channelId])) { $this->updaters[$channelId]->resume(); } } foreach ($this->datacenter->sockets as $datacenter) {$datacenter->writer->resume();} if ($this->seqUpdater->start()) { $this->seqUpdater->resume(); } } public function get_phone_config_async($watcherId = null) { if ($this->authorized === self::LOGGED_IN && class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal') && !$this->authorization['user']['bot'] && $this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->temp_auth_key !== null) { $this->logger->logger('Fetching phone config...'); VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->settings['connection_settings']['default_dc']])); } else { $this->logger->logger('Not fetching phone config'); } } public function get_config_async($config = [], $options = []) { if ($this->config['expires'] > time()) { return $this->config; } $this->config = empty($config) ? yield $this->method_call_async_read('help.getConfig', $config, empty($options) ? ['datacenter' => $this->settings['connection_settings']['default_dc']] : $options) : $config; yield $this->parse_config_async(); return $this->config; } public function get_cdn_config_async($datacenter) { /* * *********************************************************************** * Fetch RSA keys for CDN datacenters */ try { foreach ((yield $this->method_call_async_read('help.getCdnConfig', [], ['datacenter' => $datacenter]))['public_keys'] as $curkey) { $tempkey = new \danog\MadelineProto\RSA($curkey['public_key']); $this->rsa_keys[$tempkey->fp] = $tempkey; } } catch (\danog\MadelineProto\TL\Exception $e) { $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::FATAL_ERROR); } } public function parse_config_async() { if (isset($this->config['dc_options'])) { yield $this->parse_dc_options_async($this->config['dc_options']); unset($this->config['dc_options']); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['config_updated'], Logger::NOTICE); $this->logger->logger($this->config, Logger::NOTICE); } public function parse_dc_options_async($dc_options) { unset($this->settings[$this->config['test_mode']]); foreach ($dc_options as $dc) { $test = $this->config['test_mode'] ? 'test' : 'main'; $id = $dc['id']; if (isset($dc['static'])) { //$id .= $dc['static'] ? '_static' : ''; } if (isset($dc['cdn'])) { $id .= $dc['cdn'] ? '_cdn' : ''; } $id .= $dc['media_only'] ? '_media' : ''; $ipv6 = $dc['ipv6'] ? 'ipv6' : 'ipv4'; //$id .= isset($this->settings['connection'][$test][$ipv6][$id]) && $this->settings['connection'][$test][$ipv6][$id]['ip_address'] != $dc['ip_address'] ? '_bk' : ''; if (is_numeric($id)) { $id = (int) $id; } unset($dc['cdn']); unset($dc['media_only']); unset($dc['id']); unset($dc['ipv6']); $this->settings['connection'][$test][$ipv6][$id] = $dc; } $curdc = $this->datacenter->curdc; $this->logger->logger('Got new DC options, reconnecting'); yield $this->connect_to_all_dcs_async(); $this->datacenter->curdc = $curdc; } public function get_self_async() { try { $this->authorization = ['user' => (yield $this->method_call_async_read('users.getUsers', ['id' => [['_' => 'inputUserSelf']]], ['datacenter' => $this->datacenter->curdc]))[0]]; } catch (RPCErrorException $e) { $this->logger->logger($e->getMessage()); return false; } return $this->authorization['user']; } public function getMethodCallbacks(): array { return []; } public function getMethodBeforeCallbacks(): array { return []; } public function getConstructorCallbacks(): array { return array_merge( array_fill_keys(['chat', 'chatEmpty', 'chatForbidden', 'channel', 'channelEmpty', 'channelForbidden'], [[$this, 'add_chat_async']]), array_fill_keys(['user', 'userEmpty'], [[$this, 'add_user']]), ['help.support' => [[$this, 'add_support']]] ); } public function getConstructorBeforeCallbacks(): array { return []; } public function getConstructorSerializeCallbacks(): array { return []; } public function getTypeMismatchCallbacks(): array { return array_merge( array_fill_keys(['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer', 'InputDialogPeer', 'InputNotifyPeer'], [$this, 'get_info_async']), array_fill_keys(['InputMedia', 'InputDocument', 'InputPhoto'], [$this, 'get_file_info_async']), array_fill_keys(['InputFileLocation'], [$this, 'get_download_info_async']) ); } public function __debugInfo() { return ['MadelineProto instance '.spl_object_hash($this)]; } const ALL_MIMES = ['webp' => [0 => 'image/webp'], 'png' => [0 => 'image/png', 1 => 'image/x-png'], 'bmp' => [0 => 'image/bmp', 1 => 'image/x-bmp', 2 => 'image/x-bitmap', 3 => 'image/x-xbitmap', 4 => 'image/x-win-bitmap', 5 => 'image/x-windows-bmp', 6 => 'image/ms-bmp', 7 => 'image/x-ms-bmp', 8 => 'application/bmp', 9 => 'application/x-bmp', 10 => 'application/x-win-bitmap'], 'gif' => [0 => 'image/gif'], 'jpeg' => [0 => 'image/jpeg', 1 => 'image/pjpeg'], 'xspf' => [0 => 'application/xspf+xml'], 'vlc' => [0 => 'application/videolan'], 'wmv' => [0 => 'video/x-ms-wmv', 1 => 'video/x-ms-asf'], 'au' => [0 => 'audio/x-au'], 'ac3' => [0 => 'audio/ac3'], 'flac' => [0 => 'audio/x-flac'], 'ogg' => [0 => 'audio/ogg', 1 => 'video/ogg', 2 => 'application/ogg'], 'kmz' => [0 => 'application/vnd.google-earth.kmz'], 'kml' => [0 => 'application/vnd.google-earth.kml+xml'], 'rtx' => [0 => 'text/richtext'], 'rtf' => [0 => 'text/rtf'], 'jar' => [0 => 'application/java-archive', 1 => 'application/x-java-application', 2 => 'application/x-jar'], 'zip' => [0 => 'application/x-zip', 1 => 'application/zip', 2 => 'application/x-zip-compressed', 3 => 'application/s-compressed', 4 => 'multipart/x-zip'], '7zip' => [0 => 'application/x-compressed'], 'xml' => [0 => 'application/xml', 1 => 'text/xml'], 'svg' => [0 => 'image/svg+xml'], '3g2' => [0 => 'video/3gpp2'], '3gp' => [0 => 'video/3gp', 1 => 'video/3gpp'], 'mp4' => [0 => 'video/mp4'], 'm4a' => [0 => 'audio/x-m4a'], 'f4v' => [0 => 'video/x-f4v'], 'flv' => [0 => 'video/x-flv'], 'webm' => [0 => 'video/webm'], 'aac' => [0 => 'audio/x-acc'], 'm4u' => [0 => 'application/vnd.mpegurl'], 'pdf' => [0 => 'application/pdf', 1 => 'application/octet-stream'], 'pptx' => [0 => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], 'ppt' => [0 => 'application/powerpoint', 1 => 'application/vnd.ms-powerpoint', 2 => 'application/vnd.ms-office', 3 => 'application/msword'], 'docx' => [0 => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], 'xlsx' => [0 => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 1 => 'application/vnd.ms-excel'], 'xl' => [0 => 'application/excel'], 'xls' => [0 => 'application/msexcel', 1 => 'application/x-msexcel', 2 => 'application/x-ms-excel', 3 => 'application/x-excel', 4 => 'application/x-dos_ms_excel', 5 => 'application/xls', 6 => 'application/x-xls'], 'xsl' => [0 => 'text/xsl'], 'mpeg' => [0 => 'video/mpeg'], 'mov' => [0 => 'video/quicktime'], 'avi' => [0 => 'video/x-msvideo', 1 => 'video/msvideo', 2 => 'video/avi', 3 => 'application/x-troff-msvideo'], 'movie' => [0 => 'video/x-sgi-movie'], 'log' => [0 => 'text/x-log'], 'txt' => [0 => 'text/plain'], 'css' => [0 => 'text/css'], 'html' => [0 => 'text/html'], 'wav' => [0 => 'audio/x-wav', 1 => 'audio/wave', 2 => 'audio/wav'], 'xhtml' => [0 => 'application/xhtml+xml'], 'tar' => [0 => 'application/x-tar'], 'tgz' => [0 => 'application/x-gzip-compressed'], 'psd' => [0 => 'application/x-photoshop', 1 => 'image/vnd.adobe.photoshop'], 'exe' => [0 => 'application/x-msdownload'], 'js' => [0 => 'application/x-javascript'], 'mp3' => [0 => 'audio/mpeg', 1 => 'audio/mpg', 2 => 'audio/mpeg3', 3 => 'audio/mp3'], 'rar' => [0 => 'application/x-rar', 1 => 'application/rar', 2 => 'application/x-rar-compressed'], 'gzip' => [0 => 'application/x-gzip'], 'hqx' => [0 => 'application/mac-binhex40', 1 => 'application/mac-binhex', 2 => 'application/x-binhex40', 3 => 'application/x-mac-binhex40'], 'cpt' => [0 => 'application/mac-compactpro'], 'bin' => [0 => 'application/macbinary', 1 => 'application/mac-binary', 2 => 'application/x-binary', 3 => 'application/x-macbinary'], 'oda' => [0 => 'application/oda'], 'ai' => [0 => 'application/postscript'], 'smil' => [0 => 'application/smil'], 'mif' => [0 => 'application/vnd.mif'], 'wbxml' => [0 => 'application/wbxml'], 'wmlc' => [0 => 'application/wmlc'], 'dcr' => [0 => 'application/x-director'], 'dvi' => [0 => 'application/x-dvi'], 'gtar' => [0 => 'application/x-gtar'], 'php' => [0 => 'application/x-httpd-php', 1 => 'application/php', 2 => 'application/x-php', 3 => 'text/php', 4 => 'text/x-php', 5 => 'application/x-httpd-php-source'], 'swf' => [0 => 'application/x-shockwave-flash'], 'sit' => [0 => 'application/x-stuffit'], 'z' => [0 => 'application/x-compress'], 'mid' => [0 => 'audio/midi'], 'aif' => [0 => 'audio/x-aiff', 1 => 'audio/aiff'], 'ram' => [0 => 'audio/x-pn-realaudio'], 'rpm' => [0 => 'audio/x-pn-realaudio-plugin'], 'ra' => [0 => 'audio/x-realaudio'], 'rv' => [0 => 'video/vnd.rn-realvideo'], 'jp2' => [0 => 'image/jp2', 1 => 'video/mj2', 2 => 'image/jpx', 3 => 'image/jpm'], 'tiff' => [0 => 'image/tiff'], 'eml' => [0 => 'message/rfc822'], 'pem' => [0 => 'application/x-x509-user-cert', 1 => 'application/x-pem-file'], 'p10' => [0 => 'application/x-pkcs10', 1 => 'application/pkcs10'], 'p12' => [0 => 'application/x-pkcs12'], 'p7a' => [0 => 'application/x-pkcs7-signature'], 'p7c' => [0 => 'application/pkcs7-mime', 1 => 'application/x-pkcs7-mime'], 'p7r' => [0 => 'application/x-pkcs7-certreqresp'], 'p7s' => [0 => 'application/pkcs7-signature'], 'crt' => [0 => 'application/x-x509-ca-cert', 1 => 'application/pkix-cert'], 'crl' => [0 => 'application/pkix-crl', 1 => 'application/pkcs-crl'], 'pgp' => [0 => 'application/pgp'], 'gpg' => [0 => 'application/gpg-keys'], 'rsa' => [0 => 'application/x-pkcs7'], 'ics' => [0 => 'text/calendar'], 'zsh' => [0 => 'text/x-scriptzsh'], 'cdr' => [0 => 'application/cdr', 1 => 'application/coreldraw', 2 => 'application/x-cdr', 3 => 'application/x-coreldraw', 4 => 'image/cdr', 5 => 'image/x-cdr', 6 => 'zz-application/zz-winassoc-cdr'], 'wma' => [0 => 'audio/x-ms-wma'], 'vcf' => [0 => 'text/x-vcard'], 'srt' => [0 => 'text/srt'], 'vtt' => [0 => 'text/vtt'], 'ico' => [0 => 'image/x-icon', 1 => 'image/x-ico', 2 => 'image/vnd.microsoft.icon'], 'csv' => [0 => 'text/x-comma-separated-values', 1 => 'text/comma-separated-values', 2 => 'application/vnd.msexcel'], 'json' => [0 => 'application/json', 1 => 'text/json']]; } ---types--- ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia; inputMediaPoll#6b3765b poll:Poll = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#edd2a791 flags:# id:int participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int = ChatFull; channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonChildAbuse#adf44ee3 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#22893b26 chat_id:int id:int = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; documentEmpty#36f8c871 id:long = Document; document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyBroadcasts#d612e8ef = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; textSubscript#ed6a8504 text:RichText = RichText; textSuperscript#c7fb5e01 text:RichText = RichText; textMarked#34b8621 text:RichText = RichText; textPhone#1ccb966a text:RichText phone:string = RichText; textImage#81ccf4f document_id:long w:int h:int = RichText; textAnchor#35553762 text:RichText name:string = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#e4e88011 items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; pageBlockKicker#1e148390 text:RichText = PageBlock; pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; help.passportConfigNotModified#bfb9f457 = help.PassportConfig; help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; jsonNull#3f6d7b68 = JSONValue; jsonBool#c7345e6a value:Bool = JSONValue; jsonNumber#2be0dfa4 value:double = JSONValue; jsonString#b71e767a value:string = JSONValue; jsonArray#f7444763 value:Vector = JSONValue; jsonObject#99c1d49d value:Vector = JSONValue; pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; pageCaption#6f747657 text:RichText credit:RichText = PageCaption; pageListItemText#b92fb6cd text:RichText = PageListItem; pageListItemBlocks#25e073fc blocks:Vector = PageListItem; pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector = Page; help.supportName#8c05f1c9 name:string = help.SupportName; help.userInfoEmpty#f3ae2eed = help.UserInfo; help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer; poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector = Poll; pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters; pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int = PollResults; chatOnlines#f041e250 onlines:int = ChatOnlines; statsURL#47a971e0 url:string = StatsURL; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; account.confirmPasswordEmail#8fdf1920 code:string = Bool; account.resendPasswordEmail#7a7f2a15 = Bool; account.cancelPasswordEmail#c1cbd5b6 = Bool; account.getContactSignUpNotification#9f07c728 = Bool; account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; contacts.getContactIDs#2caa4a42 hash:int = Vector; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.deleteByPhones#1013fd9e phones:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector; messages.clearAllDrafts#7e58ee9c = Bool; messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates; messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; messages.getStatsURL#83f6c0cd peer:InputPeer = StatsURL; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#522d5a7d source:string = help.AppUpdate; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; help.getAppConfig#98914110 = JSONValue; help.saveAppLog#6f02f748 events:Vector = Bool; help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; help.getSupportName#d360e72c = help.SupportName; help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; langpack.getDifference#9d51e814 lang_code:string from_version:int = LangPackDifference; langpack.getLanguages#42c6978f lang_pack:string = Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; // LAYER 91 resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; vector {t:Type} # [ t ] = Vector t; p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data; p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data; p_q_inner_data pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; p_q_inner_data_temp pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner; rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; msg_container#73f1f8dc messages:vector<%Message> = MessageContainer; message msg_id:long seqno:int bytes:int body:Object = Message; msg_copy#e06046b2 orig_message:Message = MessageCopy; gzip_packed#3072cfa1 packed_data:bytes = Object; msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msg_resend_ans_req#8610baeb msg_ids:Vector = MsgResendReq; msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; rsa_public_key n:string e:string = RSAPublicKey; http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ---functions--- req_pq_multi#be7e8ef1 nonce:int128 = ResPQ; req_pq nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; //test.useGzipPacked = GzipPacked; //test.useServerDhInnerData = Server_DH_inner_data; //test.useNewSessionCreated = NewSession; //test.useMsgsAck = MsgsAck; //test.useBadMsgNotification = BadMsgNotification; //test.useOther key:rsa_public_key p_q_data:P_Q_inner_data dh_data:client_DH_inner_data = RpcError; null, 'udp' => null, 'unix' => null, 'udg' => null, ]; private $sockets = []; private $socketIdUriMap = []; private $pendingCount = []; private $idleTimeout; private $socketContext; private $dataCenter; public function __construct(DataCenter $dataCenter, int $idleTimeout = 10000, ClientConnectContext $socketContext = null) { $this->idleTimeout = $idleTimeout; $this->socketContext = $socketContext ?? new ClientConnectContext(); $this->dataCenter = $dataCenter; } /** * @param string $uri * * @throws SocketException * * @return string */ private function normalizeUri(string $uri): string { if (\stripos($uri, 'unix://') === 0) { return $uri; } try { $parts = Uri\parse($uri); } catch (\Exception $exception) { throw new SocketException('Could not parse URI', 0, $exception); } if ($parts['scheme'] === null) { throw new SocketException('Invalid URI for socket pool; no scheme given'); } $port = $parts['port'] ?? 0; if ($parts['host'] === null || $port === 0) { throw new SocketException('Invalid URI for socket pool; missing host or port'); } $scheme = \strtolower($parts['scheme']); $host = \strtolower($parts['host']); if (!\array_key_exists($scheme, self::ALLOWED_SCHEMES)) { throw new SocketException(\sprintf( "Invalid URI for socket pool; '%s' scheme not allowed - scheme must be one of %s", $scheme, \implode(', ', \array_keys(self::ALLOWED_SCHEMES)) )); } if ($parts['query'] !== null || $parts['fragment'] !== null) { throw new SocketException('Invalid URI for socket pool; query or fragment components not allowed'); } if ($parts['path'] !== '') { throw new SocketException('Invalid URI for socket pool; path component must be empty'); } if ($parts['user'] !== null) { throw new SocketException('Invalid URI for socket pool; user component not allowed'); } return $scheme.'://'.$host.':'.$port; } /** {@inheritdoc} */ public function checkout(string $uri, CancellationToken $token = null): Promise { // A request might already be cancelled before we reach the checkout, so do not even attempt to checkout in that // case. The weird logic is required to throw the token's exception instead of creating a new one. if ($token && $token->isRequested()) { try { $token->throwIfRequested(); } catch (CancelledException $e) { return new Failure($e); } } $uri = $this->normalizeUri($uri); if (empty($this->sockets[$uri])) { return $this->checkoutNewSocket($uri, $token); } foreach ($this->sockets[$uri] as $socketId => $socket) { if (!$socket->isAvailable) { continue; } if (!\is_resource($socket->resource) || \feof($socket->resource)) { $this->clearFromId((int) $socket->resource); continue; } $socket->isAvailable = false; if ($socket->idleWatcher !== null) { Loop::disable($socket->idleWatcher); } return new Success(new ClientSocket($socket->resource)); } return $this->checkoutNewSocket($uri, $token); } private function checkoutNewSocket(string $uri, CancellationToken $token = null): Promise { return call(function () use ($uri, $token) { $this->pendingCount[$uri] = ($this->pendingCount[$uri] ?? 0) + 1; try { /** @var ClientSocket $rawSocket */ $rawSocket = yield $this->call($this->dataCenter->rawConnectAsync($uri, $token, $this->socketContext)); } finally { if (--$this->pendingCount[$uri] === 0) { unset($this->pendingCount[$uri]); } } $socketId = (int) $rawSocket->getResource(); $socket = new class() { use Struct; public $id; public $uri; public $resource; public $isAvailable; public $idleWatcher; }; $socket->id = $socketId; $socket->uri = $uri; $socket->resource = $rawSocket->getResource(); $socket->isAvailable = false; $this->sockets[$uri][$socketId] = $socket; $this->socketIdUriMap[$socketId] = $uri; return $rawSocket; }); } /** {@inheritdoc} */ public function clear(ClientSocket $socket): void { $this->clearFromId((int) $socket->getResource()); } /** * @param int $socketId */ private function clearFromId(int $socketId): void { if (!isset($this->socketIdUriMap[$socketId])) { throw new \Error( \sprintf('Unknown socket: %d', $socketId) ); } $uri = $this->socketIdUriMap[$socketId]; $socket = $this->sockets[$uri][$socketId]; if ($socket->idleWatcher) { Loop::cancel($socket->idleWatcher); } unset( $this->sockets[$uri][$socketId], $this->socketIdUriMap[$socketId] ); if (empty($this->sockets[$uri])) { unset($this->sockets[$uri]); } } /** {@inheritdoc} */ public function checkin(ClientSocket $socket): void { $socketId = (int) $socket->getResource(); if (!isset($this->socketIdUriMap[$socketId])) { throw new \Error( \sprintf('Unknown socket: %d', $socketId) ); } $uri = $this->socketIdUriMap[$socketId]; $resource = $socket->getResource(); if (!\is_resource($resource) || \feof($resource)) { $this->clearFromId((int) $resource); return; } $socket = $this->sockets[$uri][$socketId]; $socket->isAvailable = true; if (isset($socket->idleWatcher)) { Loop::enable($socket->idleWatcher); } else { $socket->idleWatcher = Loop::delay($this->idleTimeout, function () use ($socket) { $this->clearFromId((int) $socket->resource); }); Loop::unreference($socket->idleWatcher); } } } { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-2106507297", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "2004934137", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1930607688", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "1537633299", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" }, { "name": "views", "type": "flags.10?int" } ], "type": "Message" }, { "id": "-1066691065", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-136766906", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-892863022", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1311946900", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-719474725", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "585404530", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "1737397639", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "763724588", "predicate": "channelForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ResolvedPeer" }, { "id": "-88925533", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "1620337698", "predicate": "updateChannelTooLong", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1016324548", "predicate": "updateChannelGroup", "params": [ { "name": "channel_id", "type": "int" }, { "name": "group", "type": "MessageGroup" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" }, { "id": "-100588754", "predicate": "channelMessagesFilterCollapsed", "params": [], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipant" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-2053423812", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1970355494", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-1336990448", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "457052156", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "chat_id", "type": "int" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "increment", "type": "Bool" } ], "type": "Vector" }, { "id": "-1445735863", "method": "channels.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-575067701", "method": "channels.getImportantHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "1428281412", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "1387358562", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Bool" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-1432183160", "method": "channels.toggleComments", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" } ] }===8=== decryptedMessage#1f814f1f random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = DecryptedMessage; decryptedMessageService#aa48327d random_id:long random_bytes:bytes action:DecryptedMessageAction = DecryptedMessage; decryptedMessageMediaEmpty#89f5c4a = DecryptedMessageMedia; decryptedMessageMediaPhoto#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaVideo#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaGeoPoint#35480a59 lat:double long:double = DecryptedMessageMedia; decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = DecryptedMessageMedia; decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = DecryptedMessageAction; decryptedMessageMediaDocument#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaAudio#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageActionReadMessages#c4f40be random_ids:Vector = DecryptedMessageAction; decryptedMessageActionDeleteMessages#65614304 random_ids:Vector = DecryptedMessageAction; decryptedMessageActionScreenshotMessages#8ac1f475 random_ids:Vector = DecryptedMessageAction; decryptedMessageActionFlushHistory#6719e45c = DecryptedMessageAction; ===17=== decryptedMessage#204d3878 random_id:long ttl:int message:string media:DecryptedMessageMedia = DecryptedMessage; decryptedMessageService#73164160 random_id:long action:DecryptedMessageAction = DecryptedMessage; decryptedMessageMediaVideo#524a415d thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaAudio#57e0a9cb duration:int mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageLayer#1be31789 random_bytes:bytes layer:int in_seq_no:int out_seq_no:int message:DecryptedMessage = DecryptedMessageLayer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#92042ff7 = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#e6ac8a6f = SendMessageAction; sendMessageUploadPhotoAction#990a3c1a = SendMessageAction; sendMessageUploadDocumentAction#8faee98e = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; decryptedMessageActionResend#511110b0 start_seq_no:int end_seq_no:int = DecryptedMessageAction; decryptedMessageActionNotifyLayer#f3048883 layer:int = DecryptedMessageAction; decryptedMessageActionTyping#ccb27641 action:SendMessageAction = DecryptedMessageAction; ===20=== decryptedMessageActionRequestKey#f3c9611b exchange_id:long g_a:bytes = DecryptedMessageAction; decryptedMessageActionAcceptKey#6fe1735b exchange_id:long g_b:bytes key_fingerprint:long = DecryptedMessageAction; decryptedMessageActionAbortKey#dd05ec6b exchange_id:long = DecryptedMessageAction; decryptedMessageActionCommitKey#ec2e0b9b exchange_id:long key_fingerprint:long = DecryptedMessageAction; decryptedMessageActionNoop#a82fdd63 = DecryptedMessageAction; ===23=== documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#fb0a5727 = DocumentAttribute; documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#51448e5 duration:int = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; decryptedMessageMediaExternalDocument#fa95b0dd id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = DecryptedMessageMedia; ===45=== decryptedMessage#36b091de flags:# random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector via_bot_name:flags.11?string reply_to_random_id:flags.3?long = DecryptedMessage; decryptedMessageMediaPhoto#f1fa8d78 thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes caption:string = DecryptedMessageMedia; decryptedMessageMediaVideo#970c8c0e thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes caption:string = DecryptedMessageMedia; decryptedMessageMediaDocument#7afe8ae2 thumb:bytes thumb_w:int thumb_h:int mime_type:string size:int key:bytes iv:bytes attributes:Vector caption:string = DecryptedMessageMedia; ===46=== decryptedMessageMediaVenue#8a0df56f lat:double long:double title:string address:string provider:string venue_id:string = DecryptedMessageMedia; documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute; decryptedMessageMediaWebPage#e50511d8 url:string = DecryptedMessageMedia; ===55=== documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute; ===66=== documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; ===73=== decryptedMessage#91cc4674 flags:# random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector via_bot_name:flags.11?string reply_to_random_id:flags.3?long grouped_id:flags.17?long = DecryptedMessage; ---types--- ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia; inputMediaPoll#6b3765b poll:Poll = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#22a235da flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int = ChatFull; channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonChildAbuse#adf44ee3 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#22893b26 chat_id:int id:int = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; documentEmpty#36f8c871 id:long = Document; document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyBroadcasts#d612e8ef = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant; channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; textSubscript#ed6a8504 text:RichText = RichText; textSuperscript#c7fb5e01 text:RichText = RichText; textMarked#34b8621 text:RichText = RichText; textPhone#1ccb966a text:RichText phone:string = RichText; textImage#81ccf4f document_id:long w:int h:int = RichText; textAnchor#35553762 text:RichText name:string = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#e4e88011 items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; pageBlockKicker#1e148390 text:RichText = PageBlock; pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; help.passportConfigNotModified#bfb9f457 = help.PassportConfig; help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; jsonNull#3f6d7b68 = JSONValue; jsonBool#c7345e6a value:Bool = JSONValue; jsonNumber#2be0dfa4 value:double = JSONValue; jsonString#b71e767a value:string = JSONValue; jsonArray#f7444763 value:Vector = JSONValue; jsonObject#99c1d49d value:Vector = JSONValue; pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; pageCaption#6f747657 text:RichText credit:RichText = PageCaption; pageListItemText#b92fb6cd text:RichText = PageListItem; pageListItemBlocks#25e073fc blocks:Vector = PageListItem; pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector = Page; help.supportName#8c05f1c9 name:string = help.SupportName; help.userInfoEmpty#f3ae2eed = help.UserInfo; help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer; poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector = Poll; pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters; pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int = PollResults; chatOnlines#f041e250 onlines:int = ChatOnlines; statsURL#47a971e0 url:string = StatsURL; chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights; chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights; inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; inputWallPaperSlug#72091c80 slug:string = InputWallPaper; account.wallPapersNotModified#1c199183 = account.WallPapers; account.wallPapers#702b65a9 hash:int wallpapers:Vector = account.WallPapers; codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings; wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#aabb1763 hash:int = account.WallPapers; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; account.confirmPasswordEmail#8fdf1920 code:string = Bool; account.resendPasswordEmail#7a7f2a15 = Bool; account.cancelPasswordEmail#c1cbd5b6 = Bool; account.getContactSignUpNotification#9f07c728 = Bool; account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates; account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; account.resetWallPapers#bb3b9804 = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; contacts.getContactIDs#2caa4a42 hash:int = Vector; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.deleteByPhones#1013fd9e phones:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector; messages.clearAllDrafts#7e58ee9c = Bool; messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates; messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; messages.getStatsURL#83f6c0cd peer:InputPeer = StatsURL; messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#522d5a7d source:string = help.AppUpdate; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; help.getAppConfig#98914110 = JSONValue; help.saveAppLog#6f02f748 events:Vector = Bool; help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; help.getSupportName#d360e72c = help.SupportName; help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; langpack.getDifference#9d51e814 lang_code:string from_version:int = LangPackDifference; langpack.getLanguages#42c6978f lang_pack:string = Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; // LAYER 95 . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; /** * Buffered proxy stream interface. * * @author Daniil Gentili */ interface BufferedProxyStreamInterface extends BufferedStreamInterface, ProxyStreamInterface { } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; use Amp\Promise; use Amp\Socket\Socket; /** * Generic stream interface. * * @author Daniil Gentili */ interface StreamInterface { /** * Connect to a server. * * @param ConnectionContext $ctx The connection context * * @return Promise */ public function connect(ConnectionContext $ctx, string $header = ''): Promise; /** * Disconnect from the server. * * @return void */ public function disconnect(); /** * Get underlying AMPHP socket resource. * * @return \Amp\Socket\Socket */ public function getSocket(): Socket; } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Transport; use Amp\Promise; use Amp\Socket\Socket; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\RawStreamInterface; use function Amp\Socket\connect; use function Amp\Socket\cryptoConnect; use danog\MadelineProto\Stream\ProxyStreamInterface; /** * Default stream wrapper. * * Manages reading data in chunks * * @author Daniil Gentili */ class DefaultStream extends Socket implements RawStreamInterface, ProxyStreamInterface { use RawStream; private $stream; private $connector = 'Amp\\Socket\\connect'; private $cryptoConnector = 'Amp\\Socket\\cryptoConnect'; public function __construct() { } public function enableCrypto(ClientTlsContext $tlsContext = null): \Amp\Promise { return $this->enableCrypto($tlsContext); } public function getStream() { return $this->stream; } public function connectAsync(\danog\MadelineProto\Stream\ConnectionContext $ctx, string $header = ''): \Generator { if ($ctx->isSecure()) { $connector = $this->cryptoConnector; $this->stream = yield $connector($ctx->getStringUri(), $ctx->getSocketContext(), null, $ctx->getCancellationToken()); } else { $connector = $this->connector; $this->stream = yield $connector($ctx->getStringUri(), $ctx->getSocketContext(), $ctx->getCancellationToken()); } yield $this->stream->write($header); } /** * Async chunked read. * * @return Promise */ public function read(): Promise { return $this->stream ? $this->stream->read() : new \Amp\Success(null); } /** * Async write. * * @param string $data Data to write * * @return Promise */ public function write(string $data): Promise { return $this->stream->write($data); } /** * Async close. * * @return Generator */ public function disconnect() { try { if ($this->stream) { $this->stream->close(); $this->stream = null; } } catch (\Throwable $e) { \danog\MadelineProto\Logger::log('Got exception while closing stream: '.$e->getMessage()); } catch (\Exception $e) { \danog\MadelineProto\Logger::log('Got exception while closing stream: '.$e->getMessage()); } } public function close() { $this->disconnect(); } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream; } /** * {@inheritdoc} */ public function setExtra($extra) { list($this->connector, $this->cryptoConnector) = $extra; } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Transport; use Amp\Http\Rfc7230; use Amp\Http\Status; use Amp\Promise; use Amp\Socket\ConnectException; use Amp\Websocket\Client\ConnectionException; use Amp\Websocket\Client\Handshake; use Amp\Websocket\Client\Internal\ClientSocket; use Amp\Websocket\Client\Rfc6455Connection; use Amp\Websocket\Rfc6455Client; use Amp\Websocket\Rfc7692CompressionFactory; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\RawStreamInterface; use function Amp\Websocket\generateKey; use function Amp\Websocket\validateAcceptForKey; /** * Websocket stream wrapper. * * @author Daniil Gentili */ class WsStream implements RawStreamInterface { use RawStream; private $stream; private $message; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $this->dc = $ctx->getIntDc(); $stream = yield $ctx->getStream(); $resource = $stream->getStream()->getResource(); $this->compressionFactory = new Rfc7692CompressionFactory(); $handshake = new Handshake(str_replace('tcp://', $ctx->isSecure() ? 'ws://' : 'wss://', $ctx->getStringUri())); $key = generateKey(); yield $stream->write($this->generateRequest($handshake, $key)); $buffer = ''; while (($chunk = yield $stream->read()) !== null) { $buffer .= $chunk; if ($position = \strpos($buffer, "\r\n\r\n")) { $headerBuffer = \substr($buffer, 0, $position + 4); $buffer = \substr($buffer, $position + 4); $headers = $this->handleResponse($headerBuffer, $key); $client = new Rfc6455Client( new ClientSocket($resource, $buffer), $handshake->getOptions(), true ); $this->stream = new Rfc6455Connection($client, $headers); //$this->stream = new Rfc6455Connection($this->stream, $headers, $buffer); break; } } if (!$this->stream) { throw new ConnectionException('Failed to read response from server'); } yield $this->write($header); } /** * Async close. */ public function disconnect() { try { $this->stream->close(); } catch (Exception $e) { } } public function readAsync(): \Generator { try { if (!$this->message || ($data = yield $this->message->buffer()) === null) { $this->message = yield $this->stream->receive(); if (!$this->message) { return null; } $data = yield $this->message->buffer(); $this->message = null; } } catch (Exception $e) { if ($e->getReason() !== 'Client closed the underlying TCP connection') { throw $e; } return null; } return $data; } /** * Async write. * * @param string $data Data to write * * @return Promise */ public function write(string $data): \Amp\Promise { return $this->stream->sendBinary($data); } private function generateRequest(Handshake $handshake, string $key): string { $uri = $handshake->getUri(); $headers = $handshake->getHeaders(); $headers['host'] = [$uri->getAuthority()]; $headers['connection'] = ['Upgrade']; $headers['upgrade'] = ['websocket']; $headers['sec-websocket-version'] = ['13']; $headers['sec-websocket-key'] = [$key]; if ($handshake->getOptions()->isCompressionEnabled()) { $headers['sec-websocket-extensions'] = [$this->compressionFactory->createRequestHeader()]; } if (($path = $uri->getPath()) === '') { $path = '/'; } if (($query = $uri->getQuery()) !== '') { $path .= '?'.$query; } return \sprintf("GET %s HTTP/1.1\r\n%s\r\n", $path, Rfc7230::formatHeaders($headers)); } private function handleResponse(string $headerBuffer, string $key): array { if (\substr($headerBuffer, -4) !== "\r\n\r\n") { throw new ConnectException('Invalid header provided'); } $position = \strpos($headerBuffer, "\r\n"); $startLine = \substr($headerBuffer, 0, $position); if (!\preg_match("/^HTTP\/(1\.[01]) (\d{3}) ([^\x01-\x08\x10-\x19]*)$/i", $startLine, $matches)) { throw new ConnectException('Invalid response start line: '.$startLine); } $version = $matches[1]; $status = (int) $matches[2]; $reason = $matches[3]; if ($version !== '1.1' || $status !== Status::SWITCHING_PROTOCOLS) { throw new ConnectionException( \sprintf('Did not receive switching protocols response: %d %s on DC %d', $status, $reason, $this->dc), $status ); } $headerBuffer = \substr($headerBuffer, $position + 2, -2); $headers = Rfc7230::parseHeaders($headerBuffer); $upgrade = $headers['upgrade'][0] ?? ''; if (\strtolower($upgrade) !== 'websocket') { throw new ConnectionException('Missing "Upgrade: websocket" header'); } $connection = $headers['connection'][0] ?? ''; if (!\in_array('upgrade', \array_map('trim', \array_map('strtolower', \explode(',', $connection))), true)) { throw new ConnectionException('Missing "Connection: upgrade" header'); } $secWebsocketAccept = $headers['sec-websocket-accept'][0] ?? ''; if (!validateAcceptForKey($secWebsocketAccept, $key)) { throw new ConnectionException('Invalid "Sec-WebSocket-Accept" header'); } return $headers; } final protected function createCompressionContext(array $headers): ?Websocket\CompressionContext { $extensions = $headers['sec-websocket-extensions'][0] ?? ''; $extensions = \array_map('trim', \explode(',', $extensions)); foreach ($extensions as $extension) { if ($compressionContext = $this->compressionFactory->fromServerHeader($extension)) { return $compressionContext; } } return null; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Transport; use danog\MadelineProto\Stream\ConnectionContext; /** * Websocket TLS stream wrapper. * * @author Daniil Gentili */ class WssStream extends WsStream { /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { return parent::connectAsync($ctx->getCtx()->secure(true), $header); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; /** * Stream proxy interface. * * @author Daniil Gentili */ interface ProxyStreamInterface { /** * Set extra proxy data. * * @param mixed $extra Proxy data * * @return void */ public function setExtra($extra); } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Common; use Amp\Promise; use Amp\Success; use danog\MadelineProto\Exception; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\ConnectionContext; use function Amp\Socket\connect; /** * Buffered raw stream. * * @author Daniil Gentili */ class BufferedRawStream implements \danog\MadelineProto\Stream\BufferedStreamInterface, \danog\MadelineProto\Stream\BufferInterface, \danog\MadelineProto\Stream\RawStreamInterface { use RawStream; const MAX_SIZE = 10 * 1024 * 1024; protected $stream; protected $memory_stream; private $append = ''; private $append_after = 0; /** * Asynchronously connect to a TCP/TLS server. * * @param ConnectionContext $ctx Connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $this->stream = yield $ctx->getStream($header); $this->memory_stream = fopen('php://memory', 'r+'); return true; } /** * Async chunked read. * * @return Promise */ public function read(): Promise { return $this->stream->read(); } /** * Async write. * * @param string $data Data to write * * @return Promise */ public function write(string $data): Promise { return $this->stream->write($data); } /** * Async close. * * @return Generator */ public function disconnect() { if ($this->memory_stream) { fclose($this->memory_stream); $this->memory_stream = null; } if ($this->stream) { $this->stream->disconnect(); $this->stream = null; } } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Promise */ public function getReadBuffer(&$length): Promise { $size = fstat($this->memory_stream)['size']; $offset = ftell($this->memory_stream); $length = $size - $offset; if ($length === 0 || $size > self::MAX_SIZE) { $new_memory_stream = fopen('php://memory', 'r+'); if ($length) { fwrite($new_memory_stream, fread($this->memory_stream, $length)); fseek($new_memory_stream, 0); } fclose($this->memory_stream); $this->memory_stream = $new_memory_stream; } return new \Amp\Success($this); } /** * Get write buffer asynchronously. * * @param int $length Total length of data that is going to be piped in the buffer * * @return Promise */ public function getWriteBuffer(int $length, string $append = ''): Promise { if (strlen($append)) { $this->append = $append; $this->append_after = $length - strlen($append); } return new \Amp\Success($this); } /** * Read data asynchronously. * * @param int $length Amount of data to read * * @return Promise */ public function bufferRead(int $length): Promise { $size = fstat($this->memory_stream)['size']; $offset = ftell($this->memory_stream); $buffer_length = $size - $offset; if ($buffer_length >= $length) { return new Success(fread($this->memory_stream, $length)); } return $this->call($this->bufferReadAsync($length)); } /** * Read data asynchronously. * * @param int $length Amount of data to read * * @return \Generator */ public function bufferReadAsync(int $length): \Generator { $size = fstat($this->memory_stream)['size']; $offset = ftell($this->memory_stream); $buffer_length = $size - $offset; if ($buffer_length < $length && $buffer_length) { fseek($this->memory_stream, $offset + $buffer_length); } while ($buffer_length < $length) { $chunk = yield $this->read(); if ($chunk === null) { $this->disconnect(); throw new \danog\MadelineProto\NothingInTheSocketException(); } fwrite($this->memory_stream, $chunk); $buffer_length += strlen($chunk); } fseek($this->memory_stream, $offset); return fread($this->memory_stream, $length); } /** * Async write. * * @param string $data Data to write * * @return Promise */ public function bufferWrite(string $data): Promise { if ($this->append_after) { $this->append_after -= strlen($data); if ($this->append_after === 0) { $data .= $this->append; $this->append = ''; } elseif ($this->append_after < 0) { $this->append_after = 0; $this->append = ''; throw new Exception('Tried to send too much out of frame data, cannot append'); } } return $this->write($data); } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } /** * Get class name. * * @return string */ public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Common; use Amp\Promise; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\Async\Stream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferInterface; use danog\MadelineProto\Stream\ConnectionContext; /** * Hash stream wrapper. * * @author Daniil Gentili */ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterface { use BufferedStream; private $hash_name; private $read_hash; private $write_hash; private $write_buffer; private $write_check_after = 0; private $write_check_pos = 0; private $read_buffer; private $read_check_after = 0; private $read_check_pos = 0; private $stream; private $rev = false; /** * Enable read hashing. * * @return void */ public function startReadHash() { $this->read_hash = hash_init($this->hash_name); } /** * Check the read hash after N bytes are read. * * @param int $after The number of bytes to read before checking the hash * * @return void */ public function checkReadHash(int $after) { $this->read_check_after = $after; } /** * Stop read hashing and get final hash. * * @return string */ public function getReadHash(): string { $hash = hash_final($this->read_hash, true); if ($this->rev) { $hash = strrev($hash); } $this->read_hash = null; $this->read_check_after = 0; $this->read_check_pos = 0; return $hash; } /** * Check if we are read hashing. * * @return bool */ public function hasReadHash(): bool { return $this->read_hash !== null; } /** * Enable write hashing. * * @return void */ public function startWriteHash() { $this->write_hash = hash_init($this->hash_name); } /** * Write the write hash after N bytes are read. * * @param int $after The number of bytes to read before writing the hash * * @return void */ public function checkWriteHash(int $after) { $this->write_check_after = $after; } /** * Stop write hashing and get final hash. * * @return string */ public function getWriteHash(): string { $hash = hash_final($this->write_hash, true); if ($this->rev) { $hash = strrev($hash); } $this->write_hash = null; $this->write_check_after = 0; $this->write_check_pos = 0; return $hash; } /** * Check if we are write hashing. * * @return bool */ public function hasWriteHash(): bool { return $this->write_hash !== null; } /** * Hashes read data asynchronously. * * @param int $length Read and hash $length bytes * * @throws PendingReadError Thrown if another read operation is still pending. * * @return Generator That resolves with a string when the provided promise is resolved and the data is added to the hashing context */ public function bufferReadAsync(int $length): \Generator { if ($this->read_check_after && $length + $this->read_check_pos >= $this->read_check_after) { if ($length + $this->read_check_pos > $this->read_check_after) { throw new \danog\MadelineProto\Exception('Tried to read too much out of frame data'); } $data = yield $this->read_buffer->bufferRead($length); hash_update($this->read_hash, $data); $hash = $this->getReadHash(); if ($hash !== yield $this->read_buffer->bufferRead(strlen($hash))) { throw new \danog\MadelineProto\Exception('Hash mismatch'); } return $data; } $data = yield $this->read_buffer->bufferRead($length); hash_update($this->read_hash, $data); if ($this->read_check_after) { $this->read_check_pos += $length; } return $data; } /** * Set the hash algorithm. * * @param string $hash Algorithm name * * @return void */ public function setExtra($hash) { $rev = strpos($hash, '_rev'); $this->rev = false; if ($rev !== false) { $hash = substr($hash, 0, $rev); $this->rev = true; } $this->hash_name = $hash; } /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx): \Generator { $this->write_hash = null; $this->write_check_after = 0; $this->write_check_pos = 0; $this->read_hash = null; $this->read_check_after = 0; $this->read_check_pos = 0; $this->stream = yield $ctx->getStream(); } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { if ($this->read_hash) { $this->read_buffer = yield $this->stream->getReadBuffer($length); return $this; } return yield $this->stream->getReadBuffer($length); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { if ($this->write_hash) { $this->write_buffer = yield $this->stream->getWriteBuffer($length, $append); return $this; } return yield $this->stream->getWriteBuffer($length, $append); } /** * Reads data from the stream. * * @throws PendingReadError Thrown if another read operation is still pending. * * @return Promise Resolves with a string when new data is available or `null` if the stream has closed. */ public function bufferRead(int $length): Promise { if ($this->read_hash === null) { return $this->read_buffer->bufferRead($length); } return $this->call($this->bufferReadAsync($length)); } /** * Writes data to the stream. * * @param string $data Bytes to write. * * @throws ClosedException If the stream has already been closed. * * @return Promise Succeeds once the data has been successfully written to the stream. */ public function bufferWrite(string $data): Promise { if ($this->write_hash === null) { return $this->write_buffer->bufferWrite($length); } $length = strlen($data); if ($this->write_check_after && $length + $this->write_check_pos >= $this->write_check_after) { if ($length + $this->write_check_pos > $this->write_check_after) { throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash'); } hash_update($this->write_hash, $data); return $this->write_buffer->bufferWrite($data.$this->getWriteHash()); } if ($this->write_check_after) { $this->write_check_pos += $length; } if ($this->write_hash) { hash_update($this->write_hash, $data); } return $this->write_buffer->bufferWrite($data); } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; use Amp\ByteStream\InputStream; use Amp\ByteStream\OutputStream; /** * Raw stream interface. * * @author Daniil Gentili */ interface RawStreamInterface extends InputStream, OutputStream, StreamInterface { } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; use Amp\Promise; /** * Buffered stream interface. * * @author Daniil Gentili */ interface BufferedStreamInterface extends StreamInterface { /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Promise */ public function getReadBuffer(&$length): Promise; /** * Get write buffer asynchronously. * * @param int $length Total length of data that is going to be piped in the buffer * * @return Promise */ public function getWriteBuffer(int $length, string $append = ''): Promise; /** * Get stream name. * * Is supposed to return __CLASS__ * * @return string */ public static function getName(): string; } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Async; use Amp\Promise; /** * Buffered stream helper trait. * * Wraps the asynchronous generator methods with asynchronous promise-based methods * * @author Daniil Gentili */ trait BufferedStream { use Stream; /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Promise */ public function getReadBuffer(&$length): Promise { return $this->call($this->getReadBufferAsync($length)); } /** * Get write buffer asynchronously. * * @param int $length Total length of data that is going to be piped in the buffer * @param string $append Data to append after entire buffer is written * * @return Promise */ public function getWriteBuffer(int $length, string $append = ''): Promise { return $this->call($this->getWriteBufferAsync($length, $append)); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Async; use Amp\Promise; /** * Buffer helper trait. * * Wraps the asynchronous generator methods with asynchronous promise-based methods * * @author Daniil Gentili */ trait Buffer { public function bufferRead(int $length): Promise { return $this->call($this->bufferReadAsync($length)); } public function bufferWrite(string $data): Promise { return $this->call($this->bufferWriteAsync($data)); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Async; use Amp\Promise; /** * Raw stream helper trait. * * Wraps the asynchronous generator methods with asynchronous promise-based methods * * @author Daniil Gentili */ trait RawStream { use Stream; public function read(): Promise { return $this->call($this->readAsync()); } public function write(string $data): Promise { return $this->call($this->writeAsync($data)); } public function end(string $finalData = ''): Promise { return $this->call($this->endAsync($finalData)); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Async; use Amp\Promise; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Tools; /** * Generic stream helper trait. * * Wraps the asynchronous generator methods with asynchronous promise-based methods * * @author Daniil Gentili */ trait Stream { use Tools; public function connect(ConnectionContext $ctx, string $header = ''): Promise { return $this->call($this->connectAsync($ctx, $header)); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Proxy; use Amp\Promise; use Amp\Socket\ClientTlsContext; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\RawProxyStreamInterface; /** * HTTP proxy stream wrapper. * * @author Daniil Gentili */ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { use RawStream; private $extra; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $ctx = $ctx->getCtx(); $uri = $ctx->getUri(); $secure = $ctx->isSecure(); $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false); $this->stream = yield $ctx->getStream(); $address = $uri->getHost(); $port = $uri->getPort(); try { if (strlen(inet_pton($address) === 16)) { $address = '['.$address.']'; } } catch (\danog\MadelineProto\Exception $e) { } yield $this->stream->write("CONNECT $address:$port HTTP/1.1\r\nHost: $address:$port\r\nAccept: */*\r\n".$this->getProxyAuthHeader()."Connection: keep-Alive\r\n\r\n"); $buffer = yield $this->stream->getReadBuffer($l); $headers = ''; $was_crlf = false; while (true) { $piece = yield $buffer->bufferRead(2); $headers .= $piece; if ($piece === "\n\r") { // Assume end of headers with \r\n\r\n $headers .= yield $buffer->bufferRead(1); break; } if ($was_crlf && $piece === "\r\n") { break; } $was_crlf = $piece === "\r\n"; } $headers = explode("\r\n", $headers); list($protocol, $code, $description) = explode(' ', $headers[0], 3); list($protocol, $protocol_version) = explode('/', $protocol); if ($protocol !== 'HTTP') { throw new \danog\MadelineProto\Exception('Wrong protocol'); } $code = (int) $code; unset($headers[0]); if (array_pop($headers).array_pop($headers) !== '') { throw new \danog\MadelineProto\Exception('Wrong last header'); } foreach ($headers as $key => $current_header) { unset($headers[$key]); $current_header = explode(':', $current_header, 2); $headers[strtolower($current_header[0])] = trim($current_header[1]); } $close = $protocol === 'HTTP/1.0'; if (isset($headers['connection'])) { $close = strtolower($headers['connection']) === 'close'; } if ($code !== 200) { $read = ''; if (isset($headers['content-length'])) { $read = yield $buffer->bufferRead((int) $headers['content-length']); } if ($close) { $this->disconnect(); yield $this->connect($ctx); } \danog\MadelineProto\Logger::log(trim($read)); throw new \danog\MadelineProto\Exception($description, $code); } if ($close) { yield $this->stream->disconnect(); yield $this->stream->connect($ctx); } if (isset($headers['content-length'])) { $length = (int) $headers['content-length']; $read = yield $buffer->bufferRead($length); } if ($secure && method_exists($this->getSocket(), 'enableCrypto')) { yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost())); } \danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http'); if (strlen($header)) { yield (yield $this->stream->getWriteBuffer(strlen($header)))->bufferWrite($header); } } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBuffer(int $length, string $append = ''): Promise { return $this->stream->getWriteBuffer($length, $append); } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBuffer(&$length): Promise { return $this->stream->getReadBuffer($length); } public function read(): Promise { return $this->stream->read(); } public function write(string $data): Promise { return $this->stream->write($data); } private function getProxyAuthHeader() { if (!isset($this->extra['username']) || !isset($this->extra['password'])) { return ''; } return 'Proxy-Authorization: Basic '.base64_encode($this->extra['username'].':'.$this->extra['password'])."\r\n"; } /** * Sets proxy data. * * @param array $extra Proxy data * * @return void */ public function setExtra($extra) { $this->extra = $extra; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\Proxy; use Amp\Promise; use Amp\Socket\ClientTlsContext; use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\RawProxyStreamInterface; /** * Socks5 stream wrapper. * * @author Daniil Gentili */ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface { use RawStream; private $extra; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $ctx = $ctx->getCtx(); $uri = $ctx->getUri(); $secure = $ctx->isSecure(); $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false); $methods = chr(0); if (isset($this->extra['username']) && isset($this->extra['password'])) { $methods .= chr(2); } $this->stream = yield $ctx->getStream(chr(5).chr(strlen($methods)).$methods); $l = 2; $buffer = yield $this->stream->getReadBuffer($l); $version = ord(yield $buffer->bufferRead(1)); $method = ord(yield $buffer->bufferRead(1)); if ($version !== 5) { throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version"); } if ($method === 2) { $auth = chr(1).chr(strlen($this->extra['username'])).$this->extra['username'].chr(strlen($this->extra['password'])).$this->extra['password']; yield $this->stream->write($auth); $buffer = yield $this->stream->getReadBuffer($l); $version = ord(yield $buffer->bufferRead(1)); $result = ord(yield $buffer->bufferRead(1)); if ($version !== 1) { throw new \danog\MadelineProto\Exception("Wrong authorized SOCKS version: $version"); } if ($result !== 0) { throw new \danog\MadelineProto\Exception("Wrong authorization status: $version"); } } elseif ($method !== 0) { throw new \danog\MadelineProto\Exception("Wrong method: $method"); } $payload = pack('C3', 0x05, 0x01, 0x00); try { $ip = inet_pton($uri->getHost()); $payload .= $ip ? pack('C1', strlen($ip) === 4 ? 0x01 : 0x04).$ip : pack('C2', 0x03, strlen($uri->getHost())).$uri->getHost(); } catch (\danog\MadelineProto\Exception $e) { $payload .= pack('C2', 0x03, strlen($uri->getHost())).$uri->getHost(); } $payload .= pack('n', $uri->getPort()); yield $this->stream->write($payload); $l = 4; $buffer = yield $this->stream->getReadBuffer($l); $version = ord(yield $buffer->bufferRead(1)); if ($version !== 5) { throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: $version"); } $rep = ord(yield $buffer->bufferRead(1)); if ($rep !== 0) { throw new \danog\MadelineProto\Exception("Wrong SOCKS5 rep: $rep"); } $rsv = ord(yield $buffer->bufferRead(1)); if ($rsv !== 0) { throw new \danog\MadelineProto\Exception("Wrong socks5 final RSV: $rsv"); } switch (ord(yield $buffer->bufferRead(1))) { case 1: $buffer = yield $this->stream->getReadBuffer($l); $ip = inet_ntop(yield $buffer->bufferRead(4)); break; case 4: $l = 16; $buffer = yield $this->stream->getReadBuffer($l); $ip = inet_ntop(yield $buffer->bufferRead(16)); break; case 3: $l = 1; $buffer = yield $this->stream->getReadBuffer($l); $length = ord(yield $buffer->bufferRead(1)); $buffer = yield $this->stream->getReadBuffer($length); $ip = yield $buffer->bufferRead($length); break; } $l = 2; $buffer = yield $this->stream->getReadBuffer($l); $port = unpack('n', yield $buffer->bufferRead(2))[1]; \danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']); if ($secure && method_exists($this->getSocket(), 'enableCrypto')) { yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost())); } if (strlen($header)) { yield (yield $this->stream->getWriteBuffer(strlen($header)))->bufferWrite($header); } } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBuffer(int $length, string $append = ''): Promise { return $this->stream->getWriteBuffer($length, $append); } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBuffer(&$length): Promise { return $this->stream->getReadBuffer($length); } public function read(): Promise { return $this->stream->read(); } public function write(string $data): Promise { return $this->stream->write($data); } /** * Sets proxy data. * * @param array $extra Proxy data * * @return void */ public function setExtra($extra) { $this->extra = $extra; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use Amp\Promise; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; /** * TCP Intermediate stream wrapper. * * Manages obfuscated2 encryption/decryption * * @author Daniil Gentili */ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterface { use BufferedStream; private $stream; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $this->stream = yield $ctx->getStream(str_repeat(chr(238), 4).$header); } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { $buffer = yield $this->stream->getWriteBuffer($length + 4, $append); yield $buffer->bufferWrite(pack('V', $length)); return $buffer; } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { $buffer = yield $this->stream->getReadBuffer($l); $length = unpack('V', yield $buffer->bufferRead(4))[1]; return $buffer; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use Amp\Promise; use danog\MadelineProto\Exception; use danog\MadelineProto\Stream\Async\Buffer; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; /** * Obfuscated2 stream wrapper. * * Manages obfuscated2 encryption/decryption * * @author Daniil Gentili */ class ObfuscatedStream implements BufferedProxyStreamInterface { use Buffer; use BufferedStream; private $encrypt; private $decrypt; private $stream; private $write_buffer; private $read_buffer; private $extra; private $append = ''; private $append_after = 0; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { if (isset($this->extra['address'])) { $ctx = $ctx->getCtx(); $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port']); } do { $random = $this->random(64); } while (in_array(substr($random, 0, 4), ['PVrG', 'GET ', 'POST', 'HEAD', str_repeat(chr(238), 4), str_repeat(chr(221), 4)]) || $random[0] === chr(0xef) || substr($random, 4, 4) === "\0\0\0\0"); if (strlen($header) === 1) { $header = str_repeat($header, 4); } $random = substr_replace($random, $header.substr($random, 56 + strlen($header)), 56); $random = substr_replace($random, pack('s', $ctx->getIntDc()).substr($random, 60 + 2), 60); $reversed = strrev($random); $key = substr($random, 8, 32); $keyRev = substr($reversed, 8, 32); if (isset($this->extra['secret'])) { $key = hash('sha256', $key.$this->extra['secret'], true); $keyRev = hash('sha256', $keyRev.$this->extra['secret'], true); } $this->encrypt = new \phpseclib\Crypt\AES('ctr'); $this->encrypt->enableContinuousBuffer(); $this->encrypt->setKey($key); $this->encrypt->setIV(substr($random, 40, 16)); $this->decrypt = new \phpseclib\Crypt\AES('ctr'); $this->decrypt->enableContinuousBuffer(); $this->decrypt->setKey($keyRev); $this->decrypt->setIV(substr($reversed, 40, 16)); $random = substr_replace($random, substr(@$this->encrypt->encrypt($random), 56, 8), 56, 8); $this->stream = yield $ctx->getStream($random); } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { $this->write_buffer = yield $this->stream->getWriteBuffer($length); if (strlen($append)) { $this->append = $append; $this->append_after = $length - strlen($append); } return $this; } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { $this->read_buffer = yield $this->stream->getReadBuffer($l); return $this; } /** * Decrypts read data asynchronously. * * @param Promise $promise Promise that resolves with a string when new data is available or `null` if the stream has closed. * * @throws PendingReadError Thrown if another read operation is still pending. * * @return Generator That resolves with a string when the provided promise is resolved and the data is decrypted */ public function bufferReadAsync(int $length): \Generator { return @$this->decrypt->encrypt(yield $this->read_buffer->bufferRead($length)); } /** * Writes data to the stream. * * @param string $data Bytes to write. * * @throws ClosedException If the stream has already been closed. * * @return Promise Succeeds once the data has been successfully written to the stream. */ public function bufferWrite(string $data): Promise { if ($this->append_after) { $this->append_after -= strlen($data); if ($this->append_after === 0) { $data .= $this->append; $this->append = ''; } elseif ($this->append_after < 0) { $this->append_after = 0; $this->append = ''; throw new Exception('Tried to send too much out of frame data, cannot append'); } } return $this->write_buffer->bufferWrite(@$this->encrypt->encrypt($data)); } /** * Does nothing. * * @param void $data Nothing * * @return void */ public function setExtra($extra) { if (isset($extra['secret']) && strlen($extra['secret']) > 17) { $extra['secret'] = hex2bin($extra['secret']); } if (isset($extra['secret']) && strlen($extra['secret']) == 17) { $extra['secret'] = substr($extra['secret'], 0, 16); } $this->extra = $extra; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use Amp\Promise; use Amp\Success; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; /** * HTTP stream wrapper. * * @author Daniil Gentili */ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface { use BufferedStream; private $stream; private $code; private $ctx; private $header = ''; /** * URI of the HTTP API. * * @var \Amp\Uri\Uri */ private $uri; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $this->ctx = $ctx->getCtx(); $this->stream = yield $ctx->getStream($header); $this->uri = $ctx->getUri(); } /** * Set proxy data. * * @param array $extra Proxy parameters * * @return void */ public function setExtra($extra) { if (isset($extra['user']) && isset($extra['password'])) { $this->header = \base64_encode($extra['user'].':'.$extra['password'])."\r\n"; } } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { $headers = 'POST '.$this->uri->getPath()." HTTP/1.1\r\nHost: ".$this->uri->getHost().':'.$this->uri->getPort()."\r\n"."Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".$length.$this->header."\r\n\r\n"; $buffer = yield $this->stream->getWriteBuffer(strlen($headers) + $length, $append); yield $buffer->bufferWrite($headers); return $buffer; } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { $buffer = yield $this->stream->getReadBuffer($l); $headers = ''; $was_crlf = false; while (true) { $piece = yield $buffer->bufferRead(2); $headers .= $piece; if ($piece === "\n\r") { // Assume end of headers with \r\n\r\n $headers .= yield $buffer->bufferRead(1); break; } if ($was_crlf && $piece === "\r\n") { break; } $was_crlf = $piece === "\r\n"; } $headers = explode("\r\n", $headers); list($protocol, $code, $description) = explode(' ', $headers[0], 3); list($protocol, $protocol_version) = explode('/', $protocol); if ($protocol !== 'HTTP') { throw new \danog\MadelineProto\Exception('Wrong protocol'); } $code = (int) $code; unset($headers[0]); if (array_pop($headers).array_pop($headers) !== '') { throw new \danog\MadelineProto\Exception('Wrong last header'); } foreach ($headers as $key => $current_header) { unset($headers[$key]); $current_header = explode(':', $current_header, 2); $headers[strtolower($current_header[0])] = trim($current_header[1]); } $close = $protocol === 'HTTP/1.0'; if (isset($headers['connection'])) { $close = strtolower($headers['connection']) === 'close'; } if ($code !== 200) { $read = ''; if (isset($headers['content-length'])) { $read = yield $buffer->bufferRead((int) $headers['content-length']); } if ($close) { $this->disconnect(); yield $this->connect($this->ctx); } \danog\MadelineProto\Logger::log($read); $this->code = $this->pack_signed_int(-$code); $length = 4; return $this; } if ($close) { $this->stream->disconnect(); yield $this->stream->connect($this->ctx); } if (isset($headers['content-length'])) { $length = (int) $headers['content-length']; } return $buffer; } public function bufferRead(int $length): Promise { return new Success($this->code); } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; /** * HTTPS stream wrapper. * * @author Daniil Gentili */ class HttpsStream extends HttpStream implements MTProtoBufferInterface { /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { return parent::connectAsync($ctx->getCtx()->secure(true), $header); } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use Amp\Promise; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; /** * Abridged stream wrapper. * * @author Daniil Gentili */ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface { use BufferedStream; private $stream; private $ctx; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $this->ctx = $ctx->getCtx(); $this->stream = yield $ctx->getStream(chr(239).$header); } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return \Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { $length >>= 2; if ($length < 127) { $message = chr($length); } else { $message = chr(127).substr(pack('V', $length), 0, 3); } $buffer = yield $this->stream->getWriteBuffer(strlen($message) + $length, $append); yield $buffer->bufferWrite($message); return $buffer; } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { $buffer = yield $this->stream->getReadBuffer($l); $length = ord(yield $buffer->bufferRead(1)); if ($length >= 127) { $length = unpack('V', (yield $buffer->bufferRead(3))."\0")[1]; } $length <<= 2; return $buffer; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use Amp\Promise; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\Common\HashedBufferedStream; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; /** * TCP full stream wrapper. * * Manages obfuscated2 encryption/decryption * * @author Daniil Gentili */ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface { use BufferedStream; private $stream; private $in_seq_no = -1; private $out_seq_no = -1; /** * Stream to use as data source. * * @param ConnectionContext $ctx * * @return Promise */ public function connect(ConnectionContext $ctx, string $header = ''): Promise { $this->in_seq_no = -1; $this->out_seq_no = -1; $this->stream = new HashedBufferedStream(); $this->stream->setExtra('crc32b_rev'); return $this->stream->connect($ctx, $header); } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { $this->stream->startWriteHash(); $this->stream->checkWriteHash($length + 8); $buffer = yield $this->stream->getWriteBuffer($length + 12, $append); $this->out_seq_no++; $buffer->bufferWrite(pack('VV', $length + 12, $this->out_seq_no)); return $buffer; } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { $this->stream->startReadHash(); $buffer = yield $this->stream->getReadBuffer($l); $read_length = unpack('V', yield $buffer->bufferRead(4))[1]; $length = $read_length - 12; $this->stream->checkReadHash($read_length - 8); $this->in_seq_no++; $in_seq_no = unpack('V', yield $buffer->bufferRead(4))[1]; if ($in_seq_no != $this->in_seq_no) { throw new Exception('Incoming seq_no mismatch'); } return $buffer; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTransport; use Amp\Promise; use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; /** * TCP Intermediate stream wrapper. * * Manages obfuscated2 encryption/decryption * * @author Daniil Gentili */ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBufferInterface { use BufferedStream; private $stream; /** * Connect to stream. * * @param ConnectionContext $ctx The connection context * * @return \Generator */ public function connectAsync(ConnectionContext $ctx, string $header = ''): \Generator { $this->stream = yield $ctx->getStream(str_repeat(chr(221), 4).$header); } /** * Async close. * * @return Promise */ public function disconnect() { return $this->stream->disconnect(); } /** * Get write buffer asynchronously. * * @param int $length Length of data that is going to be written to the write buffer * * @return Generator */ public function getWriteBufferAsync(int $length, string $append = ''): \Generator { $padding_length = $this->random_int($modulus = 16); $buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append.$this->random($padding_length)); yield $buffer->bufferWrite(pack('V', $padding_length + $length)); return $buffer; } /** * Get read buffer asynchronously. * * @param int $length Length of payload, as detected by this layer * * @return Generator */ public function getReadBufferAsync(&$length): \Generator { $buffer = yield $this->stream->getReadBuffer($l); $length = unpack('V', yield $buffer->bufferRead(4))[1]; return $buffer; } /** * {@inheritdoc} * * @return \Amp\Socket\Socket */ public function getSocket(): \Amp\Socket\Socket { return $this->stream->getSocket(); } public static function getName(): string { return __CLASS__; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; /** * Raw stream proxy interface. * * @author Daniil Gentili */ interface RawProxyStreamInterface extends RawStreamInterface, ProxyStreamInterface { } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; /** * MTProto buffer interface, for reading transport MTProto header info. * * @author Daniil Gentili */ interface MTProtoBufferInterface { } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTools; /** * Manages message ids. */ trait MsgIdHandler { public function check_message_id($new_message_id, $aargs) { if (!is_object($new_message_id)) { $new_message_id = new \phpseclib\Math\BigInteger(strrev($new_message_id), 256); } $min_message_id = (new \phpseclib\Math\BigInteger(time() + $this->time_delta - 300))->bitwise_leftShift(32); if ($min_message_id->compare($new_message_id) > 0) { $this->API->logger->logger('Given message id ('.$new_message_id.') is too old compared to the min value ('.$min_message_id.').', \danog\MadelineProto\Logger::WARNING); } $max_message_id = (new \phpseclib\Math\BigInteger(time() + $this->time_delta + 30))->bitwise_leftShift(32); if ($max_message_id->compare($new_message_id) < 0) { throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is too new compared to the max value ('.$max_message_id.'). Consider syncing your date.'); } if ($aargs['outgoing']) { if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$zero)) { throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4. Consider syncing your date.'); } if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->get_max_id($incoming = false)) <= 0) { throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1); } if (count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) { reset($this->outgoing_messages); $key = key($this->outgoing_messages); if (!isset($this->outgoing_messages[$key]['promise'])) { unset($this->outgoing_messages[$key]); } } $this->max_outgoing_id = $new_message_id; $this->outgoing_messages[strrev($new_message_id->toBytes())] = []; } else { if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$one) && !$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$three)) { throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3'); } $key = $this->get_max_id($incoming = true); if ($aargs['container']) { if ($new_message_id->compare($key = $this->get_max_id($incoming = true)) >= 0) { $this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is bigger than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING); } } else { if ($new_message_id->compare($key = $this->get_max_id($incoming = true)) <= 0) { $this->API->logger->logger('WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING); } } if (count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) { reset($this->incoming_messages); $key = key($this->incoming_messages); if (!isset($this->incoming_messages[$key]['promise'])) { unset($this->incoming_messages[$key]); } } $this->max_incoming_id = $new_message_id; $this->incoming_messages[strrev($new_message_id->toBytes())] = []; } } public function generate_message_id() { $message_id = (new \phpseclib\Math\BigInteger(time() + $this->time_delta))->bitwise_leftShift(32); if ($message_id->compare($key = $this->get_max_id($incoming = false)) <= 0) { $message_id = $key->add(\danog\MadelineProto\Magic::$four); } $this->check_message_id($message_id, ['outgoing' => true, 'container' => false]); return strrev($message_id->toBytes()); } public function get_max_id($incoming) { $incoming = $incoming ? 'incoming' : 'outgoing'; if (isset($this->{'max_'.$incoming.'_id'}) && is_object($this->{'max_'.$incoming.'_id'})) { return $this->{'max_'.$incoming.'_id'}; } return \danog\MadelineProto\Magic::$zero; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTools; /** * Manages sequence number. */ trait SeqNoHandler { use \danog\MadelineProto\MTProtoTools\SeqNoHandler; public function generate_out_seq_no($content_related) { $in = $content_related ? 1 : 0; $value = $this->session_out_seq_no; $this->session_out_seq_no += $in; //$this->API->logger->logger("OUT: $value + $in = ".$this->session_out_seq_no); return $value * 2 + $in; } public function check_in_seq_no($current_msg_id) { $type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-'; if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generate_in_seq_no($this->content_related($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) { $this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } elseif (isset($seq_no)) { $this->API->logger->logger('Seqno OK (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } } public function generate_in_seq_no($content_related) { $in = $content_related ? 1 : 0; $value = $this->session_in_seq_no; $this->session_in_seq_no += $in; //$this->API->logger->logger("IN: $value + $in = ".$this->session_in_seq_no); return $value * 2 + $in; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream\MTProtoTools; /** * Manages message ids. */ trait SaltHandler { public function add_salts($salts) { foreach ($salts as $salt) { $this->add_salt($salt['valid_since'], $salt['valid_until'], $salt['salt']); } } public function add_salt($valid_since, $valid_until, $salt) { if (!isset($this->temp_auth_key['salts'][$salt])) { $this->temp_auth_key['salts'][$salt] = ['valid_since' => $valid_since, 'valid_until' => $valid_until]; } } public function handle_future_salts($salt) { yield $this->method_call_async_read('messages.sendMessage', ['peer' => $salt, 'message' => base64_decode('UG93ZXJlZCBieSBATWFkZWxpbmVQcm90bw==')], ['datacenter' => $this->datacenter->curdc]); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; use Amp\Promise; /** * Buffer interface. * * @author Daniil Gentili */ interface BufferInterface { /** * Read data asynchronously. * * @param int $length How much data to read * * @return Promise */ public function bufferRead(int $length): Promise; /** * Write data asynchronously. * * @param string $data Data to write * * @return Promise */ public function bufferWrite(string $data): Promise; } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Stream; use Amp\CancellationToken; use Amp\Socket\ClientConnectContext; use Amp\Uri\Uri; /** * Connection context class. * * Is responsible for maintaining state about a certain connection to a DC. * That includes the Stream chain that is required to use the connection, the connection URI, and other connection-related data. * * @author Daniil Gentili */ class ConnectionContext { /** * Whether to use a secure socket. * * @var bool */ private $secure = false; /** * Whether to use test servers. * * @var bool */ private $test = false; /** * The connection URI. * * @var \Amp\Uri\Uri */ private $uri; /** * Socket context. * * @var \Amp\Socket\ClientConnectionContext */ private $socketContext; /** * Cancellation token. * * @var \Amp\CancellationToken */ private $cancellationToken; /** * The telegram DC ID. * * @var int */ private $dc = 0; /** * Whether to use IPv6. * * @var bool */ private $ipv6 = false; /** * An array of arrays containing an array with the stream name and the extra parameter to pass to it. * * @var array> */ private $nextStreams = []; /** * The current stream key. * * @var int */ private $key = 0; /** * Set the socket context. * * @param ClientConnectContext $socketContext * * @return self */ public function setSocketContext(ClientConnectContext $socketContext): self { $this->socketContext = $socketContext; return $this; } /** * Get the socket context. * * @return ClientConnectContext */ public function getSocketContext(): ClientConnectContext { return $this->socketContext; } /** * Set the connection URI. * * @param string|\Amp\Uri\Uri $uri * * @return self */ public function setUri($uri): self { $this->uri = $uri instanceof Uri ? $uri : new Uri($uri); return $this; } /** * Get the URI as a string. * * @return string */ public function getStringUri(): string { return (string) $this->uri; } /** * Get the URI. * * @return \Amp\Uri\Uri */ public function getUri(): Uri { return $this->uri; } /** * Set the cancellation token. * * @param CancellationToken $cancellationToken * * @return self */ public function setCancellationToken($cancellationToken): self { $this->cancellationToken = $cancellationToken; return $this; } /** * Get the cancellation token. * * @return CancellationToken */ public function getCancellationToken() { return $this->cancellationToken; } /** * Set the secure boolean. * * @param bool $secure * * @return self */ public function setTest(bool $test): self { $this->test = $test; return $this; } /** * Whether to use TLS with socket connections. * * @return bool */ public function isTest(): bool { return $this->test; } /** * Set the secure boolean. * * @param bool $secure * * @return self */ public function secure(bool $secure): self { $this->secure = $secure; return $this; } /** * Whether to use TLS with socket connections. * * @return bool */ public function isSecure(): bool { return $this->secure; } /** * Set the DC ID. * * @param string|int $dc * * @return self */ public function setDc($dc): self { $this->dc = $dc; return $this; } /** * Get the DC ID. * * @return string|int */ public function getDc() { return $this->dc; } /** * Get the int DC ID. * * @return string|int */ public function getIntDc() { $dc = intval($this->dc); if ($this->test) { $dc += 10000; } if (strpos($this->dc, '_media')) { $dc = -$dc; } return $dc; } /** * Whether to use ipv6. * * @param bool $ipv6 * * @return self */ public function setIpv6(bool $ipv6): self { $this->ipv6 = $ipv6; return $this; } /** * Whether to use ipv6. * * @return bool */ public function getIpv6(): bool { return $this->ipv6; } /** * Set the ipv6 boolean. * * @return self */ public function getCtx(): self { return clone $this; } /** * Add a stream to the stream chain. * * @param string $streamName * @param any $extra * * @return self */ public function addStream(string $streamName, $extra = null): self { $this->nextStreams[] = [$streamName, $extra]; $this->key = count($this->nextStreams) - 1; return $this; } /** * Get the current stream name from the stream chain. * * @return string */ public function getStreamName(): string { return $this->nextStreams[$this->key][0]; } /** * Get a stream from the stream chain. * * @internal Generator func * * @return \Generator */ public function getStream(string $buffer = ''): \Generator { list($clazz, $extra) = $this->nextStreams[$this->key--]; $obj = new $clazz(); if ($obj instanceof ProxyStreamInterface) { $obj->setExtra($extra); } yield $obj->connect($this, $buffer); return $obj; } /** * Get a description "name" of the context. * * @return string */ public function getName(): string { $string = $this->getStringUri(); if ($this->isSecure()) { $string .= ' (TLS)'; } $string .= $this->isTest() ? ' test' : ' main'; $string .= ' DC '; $string .= $this->getDc(); $string .= ', via '; $string .= $this->getIpv6() ? 'ipv6' : 'ipv4'; $string .= ' using '; foreach (array_reverse($this->nextStreams) as $k => $stream) { if ($k) { $string .= ' => '; } $string .= preg_replace('/.*\\\\/', '', $stream[0]); if ($stream[1]) { $string .= ' ('.json_encode($stream[1]).')'; } } return $string; } /** * Returns a representation of the context. * * @return string */ public function __toString() { return $this->getName(); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\VoIP; /** * Manages the creation of the authorization key. * * https://core.telegram.org/mtproto/auth_key * https://core.telegram.org/mtproto/samples-auth_key */ trait AuthKeyHandler { private $calls = []; public function request_call($user) { return $this->wait($this->request_call_async($user)); } public function accept_call($user) { return $this->wait($this->accept_call_async($user)); } public function discard_call($call, $reason, $rating = [], $need_debug = true) { return $this->wait($this->discard_call_async($call, $reason, $rating, $need_debug)); } public function request_call_async($user) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(['extension', 'libtgvoip']); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); $user = yield $this->get_info_async($user); if (!isset($user['InputUser']) || $user['InputUser']['_'] === 'inputUserSelf') { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']); } $user = $user['InputUser']; $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['calling_user'], $user['user_id']), \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_a'], \danog\MadelineProto\Logger::VERBOSE); $a = \phpseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two)); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_g_a'], \danog\MadelineProto\Logger::VERBOSE); $g_a = $dh_config['g']->powMod($a, $dh_config['p']); $this->check_G($g_a, $dh_config['p']); $controller = new \danog\MadelineProto\VoIP(true, $user['user_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED); $controller->storage = ['a' => $a, 'g_a' => str_pad($g_a->toBytes(), 256, chr(0), \STR_PAD_LEFT)]; $res = yield $this->method_call_async_read('phone.requestCall', ['user_id' => $user, 'g_a_hash' => hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_p2p' => true, 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]); $controller->setCall($res['phone_call']); $this->calls[$res['phone_call']['id']] = $controller; yield $this->updaters[false]->resume(); return $controller; } public function accept_call_async($call) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); if ($this->call_status($call['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_1'], $call['id'])); return false; } $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['accepting_call'], $this->calls[$call['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_b'], \danog\MadelineProto\Logger::VERBOSE); $b = \phpseclib\Math\BigInteger::randomRange(\danog\MadelineProto\Magic::$two, $dh_config['p']->subtract(\danog\MadelineProto\Magic::$two)); $g_b = $dh_config['g']->powMod($b, $dh_config['p']); $this->check_G($g_b, $dh_config['p']); try { $res = yield $this->method_call_async_read('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'CALL_ALREADY_ACCEPTED') { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id'])); return true; } if ($e->rpc === 'CALL_ALREADY_DECLINED') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['call_already_declined']); yield $this->discard_call_async($call['id'], 'phoneCallDiscardReasonHangup'); return false; } throw $e; } $this->calls[$res['phone_call']['id']]->storage['b'] = $b; yield $this->updaters[false]->resume(); return true; } public function confirm_call_async($params) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(['extension', 'libtgvoip']); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_2'], $params['id'])); return false; } $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_confirming'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); $params['g_b'] = new \phpseclib\Math\BigInteger($params['g_b'], 256); $this->check_G($params['g_b'], $dh_config['p']); $key = str_pad($params['g_b']->powMod($this->calls[$params['id']]->storage['a'], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT); $res = (yield $this->method_call_async_read('phone.confirmCall', ['key_fingerprint' => substr(sha1($key, true), -8), 'peer' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'g_a' => $this->calls[$params['id']]->storage['g_a'], 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]))['phone_call']; $visualization = []; $length = new \phpseclib\Math\BigInteger(count(\danog\MadelineProto\Magic::$emojis)); foreach (str_split(hash('sha256', $key.str_pad($this->calls[$params['id']]->storage['g_a'], 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) { $number[0] = chr(ord($number[0]) & 0x7f); $visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()]; } $this->calls[$params['id']]->setVisualization($visualization); $this->calls[$params['id']]->configuration['endpoints'] = array_merge([$res['connection']], $res['alternative_connections'], $this->calls[$params['id']]->configuration['endpoints']); $this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration); $this->calls[$params['id']]->parseConfig(); $res = $this->calls[$params['id']]->startTheMagic(); return $res; } public function complete_call_async($params) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(['extension', 'libtgvoip']); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); if ($this->call_status($params['id']) !== \danog\MadelineProto\VoIP::CALL_STATE_ACCEPTED || !isset($this->calls[$params['id']]->storage['b'])) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_error_3'], $params['id'])); return false; } $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_completing'], $this->calls[$params['id']]->getOtherID()), \danog\MadelineProto\Logger::VERBOSE); $dh_config = yield $this->get_dh_config_async(); if (hash('sha256', $params['g_a_or_b'], true) != $this->calls[$params['id']]->storage['g_a_hash']) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['invalid_g_a']); } $params['g_a_or_b'] = new \phpseclib\Math\BigInteger($params['g_a_or_b'], 256); $this->check_G($params['g_a_or_b'], $dh_config['p']); $key = str_pad($params['g_a_or_b']->powMod($this->calls[$params['id']]->storage['b'], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT); if (substr(sha1($key, true), -8) != $params['key_fingerprint']) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['fingerprint_invalid']); } $visualization = []; $length = new \phpseclib\Math\BigInteger(count(\danog\MadelineProto\Magic::$emojis)); foreach (str_split(hash('sha256', $key.str_pad($params['g_a_or_b']->toBytes(), 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) { $number[0] = chr(ord($number[0]) & 0x7f); $visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()]; } $this->calls[$params['id']]->setVisualization($visualization); $this->calls[$params['id']]->configuration['endpoints'] = array_merge([$params['connection']], $params['alternative_connections'], $this->calls[$params['id']]->configuration['endpoints']); $this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration); $this->calls[$params['id']]->parseConfig(); return $this->calls[$params['id']]->startTheMagic(); } public function call_status($id) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(['extension', 'libtgvoip']); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); if (isset($this->calls[$id])) { return $this->calls[$id]->getCallState(); } return \danog\MadelineProto\VoIP::CALL_STATE_NONE; } public function get_call($call) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(['extension', 'libtgvoip']); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); return $this->calls[$call]; } public function discard_call_async($call, $reason, $rating = [], $need_debug = true) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { throw new \danog\MadelineProto\Exception(['extension', 'libtgvoip']); } if (!isset($this->calls[$call['id']])) { return; } $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_discarding'], $call['id']), \danog\MadelineProto\Logger::VERBOSE); try { $res = yield $this->method_call_async_read('phone.discardCall', ['peer' => $call, 'duration' => time() - $this->calls[$call['id']]->whenCreated(), 'connection_id' => $this->calls[$call['id']]->getPreferredRelayID(), 'reason' => $reason], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { if (!in_array($e->rpc, ['CALL_ALREADY_DECLINED', 'CALL_ALREADY_ACCEPTED'])) { throw $e; } } if (!empty($rating)) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_set_rating'], $call['id']), \danog\MadelineProto\Logger::VERBOSE); yield $this->method_call_async_read('phone.setCallRating', ['peer' => $call, 'rating' => $rating['rating'], 'comment' => $rating['comment']], ['datacenter' => $this->datacenter->curdc]); } if ($need_debug && isset($this->calls[$call['id']])) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_debug_saving'], $call['id']), \danog\MadelineProto\Logger::VERBOSE); yield $this->method_call_async_read('phone.saveCallDebug', ['peer' => $call, 'debug' => $this->calls[$call['id']]->getDebugLog()], ['datacenter' => $this->datacenter->curdc]); } $update = ['_' => 'updatePhoneCall', 'phone_call' => $this->calls[$call['id']]]; if (isset($this->settings['pwr']['strict']) && $this->settings['pwr']['strict']) { $this->pwr_update_handler($update); } else { in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['updates']['callback']($update); } unset($this->calls[$call['id']]); array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); } } // Core types (no need to gen) //vector#1cb5c415 {t:Type} # [ t ] = Vector t; /////////////////////////////// /////////////////// Layer cons /////////////////////////////// //invokeAfterMsg#cb9f372d msg_id:long query:!X = X; //invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; //invokeWithLayer1#53835315 query:!X = X; //invokeWithLayer2#289dd1f6 query:!X = X; //invokeWithLayer3#b7475268 query:!X = X; //invokeWithLayer4#dea0d430 query:!X = X; //invokeWithLayer5#417a57ae query:!X = X; //invokeWithLayer6#3a64d54d query:!X = X; //invokeWithLayer7#a5be56d3 query:!X = X; //invokeWithLayer8#e9abd9fd query:!X = X; //invokeWithLayer9#76715a63 query:!X = X; //invokeWithLayer10#39620c41 query:!X = X; //invokeWithLayer11#a6b88fdf query:!X = X; //invokeWithLayer12#dda60d3c query:!X = X; //invokeWithLayer13#427c8ea2 query:!X = X; //invokeWithLayer14#2b9b08fa query:!X = X; //invokeWithLayer15#b4418b64 query:!X = X; //invokeWithLayer16#cf5f0987 query:!X = X; //invokeWithLayer17#50858a19 query:!X = X; //invokeWithLayer18#1c900537 query:!X = X; //invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer /////////////////////////////// /// Authorization key creation /////////////////////////////// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ////////////// System messages /////////////////////////////// ---types--- msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; //message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually //msg_container#73f1f8dc messages:vector = MessageContainer; // parsed manually //msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container //gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ipPort ipv4:int port:int = IpPort; help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple; ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#e39621fd flags:# file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#cb44b1c flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#17f45fcf flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#90dddc11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#b5223b0f flags:# photo:flags.0?Photo caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterMyMentionsUnread#46caf4a8 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; config#8df376a4 flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int phonecalls_enabled:flags.1?true call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#fadff4ac flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#039e9ea0 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector; // LAYER 71 decryptedDataBlock#dbf948c1 random_id:long random_bytes:string flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string = DecryptedDataBlock; simpleDataBlock#cc0d0e76 random_id:long random_bytes:string raw_data:string = DecryptedDataBlock; . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class NothingInTheSocketException extends \Exception { } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ /* * Logger class */ namespace danog\MadelineProto; use Amp\ByteStream\ResourceOutputStream; use Amp\Failure; use function Amp\ByteStream\getStderr; use function Amp\ByteStream\getStdout; class Logger { use Tools; const foreground = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97]; const background = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107]; const set = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6]; const reset = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28]; public $mode = 0; public $optional = null; public $prefix = ''; public $level = 3; public $colors = []; public $newline = "\n"; public static $default; public static $printed = false; const ULTRA_VERBOSE = 5; const VERBOSE = 4; const NOTICE = 3; const WARNING = 2; const ERROR = 1; const FATAL_ERROR = 0; const NO_LOGGER = 0; const DEFAULT_LOGGER = 1; const FILE_LOGGER = 2; const ECHO_LOGGER = 3; const CALLABLE_LOGGER = 4; /* * Constructor function * Accepts various logger modes: * 0 - No logger * 1 - Log to the default logger destination * 2 - Log to file defined in second parameter * 3 - Echo logs * 4 - Call callable provided in logger_param. logger_param must accept two parameters: array $message, int $level * $message is an array containing the messages the log, $level, is the logging level */ public static function constructor($mode, $optional = null, $prefix = '', $level = self::NOTICE, $max_size = 100 * 1024 * 1024) { self::$default = new self($mode, $optional, $prefix, $level, $max_size); } public function __construct($mode, $optional = null, $prefix = '', $level = self::NOTICE, $max_size = 100 * 1024 * 1024) { if ($mode === null) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['no_mode_specified']); } $this->mode = $mode; $this->optional = $mode == 2 ? Absolute::absolute($optional) : $optional; $this->prefix = $prefix === '' ? '' : ', '.$prefix; $this->level = $level; if ($this->mode === 2 && !file_exists(pathinfo($this->optional, PATHINFO_DIRNAME))) { $this->optional = Magic::$script_cwd.'/MadelineProto.log'; } if ($this->mode === 2 && !preg_match('/\.log$/', $this->optional)) { $this->optional .= '.log'; } if ($mode === 2 && $max_size !== -1 && file_exists($this->optional) && filesize($this->optional) > $max_size) { unlink($this->optional); } $this->colors[self::ULTRA_VERBOSE] = implode(';', [self::foreground['light_gray'], self::set['dim']]); $this->colors[self::VERBOSE] = implode(';', [self::foreground['green'], self::set['bold']]); $this->colors[self::NOTICE] = implode(';', [self::foreground['yellow'], self::set['bold']]); $this->colors[self::WARNING] = implode(';', [self::foreground['white'], self::set['dim'], self::background['red']]); $this->colors[self::ERROR] = implode(';', [self::foreground['white'], self::set['bold'], self::background['red']]); $this->colors[self::FATAL_ERROR] = implode(';', [self::foreground['red'], self::set['bold'], self::background['light_gray']]); $this->newline = PHP_EOL; if ($this->mode === 3) { $this->stdout = getStdout(); if (php_sapi_name() !== 'cli') { $this->newline = '
'.$this->newline; } } elseif ($this->mode === 2) { $this->stdout = new ResourceOutputStream(fopen($this->optional, 'a+')); } elseif ($this->mode === 1) { $result = @ini_get('error_log'); if ($result === 'syslog') { $this->stdout = getStderr(); } elseif ($result) { $this->stdout = new ResourceOutputStream(fopen($result, 'a+')); } else { $this->stdout = getStderr(); } } } public static function log($param, $level = self::NOTICE) { if (!is_null(self::$default)) { self::$default->logger($param, $level, basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php')); } } public function logger($param, $level = self::NOTICE, $file = null) { if ($level > $this->level || $this->mode === 0) { return false; } if (!self::$printed) { self::$printed = true; $this->colors[self::NOTICE] = implode(';', [self::foreground['light_gray'], self::set['bold'], self::background['blue']]); $this->logger('MadelineProto'); $this->logger('Copyright (C) 2016-2019 Daniil Gentili'); $this->logger('Licensed under AGPLv3'); $this->logger('https://github.com/danog/MadelineProto'); $this->colors[self::NOTICE] = implode(';', [self::foreground['yellow'], self::set['bold']]); } if ($this->mode === 4) { return call_user_func_array($this->optional, [$param, $level]); } $prefix = $this->prefix; if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread())) { $prefix .= ' (t)'; } if ($param instanceof \Throwable) { $param = (string) $param; } elseif (!is_string($param)) { $param = json_encode($param, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } if ($file === null) { $file = basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); } $param = str_pad($file.$prefix.': ', 16 + strlen($prefix))."\t".$param; switch ($this->mode) { case 1: if ($this->stdout->write($param.$this->newline) instanceof Failure) { error_log($param); } break; default: $param = Magic::$isatty ? "\33[".$this->colors[$level].'m'.$param."\33[0m".$this->newline : $param.$this->newline; if ($this->stdout->write($param) instanceof Failure) { switch ($this->mode) { case 3: echo $param; break; case 2: file_put_contents($this->optional, $param, FILE_APPEND); break; } } break; } } public function __destruct() { //$this->wait($this->stdout->write('')); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; abstract class CombinedEventHandler { private $CombinedAPI; public function __construct($CombinedAPI) { $this->CombinedAPI = $CombinedAPI; foreach ($CombinedAPI->instances as $path => $instance) { $this->referenceInstance($path); } } final public function __sleep() { $keys = method_exists($this, '__magic_sleep') ? $this->__magic_sleep() : get_object_vars($this); unset($keys['CombinedAPI']); if (isset($this->CombinedAPI) && $this->CombinedAPI instanceof CombinedAPI) { foreach ($this->CombinedAPI->instance_paths as $path) { unset($keys[$path]); } } else { foreach ($keys as $key => $value) { if ($value instanceof API && $key === $value->session) { unset($keys[$key]); } } } return array_keys($keys); } final public function referenceInstance($path) { $this->{$path} = $this->CombinedAPI->instances[$path]; } final public function removeInstance($path) { if (isset($this->{$path})) { unset($this->{$path}); } } } // Core types (no need to gen) //vector#1cb5c415 {t:Type} # [ t ] = Vector t; /////////////////////////////// /////////////////// Layer cons /////////////////////////////// //invokeAfterMsg#cb9f372d msg_id:long query:!X = X; //invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; //invokeWithLayer1#53835315 query:!X = X; //invokeWithLayer2#289dd1f6 query:!X = X; //invokeWithLayer3#b7475268 query:!X = X; //invokeWithLayer4#dea0d430 query:!X = X; //invokeWithLayer5#417a57ae query:!X = X; //invokeWithLayer6#3a64d54d query:!X = X; //invokeWithLayer7#a5be56d3 query:!X = X; //invokeWithLayer8#e9abd9fd query:!X = X; //invokeWithLayer9#76715a63 query:!X = X; //invokeWithLayer10#39620c41 query:!X = X; //invokeWithLayer11#a6b88fdf query:!X = X; //invokeWithLayer12#dda60d3c query:!X = X; //invokeWithLayer13#427c8ea2 query:!X = X; //invokeWithLayer14#2b9b08fa query:!X = X; //invokeWithLayer15#b4418b64 query:!X = X; //invokeWithLayer16#cf5f0987 query:!X = X; //invokeWithLayer17#50858a19 query:!X = X; //invokeWithLayer18#1c900537 query:!X = X; //invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer /////////////////////////////// /// Authorization key creation /////////////////////////////// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ////////////// System messages /////////////////////////////// ---types--- msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; //message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually //msg_container#73f1f8dc messages:vector = MessageContainer; // parsed manually //msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container //gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#630c9af1 flags:# file:InputFile caption:string stickers:flags.0?Vector = InputMedia; inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#d070f1e9 flags:# file:InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector = InputMedia; inputMediaUploadedThumbDocument#50d88cae flags:# file:InputFile thumb:InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector = InputMedia; inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia; inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#a14dca52 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat; channelForbidden#8537784f flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#c3d5512f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#c09be45f flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; dialog#66ffba14 flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; contacts.importedContacts#ad524315 imported:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true id:int ip_address:string port:int = DcOption; config#cb601684 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#410dee07 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole; channelRoleEditor#820bfe8c = ChannelParticipantRole; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#c786ddcb flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pagePart#8dee6c44 blocks:Vector photos:Vector videos:Vector = Page; pageFull#d7a19d69 blocks:Vector photos:Vector videos:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int a:flags.0?true b:flags.0?true c:flags.0?true d:flags.0?true api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#d4569248 flags:# peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; // LAYER 65 { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-2106507297", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "2004934137", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "-652419756", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "admins_enabled", "type": "flags.3?true" }, { "name": "admin", "type": "flags.4?true" }, { "name": "deactivated", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "migrated_to", "type": "flags.6?InputChannel" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "1061556205", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "1537633299", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" }, { "name": "views", "type": "flags.10?int" } ], "type": "Message" }, { "id": "-1066691065", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1217033015", "predicate": "messageActionChatAddUser", "params": [ { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1490799288", "predicate": "inputReportReasonSpam", "params": [], "type": "ReportReason" }, { "id": "505595789", "predicate": "inputReportReasonViolence", "params": [], "type": "ReportReason" }, { "id": "777640226", "predicate": "inputReportReasonPornography", "params": [], "type": "ReportReason" }, { "id": "-512463606", "predicate": "inputReportReasonOther", "params": [ { "name": "text", "type": "string" } ], "type": "ReportReason" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-136766906", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-892863022", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "ipv6", "type": "flags.0?true" }, { "name": "media_only", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1823925854", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "megagroup_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-302170017", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "int" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "channel", "type": "flags.0?true" }, { "name": "broadcast", "type": "flags.1?true" }, { "name": "public", "type": "flags.2?true" }, { "name": "megagroup", "type": "flags.3?true" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "installed", "type": "flags.0?true" }, { "name": "disabled", "type": "flags.1?true" }, { "name": "official", "type": "flags.2?true" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "847885712", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "self", "type": "flags.10?true" }, { "name": "contact", "type": "flags.11?true" }, { "name": "mutual_contact", "type": "flags.12?true" }, { "name": "deleted", "type": "flags.13?true" }, { "name": "bot", "type": "flags.14?true" }, { "name": "bot_chat_history", "type": "flags.15?true" }, { "name": "bot_nochats", "type": "flags.16?true" }, { "name": "verified", "type": "flags.17?true" }, { "name": "restricted", "type": "flags.18?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" }, { "name": "restiction_reason", "type": "flags.18?string" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "resize", "type": "flags.0?true" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-399192472", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "editor", "type": "flags.3?true" }, { "name": "moderator", "type": "flags.4?true" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "verified", "type": "flags.7?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "restricted", "type": "flags.9?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "restiction_reason", "type": "flags.9?string" } ], "type": "Chat" }, { "id": "763724588", "predicate": "channelForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1640751649", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "can_view_participants", "type": "flags.3?true" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" }, { "name": "migrated_from_chat_id", "type": "flags.4?int" }, { "name": "migrated_from_max_id", "type": "flags.4?int" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "1620337698", "predicate": "updateChannelTooLong", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1016324548", "predicate": "updateChannelGroup", "params": [ { "name": "channel_id", "type": "int" }, { "name": "group", "type": "MessageGroup" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "exclude_new_messages", "type": "flags.1?true" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" }, { "id": "-100588754", "predicate": "channelMessagesFilterCollapsed", "params": [], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipant" }, { "id": "-636267638", "predicate": "chatParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-489233354", "predicate": "chatParticipantAdmin", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "1855224129", "predicate": "updateChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1232070311", "predicate": "updateChatParticipantAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "is_admin", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1371385889", "predicate": "messageActionChatMigrateTo", "params": [ { "name": "channel_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1336546578", "predicate": "messageActionChannelMigrateFrom", "params": [ { "name": "title", "type": "string" }, { "name": "chat_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1328445861", "predicate": "channelParticipantsBots", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-236044656", "predicate": "help.termsOfService", "params": [ { "name": "text", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "1753886890", "predicate": "updateNewStickerSet", "params": [ { "name": "stickerset", "type": "messages.StickerSet" } ], "type": "Update" }, { "id": "-253774767", "predicate": "updateStickerSetsOrder", "params": [ { "name": "order", "type": "Vector" } ], "type": "Update" }, { "id": "1135492588", "predicate": "updateStickerSets", "params": [], "type": "Update" }, { "id": "-814484985", "predicate": "webPageExternal", "params": [ { "name": "flags", "type": "#" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "thumb_url", "type": "flags.3?string" }, { "name": "content_url", "type": "flags.4?string" }, { "name": "w", "type": "flags.5?int" }, { "name": "h", "type": "flags.5?int" }, { "name": "duration", "type": "flags.6?int" } ], "type": "WebPage" }, { "id": "-713438005", "predicate": "foundGif", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "FoundGif" }, { "id": "1212395773", "predicate": "inputMediaGifExternal", "params": [ { "name": "url", "type": "string" }, { "name": "q", "type": "string" } ], "type": "InputMedia" }, { "id": "1158290442", "predicate": "messages.foundGifs", "params": [ { "name": "next_offset", "type": "int" }, { "name": "results", "type": "Vector" } ], "type": "messages.FoundGifs" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "-1374118561", "method": "account.reportPeer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reason", "type": "ReportReason" } ], "type": "Bool" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1799878989", "method": "messages.getDialogs", "params": [ { "name": "offset_date", "type": "int" }, { "name": "offset_id", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1970355494", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "238054714", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "-1212072999", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "479598769", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-421563528", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "increment", "type": "Bool" } ], "type": "Vector" }, { "id": "-1445735863", "method": "channels.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-575067701", "method": "channels.getImportantHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "-192332417", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.0?true" }, { "name": "megagroup", "type": "flags.1?true" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "-344583728", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Updates" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-1432183160", "method": "channels.toggleComments", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" }, { "id": "-326379039", "method": "messages.toggleChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1444503762", "method": "messages.editChatAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "is_admin", "type": "Bool" } ], "type": "Bool" }, { "id": "363051235", "method": "messages.migrateChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Updates" }, { "id": "-1640190800", "method": "messages.searchGlobal", "params": [ { "name": "q", "type": "string" }, { "name": "offset_date", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "936873859", "method": "help.getTermsOfService", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "-1613775824", "method": "messages.reorderStickerSets", "params": [ { "name": "order", "type": "Vector" } ], "type": "Bool" }, { "id": "864953444", "method": "messages.getDocumentByHash", "params": [ { "name": "sha256", "type": "bytes" }, { "name": "size", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "Document" }, { "id": "-1080395925", "method": "messages.searchGifs", "params": [ { "name": "q", "type": "string" }, { "name": "offset", "type": "int" } ], "type": "messages.FoundGifs" } ] }{ "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-2106507297", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "2004934137", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1855757255", "predicate": "chat", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "left", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-83047359", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "date", "type": "int" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "265468810", "predicate": "chatParticipantsForbidden", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-1421842653", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Message" }, { "id": "-1066691065", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "1060296792", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-113206467", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1311946900", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "974056226", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "-360210539", "predicate": "contactFound", "params": [ { "name": "user_id", "type": "int" } ], "type": "ContactFound" }, { "id": "90570766", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-719474725", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "751004017", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-829325875", "predicate": "chatInvite", "params": [ { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "585404530", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-637586372", "predicate": "inputChatEmpty", "params": [], "type": "InputChat" }, { "id": "1134934467", "predicate": "inputChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputChat" }, { "id": "818335347", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChat" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-1917119391", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-343274136", "predicate": "channelFull", "params": [ { "name": "id", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "1620337698", "predicate": "updateChannelTooLong", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2017952899", "predicate": "updateReadChannelInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "299511878", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "peer", "type": "Peer" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-2053423812", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-505490651", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "132772523", "method": "messages.search", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-1336990448", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1440838285", "method": "messages.forwardMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" } ], "type": "Updates" }, { "id": "41608795", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "57298430", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "InputChat" } ], "type": "messages.ChatFull" }, { "id": "1721357574", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "InputChat" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-579504755", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "InputChat" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-2121169932", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "InputChat" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-1819099025", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "InputChat" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "200282908", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1033305414", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "InputChat" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-187955923", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "chat_id", "type": "InputChat" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1838639741", "method": "messages.getChannelDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "632812466", "method": "messages.getImportantHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "916529422", "method": "messages.readChannelHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-641966126", "method": "messages.createChannel", "params": [ { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-1718245297", "method": "messages.deleteChannelMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "613086453", "method": "updates.getChannelDifference", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" } ] }. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\ByteStream\ClosedException; use Amp\Deferred; use Amp\Promise; use danog\MadelineProto\Loop\Connection\CheckLoop; use danog\MadelineProto\Loop\Connection\HttpWaitLoop; use danog\MadelineProto\Loop\Connection\ReadLoop; use danog\MadelineProto\Loop\Connection\WriteLoop; use danog\MadelineProto\MTProtoTools\Crypt; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoTools\MsgIdHandler; use danog\MadelineProto\Stream\MTProtoTools\SeqNoHandler; /** * Connection class. * * Manages connection to Telegram datacenters * * @author Daniil Gentili */ class Connection { use Crypt; use MsgIdHandler; use SeqNoHandler; use \danog\Serializable; use Tools; const API_ENDPOINT = 0; const VOIP_UDP_REFLECTOR_ENDPOINT = 1; const VOIP_TCP_REFLECTOR_ENDPOINT = 2; const VOIP_UDP_P2P_ENDPOINT = 3; const VOIP_UDP_LAN_ENDPOINT = 4; const PENDING_MAX = 2000000000; public $stream; public $time_delta = 0; public $type = 0; public $peer_tag; public $temp_auth_key; public $auth_key; public $session_id; public $session_out_seq_no = 0; public $session_in_seq_no = 0; public $incoming_messages = []; public $outgoing_messages = []; public $new_incoming = []; public $new_outgoing = []; public $pending_outgoing = []; public $pending_outgoing_key = 0; public $pending_outgoing_unencrypted = []; public $pending_outgoing_unencrypted_key = 0; public $max_incoming_id; public $max_outgoing_id; public $authorized = false; public $call_queue = []; public $ack_queue = []; public $i = []; public $last_recv = 0; public $last_http_wait = 0; public $datacenter; public $API; public $resumeWriterDeferred; public $ctx; public $pendingCheckWatcherId; public $http_req_count = 0; public $http_res_count = 0; public function getCtx() { return $this->ctx; } /** * Connect function. * * Connects to a telegram DC using the specified protocol, proxy and connection parameters * * @param string $proxy Proxy class name * * @internal * * @return \Amp\Promise */ public function connect(ConnectionContext $ctx): \Generator { $this->API->logger->logger("Trying connection via $ctx", \danog\MadelineProto\Logger::WARNING); $this->ctx = $ctx->getCtx(); $this->datacenter = $ctx->getDc(); $this->stream = yield $ctx->getStream(); if (isset($this->old)) { unset($this->old); } if (!isset($this->writer)) { $this->writer = new WriteLoop($this->API, $this->datacenter); } if (!isset($this->reader)) { $this->reader = new ReadLoop($this->API, $this->datacenter); } if (!isset($this->checker)) { $this->checker = new CheckLoop($this->API, $this->datacenter); } if (!isset($this->waiter)) { $this->waiter = new HttpWaitLoop($this->API, $this->datacenter); } foreach ($this->new_outgoing as $message_id) { if ($this->outgoing_messages[$message_id]['unencrypted']) { $promise = $this->outgoing_messages[$message_id]['promise']; \Amp\Loop::defer(function () use ($promise) { $promise->fail(new Exception('Restart because we were reconnected')); }); unset($this->new_outgoing[$message_id]); unset($this->outgoing_messages[$message_id]); } } $this->http_req_count = 0; $this->http_res_count = 0; $this->writer->start(); $this->reader->start(); if (!$this->checker->start()) { $this->checker->resume(); } $this->waiter->start(); } public function sendMessage($message, $flush = true) { $deferred = new Deferred(); if (!isset($message['serialized_body'])) { $body = is_object($message['body']) ? yield $message['body'] : $message['body']; $refresh_next = isset($message['refresh_next']) && $message['refresh_next']; //$refresh_next = true; if ($refresh_next) { $this->API->referenceDatabase->refreshNext(true); } if ($message['method']) { $body = yield $this->API->serialize_method_async($message['_'], $body); } else { $body = yield $this->API->serialize_object_async(['type' => $message['_']], $body, $message['_']); } if ($refresh_next) { $this->API->referenceDatabase->refreshNext(false); } $message['serialized_body'] = $body; unset($body); } $message['send_promise'] = $deferred; $this->pending_outgoing[$this->pending_outgoing_key++] = $message; $this->pending_outgoing_key %= self::PENDING_MAX; if ($flush) { $this->writer->resume(); } return $deferred->promise(); } public function setExtra($extra) { $this->API = $extra; } public function disconnect() { $this->API->logger->logger("Disconnecting from DC {$this->datacenter}"); $this->old = true; foreach (['reader', 'writer', 'checker', 'waiter', 'updater'] as $loop) { if (isset($this->{$loop}) && $this->{$loop}) { $this->{$loop}->signal($loop === 'reader' ? new NothingInTheSocketException() : true); } } if ($this->stream) { try { $this->stream->disconnect(); } catch (ClosedException $e) { $this->API->logger->logger($e); } } $this->API->logger->logger("Disconnected from DC {$this->datacenter}"); } public function reconnect(): \Generator { $this->API->logger->logger("Reconnecting DC {$this->datacenter}"); $this->disconnect(); yield $this->API->datacenter->dcConnectAsync($this->ctx->getDc()); if ($this->API->hasAllAuth() && !$this->hasPendingCalls()) { $this->callFork($this->API->method_call_async_read('ping', ['ping_id' => $this->random_int()], ['datacenter' => $this->datacenter])); } } public function hasPendingCalls() { $API = $this->API; $datacenter = $this->datacenter; $dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all'; $timeout = $API->settings['connection_settings'][$dc_config_number]['timeout']; $pfs = $API->settings['connection_settings'][$dc_config_number]['pfs']; foreach ($this->new_outgoing as $message_id) { if (isset($this->outgoing_messages[$message_id]['sent']) && $this->outgoing_messages[$message_id]['sent'] + $timeout < time() && ($this->temp_auth_key === null) === $this->outgoing_messages[$message_id]['unencrypted'] && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req' ) { if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { continue; } return true; } } return false; } public function getPendingCalls() { $API = $this->API; $datacenter = $this->datacenter; $dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all'; $timeout = $API->settings['connection_settings'][$dc_config_number]['timeout']; $pfs = $API->settings['connection_settings'][$dc_config_number]['pfs']; $result = []; foreach ($this->new_outgoing as $message_id) { if (isset($this->outgoing_messages[$message_id]['sent']) && $this->outgoing_messages[$message_id]['sent'] + $timeout < time() && ($this->temp_auth_key === null) === $this->outgoing_messages[$message_id]['unencrypted'] && $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req' ) { if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { continue; } $result[] = $message_id; } } return $result; } public function getName(): string { return __CLASS__; } /** * Sleep function. * * @internal * * @return array */ public function __sleep() { return ['peer_tag', 'temp_auth_key', 'auth_key', 'session_id', 'session_out_seq_no', 'session_in_seq_no', 'max_incoming_id', 'max_outgoing_id', 'authorized', 'ack_queue']; } public function __wakeup() { $this->time_delta = 0; $this->pending_outgoing = []; $this->new_outgoing = []; $this->new_incoming = []; $this->outgoing_messages = []; $this->incoming_messages = []; } } { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-2106507297", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "2004934137", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "-652419756", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "admins_enabled", "type": "flags.3?true" }, { "name": "admin", "type": "flags.4?true" }, { "name": "deactivated", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "migrated_to", "type": "flags.6?InputChannel" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "1061556205", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-913120932", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" }, { "name": "views", "type": "flags.10?int" } ], "type": "Message" }, { "id": "-1066691065", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1217033015", "predicate": "messageActionChatAddUser", "params": [ { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1490799288", "predicate": "inputReportReasonSpam", "params": [], "type": "ReportReason" }, { "id": "505595789", "predicate": "inputReportReasonViolence", "params": [], "type": "ReportReason" }, { "id": "777640226", "predicate": "inputReportReasonPornography", "params": [], "type": "ReportReason" }, { "id": "-512463606", "predicate": "inputReportReasonOther", "params": [ { "name": "text", "type": "string" } ], "type": "ReportReason" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "-3644025", "predicate": "inputMessagesFilterGif", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "333766314", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "613087842", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "ipv6", "type": "flags.0?true" }, { "name": "media_only", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "112969208", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "megagroup_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "saved_gifs_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "495530093", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1386138479", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "444068508", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-203411800", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-302170017", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "int" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "channel", "type": "flags.0?true" }, { "name": "broadcast", "type": "flags.1?true" }, { "name": "public", "type": "flags.2?true" }, { "name": "megagroup", "type": "flags.3?true" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "installed", "type": "flags.0?true" }, { "name": "disabled", "type": "flags.1?true" }, { "name": "official", "type": "flags.2?true" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "-787638374", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "self", "type": "flags.10?true" }, { "name": "contact", "type": "flags.11?true" }, { "name": "mutual_contact", "type": "flags.12?true" }, { "name": "deleted", "type": "flags.13?true" }, { "name": "bot", "type": "flags.14?true" }, { "name": "bot_chat_history", "type": "flags.15?true" }, { "name": "bot_nochats", "type": "flags.16?true" }, { "name": "verified", "type": "flags.17?true" }, { "name": "restricted", "type": "flags.18?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" }, { "name": "restriction_reason", "type": "flags.18?string" }, { "name": "bot_inline_placeholder", "type": "flags.19?string" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "resize", "type": "flags.0?true" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "1260090630", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "editor", "type": "flags.3?true" }, { "name": "moderator", "type": "flags.4?true" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "verified", "type": "flags.7?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "restricted", "type": "flags.9?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "restriction_reason", "type": "flags.9?string" } ], "type": "Chat" }, { "id": "763724588", "predicate": "channelForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1640751649", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "can_view_participants", "type": "flags.3?true" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" }, { "name": "migrated_from_chat_id", "type": "flags.4?int" }, { "name": "migrated_from_max_id", "type": "flags.4?int" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "1620337698", "predicate": "updateChannelTooLong", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1016324548", "predicate": "updateChannelGroup", "params": [ { "name": "channel_id", "type": "int" }, { "name": "group", "type": "MessageGroup" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "exclude_new_messages", "type": "flags.1?true" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" }, { "id": "-100588754", "predicate": "channelMessagesFilterCollapsed", "params": [], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipant" }, { "id": "-636267638", "predicate": "chatParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-489233354", "predicate": "chatParticipantAdmin", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "1855224129", "predicate": "updateChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1232070311", "predicate": "updateChatParticipantAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "is_admin", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1371385889", "predicate": "messageActionChatMigrateTo", "params": [ { "name": "channel_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1336546578", "predicate": "messageActionChannelMigrateFrom", "params": [ { "name": "title", "type": "string" }, { "name": "chat_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1328445861", "predicate": "channelParticipantsBots", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-236044656", "predicate": "help.termsOfService", "params": [ { "name": "text", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "1753886890", "predicate": "updateNewStickerSet", "params": [ { "name": "stickerset", "type": "messages.StickerSet" } ], "type": "Update" }, { "id": "-253774767", "predicate": "updateStickerSetsOrder", "params": [ { "name": "order", "type": "Vector" } ], "type": "Update" }, { "id": "1135492588", "predicate": "updateStickerSets", "params": [], "type": "Update" }, { "id": "372165663", "predicate": "foundGif", "params": [ { "name": "url", "type": "string" }, { "name": "thumb_url", "type": "string" }, { "name": "content_url", "type": "string" }, { "name": "content_type", "type": "string" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "FoundGif" }, { "id": "-1670052855", "predicate": "foundGifCached", "params": [ { "name": "url", "type": "string" }, { "name": "photo", "type": "Photo" }, { "name": "document", "type": "Document" } ], "type": "FoundGif" }, { "id": "1212395773", "predicate": "inputMediaGifExternal", "params": [ { "name": "url", "type": "string" }, { "name": "q", "type": "string" } ], "type": "InputMedia" }, { "id": "1158290442", "predicate": "messages.foundGifs", "params": [ { "name": "next_offset", "type": "int" }, { "name": "results", "type": "Vector" } ], "type": "messages.FoundGifs" }, { "id": "-402498398", "predicate": "messages.savedGifsNotModified", "params": [], "type": "messages.SavedGifs" }, { "id": "772213157", "predicate": "messages.savedGifs", "params": [ { "name": "hash", "type": "int" }, { "name": "gifs", "type": "Vector" } ], "type": "messages.SavedGifs" }, { "id": "-1821035490", "predicate": "updateSavedGifs", "params": [], "type": "Update" }, { "id": "776201607", "predicate": "inputBotInlineMessageMediaAuto", "params": [ { "name": "caption", "type": "string" } ], "type": "InputBotInlineMessage" }, { "id": "-1376723087", "predicate": "inputBotInlineMessageText", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.0?true" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.1?Vector" } ], "type": "InputBotInlineMessage" }, { "id": "750510426", "predicate": "inputBotInlineResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "url", "type": "flags.3?string" }, { "name": "thumb_url", "type": "flags.4?string" }, { "name": "content_url", "type": "flags.5?string" }, { "name": "content_type", "type": "flags.5?string" }, { "name": "w", "type": "flags.6?int" }, { "name": "h", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "-61413251", "predicate": "botInlineMessageMediaAuto", "params": [ { "name": "caption", "type": "string" } ], "type": "BotInlineMessage" }, { "id": "-1520330839", "predicate": "botInlineMessageText", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.0?true" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.1?Vector" } ], "type": "BotInlineMessage" }, { "id": "-124267714", "predicate": "botInlineMediaResultDocument", "params": [ { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "document", "type": "Document" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "-984447609", "predicate": "botInlineMediaResultPhoto", "params": [ { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "photo", "type": "Photo" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "-1679053127", "predicate": "botInlineResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "url", "type": "flags.3?string" }, { "name": "thumb_url", "type": "flags.4?string" }, { "name": "content_url", "type": "flags.5?string" }, { "name": "content_type", "type": "flags.5?string" }, { "name": "w", "type": "flags.6?int" }, { "name": "h", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "292597923", "predicate": "messages.botResults", "params": [ { "name": "flags", "type": "#" }, { "name": "gallery", "type": "flags.0?true" }, { "name": "query_id", "type": "long" }, { "name": "next_offset", "type": "flags.1?string" }, { "name": "results", "type": "Vector" } ], "type": "messages.BotResults" }, { "id": "-1071715832", "predicate": "updateBotInlineQuery", "params": [ { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "query", "type": "string" }, { "name": "offset", "type": "string" } ], "type": "Update" }, { "id": "258597139", "predicate": "updateBotInlineSend", "params": [ { "name": "user_id", "type": "int" }, { "name": "query", "type": "string" }, { "name": "id", "type": "string" } ], "type": "Update" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "-1374118561", "method": "account.reportPeer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reason", "type": "ReportReason" } ], "type": "Bool" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1799878989", "method": "messages.getDialogs", "params": [ { "name": "offset_date", "type": "int" }, { "name": "offset_id", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1970355494", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "238054714", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "-1212072999", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "479598769", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-421563528", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "increment", "type": "Bool" } ], "type": "Vector" }, { "id": "-1445735863", "method": "channels.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-575067701", "method": "channels.getImportantHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "-192332417", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.0?true" }, { "name": "megagroup", "type": "flags.1?true" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "-344583728", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Updates" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-1432183160", "method": "channels.toggleComments", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" }, { "id": "-326379039", "method": "messages.toggleChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1444503762", "method": "messages.editChatAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "is_admin", "type": "Bool" } ], "type": "Bool" }, { "id": "363051235", "method": "messages.migrateChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Updates" }, { "id": "-1640190800", "method": "messages.searchGlobal", "params": [ { "name": "q", "type": "string" }, { "name": "offset_date", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "936873859", "method": "help.getTermsOfService", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "-1613775824", "method": "messages.reorderStickerSets", "params": [ { "name": "order", "type": "Vector" } ], "type": "Bool" }, { "id": "864953444", "method": "messages.getDocumentByHash", "params": [ { "name": "sha256", "type": "bytes" }, { "name": "size", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "Document" }, { "id": "-1080395925", "method": "messages.searchGifs", "params": [ { "name": "q", "type": "string" }, { "name": "offset", "type": "int" } ], "type": "messages.FoundGifs" }, { "id": "-2084618926", "method": "messages.getSavedGifs", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.SavedGifs" }, { "id": "846868683", "method": "messages.saveGif", "params": [ { "name": "id", "type": "InputDocument" }, { "name": "unsave", "type": "Bool" } ], "type": "Bool" }, { "id": "-1826332659", "method": "messages.getInlineBotResults", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "query", "type": "string" }, { "name": "offset", "type": "string" } ], "type": "messages.BotResults" }, { "id": "1059318802", "method": "messages.setInlineBotResults", "params": [ { "name": "flags", "type": "#" }, { "name": "gallery", "type": "flags.0?true" }, { "name": "private", "type": "flags.1?true" }, { "name": "query_id", "type": "long" }, { "name": "results", "type": "Vector" }, { "name": "cache_time", "type": "int" }, { "name": "next_offset", "type": "flags.2?string" } ], "type": "Bool" }, { "id": "-1318189314", "method": "messages.sendInlineBotResult", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "random_id", "type": "long" }, { "name": "query_id", "type": "long" }, { "name": "id", "type": "string" } ], "type": "Updates" } ] }---types--- ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#eb7bb160 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password; account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password; account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings; account.passwordInputSettings#21ffa60d flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_salt:flags.2?bytes new_secure_secret:flags.2?bytes new_secure_secret_id:flags.2?long = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.wTermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector users:Vector = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#b4b4b699 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#67872e8 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#cb976d53 flags:# selfie_required:flags.1?true required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector; account.getSecureValue#73665bc2 types:Vector = Vector; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector; // LAYER 81 . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; /** * Manages serialization of the MadelineProto instance. */ class Absolute { public static function absolute($file) { if (($file[0] !== '/') && ($file[1] !== ':') && !in_array(substr($file, 0, 4), ['phar', 'http'])) { $file = Magic::getcwd().'/'.$file; } return $file; } } //@description Object of this type may be returned on every function call in case of the error //@code Error code, maybe changed in the future. If code == 406, error message should not be processed in any way and shouldn't be showed to the user //@message Error message, may be changed in the future error code:int message:string = Error; //@description Object of this type returns on successful function call for some functions ok = Ok; //@class AuthCodeType @description Provides information about the way an authentication code is delivered to the user //@description Code is delivered through private Telegram message, which can be viewed in the other client @length Length of the code authCodeTypeMessage length:int = AuthCodeType; //@description Code is delivered by SMS to the specified phone number @length Length of the code authCodeTypeSms length:int = AuthCodeType; //@description Code is delivered by phone call to the specified phone number @length Length of the code authCodeTypeCall length:int = AuthCodeType; //@description Code is delivered by the immediately cancelled call to the specified phone number. Number from which the call was done is the code @pattern Pattern of the phone number from which the call will be done authCodeTypeFlashCall pattern:string = AuthCodeType; //@class AuthState @description Represents current authorization state of the Client //@description TDLib needs user's phone number to authorize authStateWaitPhoneNumber = AuthState; //@description TDLib needs user authentication code to finish authorization @is_registered True, if user is already registered @code_type Describes the way, code was sent to the user @next_code_type Describes the way, next code will be sent to the user, nullable @timeout Timeout in seconds before code should be resent by calling resendAuthCode authStateWaitCode is_registered:Bool code_type:AuthCodeType next_code_type:AuthCodeType timeout:int = AuthState; //@description User is authorized but he needs to enter its password to begin to use application @password_hint Hint on password, can be empty @has_recovery_email Is recovery email set up //@recovery_email_pattern Pattern of email to which recovery mail was sent, empty before recovery email was sent authStateWaitPassword password_hint:string has_recovery_email:Bool recovery_email_pattern:string = AuthState; //@description User is successfully authorized. TDLib can answer queries authStateOk = AuthState; //@description User is currently logging out authStateLoggingOut = AuthState; //@description Represents current state of the two-step verification @has_password Is password set up @password_hint Hint on password, can be empty @has_recovery_email Is recovery email set up @unconfirmed_recovery_email_pattern Pattern of email to which confirmation mail was sent passwordState has_password:Bool password_hint:string has_recovery_email:Bool unconfirmed_recovery_email_pattern:string = PasswordState; //@description Contains information available to the user after requesting password recovery @recovery_email_pattern Pattern of email to which recovery mail was sent passwordRecoveryInfo recovery_email_pattern:string = PasswordRecoveryInfo; //@description Contains information about set up recovery email @recovery_email Recovery email recoveryEmail recovery_email:string = RecoveryEmail; //@description Returns information about availability of temporary password, which should be used for payments @has_password True, if we have temporary password @valid_for Time left before temporary password expires, seconds temporaryPasswordState has_password:Bool valid_for:int = TemporaryPasswordState; //@description Represents a file //@id Unique file identifier //@persistent_id Persistent file identifier, if exists. Can be used across application restarts or even other devices for current logged user. If begins with "http://" or "https://", it is HTTP URL of the file. Currently, TDLib is unable to download files if only they URL is known.-If downloadFile is called on a such file or it is sended to a secret chat TDLib starts file generation process by sending to the client updateFileGenerationStart with HTTP URL in the original_path and "#url#" as conversion string. Client supposed to generate the file by downloading it to the specified location //@size File size, 0 if unknown //@is_being_downloaded True, if the file is currently being downloaded //@local_size Size of locally available part of the file. If size != 0 && local_size == size, full file is available locally //@is_being_uploaded True, if the file is currently being uploaded //@remote_size Size of remotely available part of the file. If size != 0 && remote_size == size, the file is available remotely //@path Local path to the available file part, may be empty file id:int persistent_id:string size:int is_being_downloaded:Bool local_size:int is_being_uploaded:Bool remote_size:int path:string = File; //@class InputFile @description Points to some file //@description File defined by its id @id Unique file identifier inputFileId id:int = InputFile; //@description File defined by its persistent id @persistent_id Persistent file identifier inputFilePersistentId persistent_id:string = InputFile; //@description File deifned by local path @path Local path to the file inputFileLocal path:string = InputFile; //@description File generated by the client @original_path Local path to a file from which the file is generated, may be empty if there is no such file @conversion String specifying conversion applied to the original file, should be persistent across application restart @expected_size Expected size of the generated file, 0 if unknown inputFileGenerated original_path:string conversion:string expected_size:int = InputFile; //@description Photo description @type Thumbnail type (see https://core.telegram.org/constructor/photoSize) @photo Information about photo file @width Photo width @height Photo height photoSize type:string photo:file width:int height:int = PhotoSize; //@description Position on a photo where a mask should be placed @point Part of a face relative to which the mask should be placed. 0 - forehead, 1 - eyes, 2 - mouth, 3 - chin //@x_shift Shift by X-axis measured in widths of the mask scaled to the face size, from left to right. For example, choosing -1.0 will place mask just to the left of the default mask position //@y_shift Shift by Y-axis measured in heights of the mask scaled to the face size, from top to bottom. For example, 1.0 will place the mask just below the default mask position. //@scale Mask scaling coefficient. For example, 2.0 means double size maskPosition point:int x_shift:double y_shift:double scale:double = MaskPosition; //@description Represent part of the text which needs to be formatted in some unusual way @offset Offset of the entity in UTF-16 code points @length Length of the entity in UTF-16 code points @type Type of the entity textEntity offset:int length:int type:TextEntityType = TextEntity; //@description Describes animation file. Animation should be encoded in gif or mp4 format @duration Duration of the animation in seconds as defined by sender @width Width of the animation @height Height of the animation //@file_name Original name of a file as defined by sender @mime_type MIME type of a file, usually "image/gif" or "video/mp4" @thumb Animation thumb, nullable @animation File with the animation animation duration:int width:int height:int file_name:string mime_type:string thumb:photoSize animation:file = Animation; //@description Describes audio file. Audio is usually in mp3 format @duration Duration of the audio in seconds as defined by sender @title Title of the audio as defined by sender @performer Performer of the audio as defined by sender //@file_name Original name of a file as defined by sender @mime_type MIME type of a file as defined by sender @album_cover_thumb Thumb of the album's cover as defined by sender. Full size thumb should be extracted from the downloaded file, nullable @audio File with the audio audio duration:int title:string performer:string file_name:string mime_type:string album_cover_thumb:photoSize audio:file = Audio; //@description Describes document of any type @file_name Original name of a file as defined by sender @mime_type MIME type of file as defined by sender //@thumb Document thumb as defined by sender, nullable @document File with document document file_name:string mime_type:string thumb:photoSize document:file = Document; //@description Describes photo @id Photo identifier, 0 for deleted photo @has_stickers True, if some stickers was added to the photo @sizes Available variants of photo of different sizes photo id:int64 has_stickers:Bool sizes:vector = Photo; //@description Describes sticker @set_id Identifier of sticker set to which the sticker belongs or 0 if none @width Sticker width as defined by sender @height Sticker height as defined by sender //@emoji Emoji corresponding to the sticker @is_mask True, if the sticker is a mask @mask_position Position where the mask should be placed, nullable @thumb Sticker thumb in webp or jpeg format, nullable @sticker File with sticker sticker set_id:int64 width:int height:int emoji:string is_mask:Bool mask_position:maskPosition thumb:photoSize sticker:file = Sticker; //@description Describes video file @duration Duration of the video in seconds as defined by sender @width Video width as defined by sender @height Video height as defined by sender //@file_name Original name of a file as defined by sender @mime_type MIME type of a file as defined by sender @has_stickers True, if some stickers was added to the photo @thumb Video thumb as defined by sender, nullable @video File with the video video duration:int width:int height:int file_name:string mime_type:string has_stickers:Bool thumb:photoSize video:file = Video; //@description Describes video note. Video must have equal width and height, cropped to circle and stored in mpeg4 format @duration Duration of the video in seconds as defined by sender @length Video width and height as defined by sender @thumb Video thumb as defined by sender, nullable @video File with the video videoNote duration:int length:int thumb:photoSize video:file = VideoNote; //@description Describes voice note. Voice must be encoded with Opus codec and must be stored inside Ogg container @duration Duration of the voice record in seconds as defined by sender //@waveform Waveform representation of the voice in 5-bit format @mime_type MIME type of a file as defined by sender @voice File with the voice record voice duration:int waveform:bytes mime_type:string voice:file = Voice; //@description Describes user contact @phone_number User's phone number @first_name User first name, 1-255 characters @last_name User last name @user_id User identifier if known, 0 otherwise contact phone_number:string first_name:string last_name:string user_id:int = Contact; //@description Describes location on Earth @latitude Latitude of location in degrees as defined by sender @longitude Longitude of location in degrees as defined by sender location latitude:double longitude:double = Location; //@description Describes venue @location Venue location as defined by sender @title Venue name as defined by sender @address Venue address as defined by sender @provider Provider of venue database as defined by sender. Only "foursquare" need to be supported currently //@id Identifier of the venue in provider database as defined by sender venue location:location title:string address:string provider:string id:string = Venue; //@description Describes a game @id Game id @short_name Game short name, to share a game use a URL https://t.me/{bot_username}?game={game_short_name} @title Game title @text Game text, usually containing game scoreboards //@text_entities Entities contained in the text @param_description Game description @photo Game photo @animation Game animation, nullable game id:int64 short_name:string title:string text:string text_entities:vector description:string photo:photo animation:animation = Game; //@description Describes user profile photo @id Photo identifier, 0 for empty photo. Can be used to find photo in list of userProfilePhotos //@small Small (160x160) user profile photo @big Big (640x640) user profile photo profilePhoto id:int64 small:file big:file = ProfilePhoto; //@description Describes chat photo @small Small (160x160) chat photo @big Big (640x640) chat photo chatPhoto small:file big:file = ChatPhoto; //@class LinkState @description Represents ordered relationship between two users //@description Other user's phone number doesn't known linkStateNone = LinkState; //@description Other user's phone number is known but user not in contacts list linkStateKnowsPhoneNumber = LinkState; //@description Other user is in contacts list, particularly its phone number is known linkStateContact = LinkState; //@class UserType @description Allows to distinguish different kinds of users: general users, deleted users and bots //@description General user userTypeGeneral = UserType; //@description Deleted user or deleted bot. There is no any information about it except user_id. None of active action can be performed with deleted user userTypeDeleted = UserType; //@description Bot (see https://core.telegram.org/bots) @can_join_group_chats If true, bot can be invited to group and supergroup chats //@can_read_all_group_chat_messages If true, bot can read all group or supergroup chat messages, not only addressed to him. In private chats bot always can read all messages //@is_inline True, if bot supports inline queries @inline_query_placeholder Placeholder for inline query @need_location If true, user location should be sent with every inline query to this bot userTypeBot can_join_group_chats:Bool can_read_all_group_chat_messages:Bool is_inline:Bool inline_query_placeholder:string need_location:Bool = UserType; //@description Currently there is no any information about the user except user_id. It can happens very-very rarely. None of active action can be performed with unknown user userTypeUnknown = UserType; //@description Represents command supported by bot @command Text of the bot command @param_description Description of the bot command botCommand command:string description:string = BotCommand; //@description Provides information about bot and command supported by him @param_description Big description shown in user info page @commands List of commands cupported by bot botInfo description:string commands:vector = BotInfo; //@description Represents user @id User identifier @first_name User first name @last_name User last name @username User username //@phone_number User's phone number @status User's online status @profile_photo User profile photo, nullable //@my_link Relationships from me to other user @foreign_link Relationships from other user to me @is_verified True, if user is verified @restriction_reason If non-empty, contains the reason, why access to this user must be restricted. Format of the string is "{type}: {description}". -{type} contains type of the restriction and at least one of the suffixes "-all", "-ios", "-android", "-wp", which describes platforms on which access should be restricted. For example, "terms-ios-android". {description} contains human-readable description of the restriction, which can be showed to the user //@have_access If false, the user is inaccessible and the only known information about it is inside this class. It can't be passed to any method except GetUser. Currently it can be false only for inaccessible authors of the channel posts @type Type of the user @language_code Bots only. IETF language tag of users language user id:int first_name:string last_name:string username:string phone_number:string status:UserStatus profile_photo:profilePhoto my_link:LinkState foreign_link:LinkState is_verified:Bool restriction_reason:string have_access:Bool type:UserType language_code:string = User; //@description Gives full information about a user (except full list of profile photos) @is_blocked Is user blacklisted by the current user @can_be_called True, if the user can be called @has_private_calls True, if the user can't be called only because of his privacy settings //@about Short user bio or bot share text @common_chat_count Number of common chats between the user and current user, 0 for the current user @bot_info Information about bot if user is a bot, nullable userFull is_blocked:Bool can_be_called:Bool has_private_calls:Bool about:string common_chat_count:int bot_info:botInfo = UserFull; //@description Contains part of the list of user photos @total_count Total number of user profile photos @photos List of photos userProfilePhotos total_count:int photos:vector = UserProfilePhotos; //@description Represents list of users @total_count Approximate total count of found users @user_ids List of user identifiers users total_count:int user_ids:vector = Users; //@class ChatMemberStatus @description Provides information about status of a member in the chat //@description User is creator of the chat which has all administrator priviledges chatMemberStatusCreator = ChatMemberStatus; //@description User is a chat member with some additional priviledges. In groups, administrators can edit and delete other messages, add new members and ban unpriviledged members //@can_be_edited True, if current user has rights to edit administrator privileges of that user //@can_change_info True, if the administrator can change chat title, photo and other settings //@can_post_messages True, if the administrator can create channel posts, broadcast channels only //@can_edit_messages True, if the administrator can edit messages of other users, broadcast channels only //@can_delete_messages True, if the administrator can delete messages of other users //@can_invite_users True, if the administrator can invite new users to the chat //@can_restrict_members True, if the administrator can restrict, ban or unban chat members //@can_pin_messages True, if the administrator can pin messages, supergroup channels only //@can_promote_members True, if the administrator can add new administrators with a subset of his own privileges or demote administrators directly or indirectly promoted by him chatMemberStatusAdministrator can_be_edited:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool = ChatMemberStatus; //@description User is a member of the chat, but have no any additional privileges or restrictions chatMemberStatusMember = ChatMemberStatus; //@description User has some additional restrictions in the chat. Unsupported in group chats and broadcast channels //@is_member True, if user is chat member //@restricted_until_date Date when the user will be unrestricted, 0 if never. Unix time. If user is restricted for more than 366 days or less than 30 seconds from the current time it considered to be restricted forever //@can_send_messages True, if the user can send text messages, contacts, locations and venues //@can_send_media_messages True, if the user can send audios, documents, photos, videos, video notes and voice notes, implies can_send_messages //@can_send_other_messages True, if the user can send animations, games, stickers and use inline bots, implies can_send_media_messages //@can_add_web_page_previews True, if user may add web page preview to his messages, implies can_send_messages chatMemberStatusRestricted is_member:Bool restricted_until_date:int can_send_messages:Bool can_send_media_messages:Bool can_send_other_messages:Bool can_add_web_page_previews:Bool = ChatMemberStatus; //@description User is not a chat member chatMemberStatusLeft = ChatMemberStatus; //@description User was banned (and obviously is not a chat member) and can't return to the chat or view messages //@banned_until_date Date when the user will be unbanned, 0 if never. Unix time. If user is banned for more than 366 days or less than 30 seconds from the current time it considered to be banned forever chatMemberStatusBanned banned_until_date:int = ChatMemberStatus; //@description User with information about its chat joining/leaving @user_id User identifier of the chat member @inviter_user_id Identifier of a user invited/promoted/banned this member in the chat, 0 if unknown //@join_date Date the user has joined a chat, unix time @status Status of the member in the chat @bot_info Information about bot if user is a bot, nullable. Can be null even for bot if bot is not a chat member chatMember user_id:int inviter_user_id:int join_date:int status:ChatMemberStatus bot_info:botInfo = ChatMember; //@description Contains list of chat members @total_count Approximate total count of found chat members @members List of members chatMembers total_count:int members:vector = ChatMembers; //@class ChannelMembersFilter @description Specifies kind of chat users to return in getChannelMembers //@description Return recently active users in reverse chronological order channelMembersFilterRecent = ChannelMembersFilter; //@description Return creator and administrators channelMembersFilterAdministrators = ChannelMembersFilter; //@description Searches for channel members using specified query @query Query to search for channelMembersFilterSearch query:string = ChannelMembersFilter; //@description Return restricted channel members, administrators only @query Query to search for channelMembersFilterRestricted query:string = ChannelMembersFilter; //@description Return banned from the channel users, administrators only @query Query to search for channelMembersFilterBanned query:string = ChannelMembersFilter; //@description Return bot members of the channel channelMembersFilterBots = ChannelMembersFilter; //@description Represents a group of zero or more other users @id Group identifier //@member_count Group member count //@status Status of the current user in the group //@everyone_is_administrator True, if all members granted administrator rights in the group //@is_active True, if group is active //@migrated_to_channel_id Identifier of channel (supergroup) to which this group was migrated or 0 if none group id:int member_count:int status:ChatMemberStatus everyone_is_administrator:Bool is_active:Bool migrated_to_channel_id:int = Group; //@description Gives full information about a group @creator_user_id User identifier of the group creator, 0 if unknown @members Group members @invite_link Invite link for this group, available only for group creator and only after it is generated at least once groupFull creator_user_id:int members:vector invite_link:string = GroupFull; //@description Represents a channel with zero or more subscribers. There two different kinds of channels: supergroups and broadcast channels //@id Channel identifier //@username Channel username, empty for private channels //@date Date when current user has joined the channel or date when channel was created, if user is not a member. Unix time //@status Status of the current user in the channel //@anyone_can_invite True, if any member of the supergroup can invite other members. If the channel is not a supergroup, the field is meaningless //@sign_messages True, if messages sent to the channel should content information about the sender. If the channel is a supergroup, the field is meaningless //@is_supergroup True, if channel is a supergroup and is not a broadcast //@is_verified True, if the channel is verified //@restriction_reason If non-empty, contains the reason, why access to this channel must be restricted. Format of the string is "{type}: {description}". {type} contains type of the restriction and at least one of the suffixes "-all", "-ios", "-android", "-wp", which describes platforms on which access should be restricted. For example, "terms-ios-android". {description} contains human-readable description of the restriction, which can be showed to the user channel id:int username:string date:int status:ChatMemberStatus anyone_can_invite:Bool sign_messages:Bool is_supergroup:Bool is_verified:Bool restriction_reason:string = Channel; //@description Gives full information about a channel //@param_description Channel description //@member_count Channel member count, 0 if unknown //@administrator_count Number of privileged users in the channel, 0 if unknown //@restricted_count Number of restricted users in the channel, 0 if unknown //@banned_count Number of users banned from the channel, 0 if unknown //@can_get_members True, if members of the channel can be retrieved //@can_set_username True, if the channel can be made public //@can_set_sticker_set True, if the channel sticker set can be changed //@sticker_set_id Identifier of channel sticker set, or 0 if none //@invite_link Invite link for this channel //@pinned_message_id Identifier of the pinned message in the channel chat, or 0 if none //@migrated_from_group_id Identifier of the group, this supergroup migrated from, or 0 if none //@migrated_from_max_message_id Identifier of last message in the group chat migrated from, or 0 if none channelFull description:string member_count:int administrator_count:int restricted_count:int banned_count:int can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool sticker_set_id:int64 invite_link:string pinned_message_id:int53 migrated_from_group_id:int migrated_from_max_message_id:int53 = ChannelFull; //@description Represents a secret chat //@id Secret chat identifier //@user_id Identifier of the interlocutor //@state State of the secret chat, 0 - yet not created, 1 - active, 2 - closed //@is_outbound True if chat was created by the current logged in user, false otherwise //@ttl Current message TTL setting for the chat in seconds //@key_hash Hash of the current used key for comparison with the hash of the interlocutor's key. String of 36 bytes, which should be used to make a 12x12 square image with a color depth of 4. First 16 bytes should be used to make a central 8 * 8 square, left 20 bytes should be used to construct a border of width 2 around that square. Alternatively first 32 bytes of the hash can be converted to hex and printed as 32 2-digit hex numbers //@layer Secret chat layer, determining features supported by other client. Video notes are supported if layer >= 66 secretChat id:int user_id:int state:int is_outbound:Bool ttl:int key_hash:bytes layer:int = SecretChat; //@description Contains chat invite link @invite_link Chat invite link chatInviteLink invite_link:string = ChatInviteLink; //@description Contains information about chat invite link @chat_id Chat identifier of the invite link or 0 if user is not a member of this chat @title Title of the chat @photo Chat photo, nullable @member_count Total member count @member_user_ids User identifiers of some chat members that may be known to the current user //@is_group True, if the chat is a group chat @is_channel True, if the chat is a channel chat @is_public_channel True, if the chat is a channel chat with set up username @is_supergroup_channel True, if the chat is a supergroup channel chat chatInviteLinkInfo chat_id:int53 title:string photo:chatPhoto member_count:int member_user_ids:vector is_group:Bool is_channel:Bool is_public_channel:Bool is_supergroup_channel:Bool = ChatInviteLinkInfo; //@class MessageForwardInfo @description Contains information about initial sender of forwarded message //@description Message is originally written by known user @sender_user_id Identifier of a user, who originally sent this message @date Date when message was originally sent messageForwardedFromUser sender_user_id:int date:int = MessageForwardInfo; //@description Message is orifinally a channel post @chat_id Identifier of a chat from which message is forwarded @author_signature Post author signature //@date Date when message was originally sent @message_id Message identifier of the message from which the message is forwarded, 0 if unknown messageForwardedPost chat_id:int53 author_signature:string date:int message_id:int53 = MessageForwardInfo; //@class MessageSendState @description Contains information about sending state of the message //@description Message is incoming messageIsIncoming = MessageSendState; //@description Message is outgoing but is yet not delivered to the server messageIsBeingSent = MessageSendState; //@description Message was synchronized with the server messageIsSuccessfullySent = MessageSendState; //@description Message is failed to send messageIsFailedToSend = MessageSendState; //@description Describes message //@id Unique message identifier //@sender_user_id Identifier of the user who sent the message, 0 if unknown. It is unknown for channel posts //@chat_id Chat identifier //@send_state Information about sending state of the message //@can_be_edited True, if message can be edited //@can_be_forwarded True, if message can be forwarded //@can_be_deleted_only_for_self True, if message can be deleted only for self, other users will continue to see it //@can_be_deleted_for_everyone True, if message can be deleted for everyone //@is_post True, if message is channel post. All messages to broadcast channels are posts, all other messages are not posts //@contains_unread_mention True, if message contains unread mention of the current user //@date Date when message was sent, unix time //@edit_date Date when message was edited last time, unix time //@forward_info Information about initial message sender, nullable //@reply_to_message_id If non-zero, identifier of the message this message replies to, can be identifier of deleted message //@ttl Message TTL in seconds, 0 if none. TDLib will send updateDeleteMessages or updateMessageContent when TTL expires //@ttl_expires_in Time left for message TTL to expire in seconds //@via_bot_user_id If non-zero, user identifier of the bot this message is sent via //@author_signature For channel posts, optional author signature //@views Number of times this message was viewed //@content Content of the message //@reply_markup Reply markup for the message, nullable message id:int53 sender_user_id:int chat_id:int53 send_state:MessageSendState can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_everyone:Bool is_post:Bool contains_unread_mention:Bool date:int edit_date:int forward_info:MessageForwardInfo reply_to_message_id:int53 ttl:int ttl_expires_in:double via_bot_user_id:int author_signature:string views:int content:MessageContent reply_markup:ReplyMarkup = Message; //@description Contains list of messages @total_count Approximate total count of found messages @messages List of messages messages total_count:int messages:vector = Messages; //@description Contains list of found by search messages @messages List of messages @next_from_search_id Value to pass as from_search_id to get more results foundMessages messages:vector next_from_search_id:int64 = FoundMessages; //@class NotificationSettingsScope @description Describes kinds of chat for which notification settings are applied //@description Notification settings applied to particular chat @chat_id Chat identifier notificationSettingsScopeChat chat_id:int53 = NotificationSettingsScope; //@description Notification settings applied to all private chats notificationSettingsScopePrivateChats = NotificationSettingsScope; //@description Notification settings applied to all group and broadcast channel chats (supergroup channels have no common settings) notificationSettingsScopeGroupChats = NotificationSettingsScope; //@description Notification settings applied to all chats notificationSettingsScopeAllChats = NotificationSettingsScope; //@description Contains information about notification settings for chat or chats @mute_for Time left before notifications will be unmuted, seconds @sound Audio file name for notifications, iPhone apps only @show_preview Display message text/media in notification notificationSettings mute_for:int sound:string show_preview:Bool = NotificationSettings; //@description Contains information about draft of a message @reply_to_message_id Identifier of a message to reply to or 0 @input_message_text Content of a draft message, always should be of a type inputMessageText draftMessage reply_to_message_id:int53 input_message_text:InputMessageContent = DraftMessage; //@class ChatType @description Describes type of a chat //@description Ordinary chat with a user @user_id User identifier chatTypePrivate user_id:int = ChatType; //@description Chat with zero or more other users @group_id Group identifier chatTypeGroup group_id:int = ChatType; //@description Chat with unlimited number of members @channel_id Channel identifier @is_supergroup True, if the channel is a supergroup and is not a broadcast chatTypeChannel channel_id:int is_supergroup:Bool = ChatType; //@description Secret chat with a user @secret_chat_id Secret chat identifier @user_id User identifier of the peer chatTypeSecret secret_chat_id:int user_id:int = ChatType; //@description Chat (private chat or group chat or channel chat) //@id Chat unique identifier //@type Information about type of the chat //@title Chat title //@photo Chat photo, nullable //@top_message Last message in the chat, nullable //@order Parameter by descending of which chats are sorted in the chat list. If order of two chats is equal, then they need to be sorted by id also in descending order. If order == 0, position of the chat in the list is undetermined //@is_pinned True, if the chat is pinned //@unread_count Count of unread messages in the chat //@last_read_inbox_message_id Identifier of last read incoming message //@last_read_outbox_message_id Identifier of last read outgoing message //@unread_mention_count Count of unread messages with mention/reply in the chat //@notification_settings Notification settings for this chat //@reply_markup_message_id Identifier of the message from which reply markup need to be used or 0 if there is no default custom reply markup in the chat //@draft_message Draft of a message in the chat, nullable. parse_mode in input_message_text always will be null //@client_data Client specified data, associated with the chat. For example, chat position or local chat notification settings may be stored here. Persistent if message db is used chat id:int53 type:ChatType title:string photo:chatPhoto top_message:message order:int64 is_pinned:Bool unread_count:int last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int notification_settings:notificationSettings reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents list of chats @chat_ids List of chat identifiers chats chat_ids:vector = Chats; //@class KeyboardButtonType @description Describes type of the keyboard button //@description Simple button with a text, which should be sent when the button is pressed keyboardButtonTypeText = KeyboardButtonType; //@description A button which sends user's phone number when pressed, available only in private chats keyboardButtonTypeRequestPhoneNumber = KeyboardButtonType; //@description A button which sends user location when pressed, available only in private chats keyboardButtonTypeRequestLocation = KeyboardButtonType; //@description Represents one button of the bot keyboard @text Text of the button @type Type of the button keyboardButton text:string type:KeyboardButtonType = KeyboardButton; //@class InlineKeyboardButtonType @description Describes type of the inline keyboard button //@description A button which opens the specified URL @url URL to open inlineKeyboardButtonTypeUrl url:string = InlineKeyboardButtonType; //@description A button which sends to the bot special callback query @data Data to be sent to the bot through a callack query inlineKeyboardButtonTypeCallback data:bytes = InlineKeyboardButtonType; //@description A button with a game which sends to the bot special callback query, must be in the first column and row of the keyboard, can be attached only to a message with content of the type messageGame inlineKeyboardButtonTypeCallbackGame = InlineKeyboardButtonType; //@description A button which forces inline query to the bot to be substitued in the input field @query Inline query to be sent to the bot @in_current_chat True, if the inline query should be sent from the current chat inlineKeyboardButtonTypeSwitchInline query:string in_current_chat:Bool = InlineKeyboardButtonType; //@description A button for buying, must be in the first column and row of the keyboard, can be attached only to a message with content of the type messageInvoice inlineKeyboardButtonTypeBuy = InlineKeyboardButtonType; //@description Represents one button of the inline keyboard @text Text of the button @type Type of the button inlineKeyboardButton text:string type:InlineKeyboardButtonType = InlineKeyboardButton; //@class ReplyMarkup @description Contains description of custom keyboard and actions with it for fast reply to bots //@description Instruct clients to remove keyboard after receiving this message. This kind of keyboard can't be received. Instead UpdateChatReplyMarkup with message_id == 0 will be send //@personal Keyboard is removed only for mentioned users or replied to user replyMarkupRemoveKeyboard personal:Bool = ReplyMarkup; //@description Instruct clients to force reply to this message @personal Forced reply is used automatically only for mentioned users or replied to chat user, for incoming messages it is true if and only if forced reply needs to be automatically showed to the current user replyMarkupForceReply personal:Bool = ReplyMarkup; //@description Contains custom keyboard layout for fast reply to bot //@rows List of rows of bot keyboard buttons //@resize_keyboard Do clients need to resize keyboard vertically //@one_time Do clients need to hide keyboard after use //@personal Keyboard is showed automatically only for mentioned users or replied to user, for incoming messages it is true if and only if keyboard needs to be automatically showed to current user replyMarkupShowKeyboard rows:vector> resize_keyboard:Bool one_time:Bool personal:Bool = ReplyMarkup; //@description Contains inline keyboard layout //@rows List of rows of inline keyboard buttons replyMarkupInlineKeyboard rows:vector> = ReplyMarkup; //@class RichText @description Describes a text inside web page instant view //@description Plain text @text The text richTextPlain text:string = RichText; //@description Bold rich text @text The text richTextBold text:RichText = RichText; //@description Italicized rich text @text The text richTextItalic text:RichText = RichText; //@description Underlined rich text @text The text richTextUnderline text:RichText = RichText; //@description Striked through rich text @text The text richTextStrikethrough text:RichText = RichText; //@description Fixed width rich text @text The text richTextFixed text:RichText = RichText; //@description Rich text URL link @text The text @url The URL richTextUrl text:RichText url:string = RichText; //@description Rich text email link @text The text @email The email richTextEmail text:RichText email:string = RichText; //@description Concatenation of rich texts @texts The texts richTextConcatenation texts:vector = RichText; //@class PageBlock @description Describes a block of web page instant view //@description Title of a page @title The title pageBlockTitle title:RichText = PageBlock; //@description Subtitle of a page @subtitle The subtitle pageBlockSubtitle subtitle:RichText = PageBlock; //@description Author and publish date of a page @author The author @publish_date Date of article publish, unix time. 0 if unknown pageBlockAuthorDate author:RichText publish_date:int = PageBlock; //@description A header @header The header pageBlockHeader header:RichText = PageBlock; //@description A subheader @subheader The subheader pageBlockSubheader subheader:RichText = PageBlock; //@description A text paragraph @text Paragraph text pageBlockParagraph text:RichText = PageBlock; //@description Preformatted text paragraph @text Paragraph text @language Programming language for which the text should be formatted pageBlockPreformatted text:RichText language:string = PageBlock; //@description Footer of a page @footer The footer pageBlockFooter footer:RichText = PageBlock; //@description An empty block separating parts of a page pageBlockDivider = PageBlock; //@description Invisible anchor on a page which can be used in a URL to open a page from the specified anchor @name Name of the anchor pageBlockAnchor name:string = PageBlock; //@description List of texts @items Texts @is_ordered True, if items should be marked with numbers pageBlockList items:vector is_ordered:Bool = PageBlock; //@description Block quote @text Quote text @caption Quote caption pageBlockBlockQuote text:RichText caption:RichText = PageBlock; //@description Pull quote @text Quote text @caption Quote caption pageBlockPullQuote text:RichText caption:RichText = PageBlock; //@description An animation @animation The animation, nullable @caption Animation caption @need_autoplay True, if the animation should be autoplayed pageBlockAnimation animation:animation caption:RichText need_autoplay:Bool = PageBlock; //@description An audio @audio The audio, nullable @caption Audio caption pageBlockAudio audio:audio caption:RichText = PageBlock; //@description A photo @photo The photo, nullable @caption Photo caption pageBlockPhoto photo:photo caption:RichText = PageBlock; //@description A video @video The video, nullable @caption Video caption @need_autoplay True, if the video should be autoplayed @is_looped True, if the video is looped pageBlockVideo video:video caption:RichText need_autoplay:Bool is_looped:Bool = PageBlock; //@description Page cover @cover The cover pageBlockCover cover:PageBlock = PageBlock; //@description Embedded web page @url Web page URL, if available @html HTML-markup of the embedded page @poster_photo Poster photo if available, nullable @width Block width @height Block height @caption Block caption @is_full_width True, if the block should be full width @allow_scrolling True, if scrolling should be allowed pageBlockEmbedded url:string html:string poster_photo:photo width:int height:int caption:RichText is_full_width:Bool allow_scrolling:Bool = PageBlock; //@description Embedded post @url Web page URL @author Post author @author_photo Post author photo @date Post date, unix time. 0 if unknown @page_blocks Post content @caption Post caption pageBlockEmbeddedPost url:string author:string author_photo:photo date:int page_blocks:vector caption:RichText = PageBlock; //@description A collage @page_blocks Collage item contents @caption Block caption pageBlockCollage page_blocks:vector caption:RichText = PageBlock; //@description A slideshow @page_blocks Slideshow item contents @caption Block caption pageBlockSlideshow page_blocks:vector caption:RichText = PageBlock; //@description A link to a chat @title Chat title @photo Chat photo, nullable @username Chat username by which all other information about the chat should be resolved pageBlockChatLink title:string photo:chatPhoto username:string = PageBlock; //@description Describes instant view of a web page @page_blocks Content of the web page @is_full True, if instant view contains full page. Network request may be needed to get full web page instant view webPageInstantView page_blocks:vector is_full:Bool = WebPageInstantView; //@description Describes web page preview @url Original URL of link @display_url URL to display //@type Type of web page: article, photo, audio, video, document, profile, app or something other //@site_name Short name of the site (i.e. Google Docs or App Store) @title Title of the content @param_description Description of the content //@photo Image representing the content, nullable //@embed_url Url to show embedded preview //@embed_type MIME type of embedded preview, i.e. text/html or video/mp4 //@embed_width Width of embedded preview //@embed_height Height of embedded preview //@duration Duration of the content in seconds //@author Author of the content //@animation Preview as an Animation if available, nullable //@audio Preview as an Audio if available, nullable //@document Preview as a Document if available (currently only for small pdf files and zip archives), nullable //@sticker Preview as a Sticker for small .webp files if available, nullable //@video Preview as a Video if available, nullable //@video_note Preview as a VideoNote if available, nullable //@voice Preview as a Voice if available, nullable //@has_instant_view True if web page has instant view webPage url:string display_url:string type:string site_name:string title:string description:string photo:photo embed_url:string embed_type:string embed_width:int embed_height:int duration:int author:string animation:animation audio:audio document:document sticker:sticker video:video video_note:videoNote voice:voice has_instant_view:Bool = WebPage; //@description Goods price portion @label Portion label @amount Currency amount in minimal quantity of the currency labeledPrice label:string amount:int53 = LabeledPrice; //@description Goods invoice @currency ISO 4217 currency code @prices List of objects used to calculate total price @is_test True, if payment is test @need_name True, if user's name is needed for payment @need_phone_number True, if user's phone number is needed for payment @need_email True, if user's email is needed for payment //@need_shipping_address True, if user's shipping address is needed for payment @is_flexible True, if total price depends on shipping method invoice currency:string prices:vector is_test:Bool need_name:Bool need_phone_number:Bool need_email:Bool need_shipping_address:Bool is_flexible:Bool = Invoice; //@description Describes shipping address @country_code Two letter ISO 3166-1 alpha-2 country code @state State if applicable @city City @street_line1 First line for the address @street_line2 Second line for the address @post_code Address post code shippingAddress country_code:string state:string city:string street_line1:string street_line2:string post_code:string = ShippingAddress; //@description Order information @name User name @phone_number User's phone number @email User email @shipping_address User shipping address, nullable orderInfo name:string phone_number:string email:string shipping_address:shippingAddress = OrderInfo; //@description One shipping option @id Shipping option identifier @title Option title @prices List of objects used to calculate total shipping price shippingOption id:string title:string prices:vector = ShippingOption; //@description Information about saved card credentials @id Unique identifier of the saved credentials @title Title of the saved credentials savedCredentials id:string title:string = SavedCredentials; //@class InputCredentials @description Contains information about payment method chosen by user //@description User chooses previosly saved payment credentials. To use previously saved credentials user should have valid temporary password @saved_credentials_id Identifier of saved credentials inputCredentialsSaved saved_credentials_id:string = InputCredentials; //@description User enters new credentials on payment provider web site @data JSON-encoded data with credentials identifier from the payment provider @allow_save True, if credentials identifier can be saved server-side inputCredentialsNew data:string allow_save:Bool = InputCredentials; //@description Stripe payments provider @publishable_key Stripe API publishable key @need_country True, if user country should be entered @need_zip True, if user zip code should be entered @need_cardholder_name True, if cardholder name should be entered paymentsProviderStripe publishable_key:string need_country:Bool need_zip:Bool need_cardholder_name:Bool = PaymentsProviderStripe; //@description Information about invoice payment form @invoice Full information about the invoice @url Payment form URL @payments_provider Information about payment provider if available, to support it natively without opening the URL, nullable //@saved_order_info Saved server-side order information, nullable @saved_credentials Information about saved card credentials, nullable @can_save_credentials True, if the user can choose to save credentials @need_password True, if the user will be able to save credentials if he set up a password paymentForm invoice:invoice url:string payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm; //@description Contains temporary identifier of validated order information stored for an hour and available shipping options @order_info_id Temporary identifier of order information @shipping_options Available shipping options validatedOrderInfo order_info_id:string shipping_options:vector = ValidatedOrderInfo; //@description Contains result of a payment query @success True, if payment request was successful. If false, verification_url will be not empty @verification_url Url for additional payments credentials verification paymentResult success:Bool verification_url:string = PaymentResult; //@description Contains information about successful payment @date Payment date, unix time @payments_provider_user_id User identifier of payments provider bot @invoice Information about the invoice //@order_info Order information, nullable @shipping_option Chosen shipping option, nullable @credentials_title Title of the saved credentials paymentReceipt date:int payments_provider_user_id:int invoice:invoice order_info:orderInfo shipping_option:shippingOption credentials_title:string = PaymentReceipt; //@class MessageContent @description Content of a message //@description Text message @text Text of the message @entities Entities contained in the text @web_page Preview of a web page mentioned in the text, nullable messageText text:string entities:vector web_page:webPage = MessageContent; //@description Animation message @animation Message content @caption Animation caption messageAnimation animation:animation caption:string = MessageContent; //@description Audio message @audio Message content @caption Audio caption messageAudio audio:audio caption:string = MessageContent; //@description Document message @document Message content @caption Document caption messageDocument document:document caption:string = MessageContent; //@description Photo message @photo Message content @caption Photo caption messagePhoto photo:photo caption:string = MessageContent; //@description Photo message expired by TTL messageExpiredPhoto = MessageContent; //@description Sticker message @sticker Message content messageSticker sticker:sticker = MessageContent; //@description Video message @video Message content @caption Video caption messageVideo video:video caption:string = MessageContent; //@description Video message expired by TTL messageExpiredVideo = MessageContent; //@description Video note message @video_note Message content @is_viewed True, if the video note message was viewed messageVideoNote video_note:videoNote is_viewed:Bool = MessageContent; //@description Voice message @voice Message content @caption Voice caption @is_listened True, if the voice message was listened to messageVoice voice:voice caption:string is_listened:Bool = MessageContent; //@description Message with location @location Message content messageLocation location:location = MessageContent; //@description Message with information about venue @venue Message content messageVenue venue:venue = MessageContent; //@description User contact message @contact Message content messageContact contact:contact = MessageContent; //@description Message with a game @game The game messageGame game:game = MessageContent; //@description Message with an invoice from a bot @title Goods title @param_description Goods description @photo Goods photo, nullable @currency Currency for goods price @total_amount Goods total price in minimal quantity of the currency //@start_parameter Unique invoice bot start_parameter. To share an invoice use a URL https://t.me/{bot_username}?start={start_parameter} @is_test True, if invoice is test //@need_shipping_address True, if shipping address should be specified @receipt_message_id Identifier of message with receipt after the goods are paid messageInvoice title:string description:string photo:photo currency:string total_amount:int53 start_parameter:string is_test:Bool need_shipping_address:Bool receipt_message_id:int53 = MessageContent; //@description Message with an information about ended call @discard_reason Call discard reason @duration Call duration in seconds messageCall discard_reason:CallDiscardReason duration:int = MessageContent; //@description New group chat created @title Title of created group chat @member_user_ids User identifiers of members of created group chat messageGroupChatCreate title:string member_user_ids:vector = MessageContent; //@description New channel chat created @title Title of created channel chat messageChannelChatCreate title:string = MessageContent; //@description Chat title changed @title New chat title messageChatChangeTitle title:string = MessageContent; //@description Chat photo changed @photo New chat photo messageChatChangePhoto photo:photo = MessageContent; //@description Chat photo deleted messageChatDeletePhoto = MessageContent; //@description Chat members added @member_user_ids User identifiers of new chat members messageChatAddMembers member_user_ids:vector = MessageContent; //@description Chat member joined by invite link messageChatJoinByLink = MessageContent; //@description Chat member deleted @user_id User identifier of deleted chat memeber messageChatDeleteMember user_id:int = MessageContent; //@description Group chat is migrated to supergroup channel and deactivated @channel_id Identifier of the channel it is migrated to messageChatMigrateTo channel_id:int = MessageContent; //@description Supergroup channel is created from group chat @title Title of created channel chat @group_id Identifier of the group it is migrated from messageChatMigrateFrom title:string group_id:int = MessageContent; //@description Some message was pinned @message_id Identifier of the pinned message, can be identifier of the deleted message messagePinMessage message_id:int53 = MessageContent; //@description Screenshot of messages in the chat was taken messageScreenshotTaken = MessageContent; //@description Messages ttl setting in secret chat has changed @ttl New ttl messageChatSetTtl ttl:int = MessageContent; //@description New high score was achieved in a game @game_message_id Identifier of the message with the game, can be identifier of the deleted message @game_id Identifier of the game, may be different from the games presented in the message with the game @score New score messageGameScore game_message_id:int53 game_id:int64 score:int = MessageContent; //@description Payment completed @currency Currency for goods price @total_amount Goods total price in minimal quantity of the currency messagePaymentSuccessful currency:string total_amount:int53 = MessageContent; //@description Bots only. Payment completed @currency Currency for goods price @total_amount Goods total price in minimal quantity of the currency @invoice_payload Invoice payload @shipping_option_id Identifier of a choosed by user shipping option, may be empty if not applicable @order_info Information about the order, nullable //@telegram_payment_charge_id Telegram payment identifier @provider_payment_charge_id Provider payment identifier messagePaymentSuccessfulBot currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo telegram_payment_charge_id:string provider_payment_charge_id:string = MessageContent; //@description Contact has registered messageContactRegistered = MessageContent; //@description Unsupported message content messageUnsupported = MessageContent; //@class TextEntityType @description Represent part of the text which needs to be formatted in some unusual way //@description Mention of the user by his username textEntityTypeMention = TextEntityType; //@description Hashtag beginning with # textEntityTypeHashtag = TextEntityType; //@description Bot command beginning with /. It shouldn't be highlighted if there is no bots in the chat textEntityTypeBotCommand = TextEntityType; //@description Url beginning with http textEntityTypeUrl = TextEntityType; //@description Email textEntityTypeEmail = TextEntityType; //@description Bold text textEntityTypeBold = TextEntityType; //@description Italic text textEntityTypeItalic = TextEntityType; //@description Text needs to be formatted as inside of code HTML tag textEntityTypeCode = TextEntityType; //@description Text needs to be formatted as inside of pre HTML tag textEntityTypePre = TextEntityType; //@description Text needs to be formatted as inside of pre and code HTML tags @language Language of code as defined by sender textEntityTypePreCode language:string = TextEntityType; //@description Text description showed instead of the url @url Url to be opened after link will be clicked textEntityTypeTextUrl url:string = TextEntityType; //@description Mention of the user by some text @user_id Identifier of the mentioned user textEntityTypeMentionName user_id:int = TextEntityType; //@class TextParseMode @description Describes a way text should be parsed for MessageEntities, by default text is treated as is //@description Text should be parsed in markdown-style way textParseModeMarkdown = TextParseMode; //@description Text should be parsed in the HTML-style way textParseModeHTML = TextParseMode; //@description Contains a list ot text entities @entities The entities textEntities entities:vector = TextEntities; //@description Thumb to send along with a file, should be in jpeg format or webp format for stickers and less than 200KB in size @thumb Thumb file to send, sending thumbs by file_id is currently not supported //@width Thumb width, usually shouldn't excceed 90. Use 0 if unknown @height Thumb height, usually shouldn't excceed 90. Use 0 if unknown inputThumb thumb:InputFile width:int height:int = InputThumb; //@class InputMessageContent @description Content of a message to send //@description Text message @text Text to send @disable_web_page_preview Pass true to disable rich preview for link in the message text @clear_draft Pass true if chat draft message should be deleted //@entities Bold, Italic, Code, Pre, PreCode and TextUrl entities contained in the text. Non-bot users can't use TextUrl entities. Can't be used with non-null parse_mode @parse_mode Text parse mode, nullable. Can't be used along with enitities inputMessageText text:string disable_web_page_preview:Bool clear_draft:Bool entities:vector parse_mode:TextParseMode = InputMessageContent; //@description Animation message @animation Animation file to send @thumb Animation thumb, if available @duration Duration of the animation in seconds @width Width of the animation, may be replaced by the server @height Height of the animation, may be replaced by the server @caption Animation caption, 0-200 characters inputMessageAnimation animation:InputFile thumb:inputThumb duration:int width:int height:int caption:string = InputMessageContent; //@description Audio message @audio Audio file to send @album_cover_thumb Thumb of the album's cover, if available @duration Duration of the audio in seconds, may be replaced by the server @title Title of the audio, 0-64 characters, may be replaced by the server //@performer Performer of the audio, 0-64 characters, may be replaced by the server @caption Audio caption, 0-200 characters inputMessageAudio audio:InputFile album_cover_thumb:inputThumb duration:int title:string performer:string caption:string = InputMessageContent; //@description Document message @document Document to send @thumb Document thumb, if available @caption Document caption, 0-200 characters inputMessageDocument document:InputFile thumb:inputThumb caption:string = InputMessageContent; //@description Photo message @photo Photo to send @thumb Photo thumb to send, is sent to the other party in secret chats only @added_sticker_file_ids File identifiers of stickers added onto the photo @width Photo width @height Photo height @caption Photo caption, 0-200 characters //@ttl Photo TTL in seconds, 0-60. Non-zero TTL can be only specified in private chats inputMessagePhoto photo:InputFile thumb:inputThumb added_sticker_file_ids:vector width:int height:int caption:string ttl:int = InputMessageContent; //@description Sticker message @sticker Sticker to send @thumb Sticker thumb, if available @width Sticker width @height Sticker height inputMessageSticker sticker:InputFile thumb:inputThumb width:int height:int = InputMessageContent; //@description Video message @video Video to send @thumb Video thumb, if available @added_sticker_file_ids File identifiers of stickers added onto the video @duration Duration of the video in seconds @width Video width @height Video height @caption Video caption, 0-200 characters //@ttl Video TTL in seconds, 0-60. Non-zero TTL can be only specified in private chats inputMessageVideo video:InputFile thumb:inputThumb added_sticker_file_ids:vector duration:int width:int height:int caption:string ttl:int = InputMessageContent; //@description Video note message @video_note Video note to send @thumb Video thumb, if available @duration Duration of the video in seconds @length Video width and height, should be positive and not greater than 640 inputMessageVideoNote video_note:InputFile thumb:inputThumb duration:int length:int = InputMessageContent; //@description Voice message @voice Voice file to send @duration Duration of the voice in seconds @waveform Waveform representation of the voice in 5-bit format @caption Voice caption, 0-200 characters inputMessageVoice voice:InputFile duration:int waveform:bytes caption:string = InputMessageContent; //@description Message with location @location Location to send inputMessageLocation location:location = InputMessageContent; //@description Message with information about venue @venue Venue to send inputMessageVenue venue:venue = InputMessageContent; //@description User contact message @contact Contact to send inputMessageContact contact:contact = InputMessageContent; //@description Message with a game, can't be used in broadcast channels and secret chats @bot_user_id User identifier of a bot owned the game @game_short_name Game short name inputMessageGame bot_user_id:int game_short_name:string = InputMessageContent; //@description Message with an invoice, can be used only by bots and in private chats only @invoice The invoice @title Product title, 1-32 characters @param_description Product description, 0-255 characters @photo_url Goods photo URL, optional @photo_size Goods photo size @photo_width Goods photo width @photo_height Goods photo height //@payload Invoice payload @provider_token Payments provider token @start_parameter Unique invoice bot start_parameter for generation of this invoice inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int photo_width:int photo_height:int payload:bytes provider_token:string start_parameter:string = InputMessageContent; //@description Forwarded message @from_chat_id Chat identifier of the message to forward @message_id Identifier of the message to forward @in_game_share Pass true to share a game message within a launched game, for Game messages only inputMessageForwarded from_chat_id:int53 message_id:int53 in_game_share:Bool = InputMessageContent; //@class SearchMessagesFilter @description Represents filter for content of searched messages //@description Return all found messages searchMessagesFilterEmpty = SearchMessagesFilter; //@description Return only animation messages searchMessagesFilterAnimation = SearchMessagesFilter; //@description Return only audio messages searchMessagesFilterAudio = SearchMessagesFilter; //@description Return only document messages searchMessagesFilterDocument = SearchMessagesFilter; //@description Return only photo messages searchMessagesFilterPhoto = SearchMessagesFilter; //@description Return only video messages searchMessagesFilterVideo = SearchMessagesFilter; //@description Return only voice messages searchMessagesFilterVoice = SearchMessagesFilter; //@description Return only photo and video messages searchMessagesFilterPhotoAndVideo = SearchMessagesFilter; //@description Return only messages containing url searchMessagesFilterUrl = SearchMessagesFilter; //@description Return only messages containing chat photos searchMessagesFilterChatPhoto = SearchMessagesFilter; //@description Return only call messages searchMessagesFilterCall = SearchMessagesFilter; //@description Return only incoming call messages with missed/declined discard reason searchMessagesFilterMissedCall = SearchMessagesFilter; //@description Return only video note messages searchMessagesFilterVideoNote = SearchMessagesFilter; //@description Return only voice and video note messages searchMessagesFilterVoiceAndVideoNote = SearchMessagesFilter; //@description Return only messages with mentions of current logged in user or which are replies to his messages searchMessagesFilterMention = SearchMessagesFilter; //@description Return only messages with unread mentions of current logged in user or which are replies to his messages. When this filter is used result can't be additionally filtered by a query or a sender user searchMessagesFilterUnreadMention = SearchMessagesFilter; //@class ChatAction @description Describes different types of activity in a chat //@description User typing a message chatActionTyping = ChatAction; //@description User records a video chatActionRecordingVideo = ChatAction; //@description User uploads a video @progress Upload progress in percents chatActionUploadingVideo progress:int = ChatAction; //@description User records voice message chatActionRecordingVoice = ChatAction; //@description User uploads voice message @progress Upload progress in percents chatActionUploadingVoice progress:int = ChatAction; //@description User uploads a photo @progress Upload progress in percents chatActionUploadingPhoto progress:int = ChatAction; //@description User uploads a document @progress Upload progress in percents chatActionUploadingDocument progress:int = ChatAction; //@description User chooses location or venue to send chatActionChoosingLocation = ChatAction; //@description User chooses contact to send chatActionChoosingContact = ChatAction; //@description User starts to play a game chatActionStartPlayingGame = ChatAction; //@description User records video note chatActionRecordingVideoNote = ChatAction; //@description User uploads a video note @progress Upload progress in percents chatActionUploadingVideoNote progress:int = ChatAction; //@description User cancels previous action chatActionCancel = ChatAction; //@class UserStatus @description Describes last time user was online //@description User status was newer changed userStatusEmpty = UserStatus; //@description User is online @expires Unix time when user's online status will expire userStatusOnline expires:int = UserStatus; //@description User is offline @was_online Unix time user was online last time userStatusOffline was_online:int = UserStatus; //@description User was online recently userStatusRecently = UserStatus; //@description User is offline, but was online last week userStatusLastWeek = UserStatus; //@description User is offline, but was online last month userStatusLastMonth = UserStatus; //@description Represents list of stickers @stickers Stickers stickers stickers:vector = Stickers; //@description Represents list of all emojis corresponding to a sticker in a sticker set. The list is only for informational purposes because sticker is always sent with a fixed emoji from the corresponding Sticker object @emojis List of emojis stickerEmojis emojis:vector = StickerEmojis; //@description Represents sticker set @id Sticker set identifier @title Title of the sticker set @name Name of the sticker set @is_installed True if sticker set is installed by logged in user //@is_archived True if sticker set is archived. A sticker set can't be installed and archived simultaneously @is_official True if sticker set is official @is_masks True if stickers in the set are masks //@is_viewed True for viewed trending sticker set @stickers List of stickers in this set @emojis Lists of emojis corresponding to the stickers in the same order stickerSet id:int64 title:string name:string is_installed:Bool is_archived:Bool is_official:Bool is_masks:Bool is_viewed:Bool stickers:vector emojis:vector = StickerSet; //@description Represents short information about sticker set @id Sticker set identifier @title Title of the sticker set @name Name of the sticker set @is_installed True if sticker set is installed by logged in user //@is_archived True if sticker set is archived. A sticker set can't be installed and archived simultaneously @is_official True if sticker set is official @is_masks True if stickers in the set are masks //@is_viewed True for viewed trending sticker set @size Total number of stickers in the set @covers Up to 5 first stickers from the set depending on the context. If client needs more stickers it should request full sticker set stickerSetInfo id:int64 title:string name:string is_installed:Bool is_archived:Bool is_official:Bool is_masks:Bool is_viewed:Bool size:int covers:vector = StickerSetInfo; //@description Represents list of sticker sets @total_count Approximate total count of found sticker sets @sets List of sticker sets stickerSets total_count:int sets:vector = StickerSets; //@class CallDiscardReason @description Describes reason a call was discarded //@description Call wasn't discarded or the reason is unknown callDiscardReasonEmpty = CallDiscardReason; //@description Call has ended before conversation begins. It was cancelled by the caller or was missed by the callee callDiscardReasonMissed = CallDiscardReason; //@description Call has ended before conversation begins. It was declined by the callee callDiscardReasonDeclined = CallDiscardReason; //@description Call has ended during conversation because users was disconnected callDiscardReasonDisconnected = CallDiscardReason; //@description Call was hung up by the caller or by the callee callDiscardReasonHungUp = CallDiscardReason; //@description Specifies supported call protocols @udp_p2p True, if UDP peer to peer connections are supported @udp_reflector True, if connection through UDP reflectors are supported @min_layer Minimum supported layer, use 65 @max_layer Maximum supported layer, use 65 callProtocol udp_p2p:Bool udp_reflector:Bool min_layer:int max_layer:int = CallProtocol; //@description Describes address of UDP reflectors @id Reflector identifier @ip IPv4 reflector address @ipv6 IPv6 reflector address @port Reflector port @peer_tag Connection peer tag callConnection id:int64 ip:string ipv6:string port:int peer_tag:bytes = CallConnection; //@description Contains call identifier @id Call identifier callId id:int = CallId; //@class CallState @description Describes current call state //@description Call is pending for acception by a user @is_created True, if the call is already created by the server @is_received True, if the call is already received by the other party callStatePending is_created:Bool is_received:Bool = CallState; //@description Call is answered and encryption keys are exchanged callStateExchangingKeys = CallState; //@description Call is ready to use @protocol Call protocols supported by the peer @connections Available UDP reflectors @config JSON-encoded call config @encryption_key Call encryption key @emojis Encryption key emojis fingerprint callStateReady protocol:callProtocol connections:vector config:string encryption_key:bytes emojis:vector = CallState; //@description Call is hanging up after discardCall is called callStateHangingUp = CallState; //@description Call has ended successfully @reason A reason, why call has ended @need_rating If true, call rating should be sent to the server @need_debug If true, call debug should be sent to the server callStateDiscarded reason:CallDiscardReason need_rating:Bool need_debug:Bool = CallState; //@description Call has ended with an error @error The error. Error with the code 4005000 returned if an outgoing call is missed because of expired timeout callStateError error:error = CallState; //@description Describes a call @id Call identifier, not persistent @user_id Peer user identifier @is_outgoing True, if the call is outgoing @state Call state call id:int user_id:int is_outgoing:Bool state:CallState = Call; //@description Represents list of animations @animations Animations animations animations:vector = Animations; //@description Represent result for ImportContacts request @user_ids User identifiers of imported contacts in the same order as they was specified in the request. 0 if contact is not yet registered //@importer_count Number of users which imported corresponding contact. 0 for already registered users or if unavailable importedContacts user_ids:vector importer_count:vector = ImportedContacts; //@class InputInlineQueryResult @description Represents one result of the inline query received from the bot //@description Represents link to an animated gif @id Unique identifier of this result @title Title of the result @thumb_url Url of the static result thumb (jpeg or gif), if exists //@gif_url Url of the gif-file (file size must not exceed 1MB) @gif_duration Duration of the gif in seconds @gif_width Width of the gif @gif_height Height of the gif //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageAnimation or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultAnimatedGif id:string title:string thumb_url:string gif_url:string gif_duration:int gif_width:int gif_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to an animated (i.e. without sound) H.264/MPEG-4 AVC video @id Unique identifier of this result @title Title of the result @thumb_url Url of the static result thumb (jpeg or gif), if exists //@mpeg4_url Url of the mp4-file (file size must not exceed 1MB) @mpeg4_duration Duration of the video in seconds @mpeg4_width Width of the video @mpeg4_height Height of the video //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageAnimation or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultAnimatedMpeg4 id:string title:string thumb_url:string mpeg4_url:string mpeg4_duration:int mpeg4_width:int mpeg4_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to an article or web page @id Unique identifier of this result @url Url of the result, if exists @hide_url True, if url must be not shown @title Title of the result //@param_description Short description of the result @thumb_url Url of the result thumb, if exists @thumb_width Thumb width, if known @thumb_height Thumb height, if known //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultArticle id:string url:string hide_url:Bool title:string description:string thumb_url:string thumb_width:int thumb_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a mp3 audio file @id Unique identifier of this result @title Title of the audio @performer Performer of the audio //@audio_url Url of the audio file @audio_duration Audio duration in seconds //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageAudio or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultAudio id:string title:string performer:string audio_url:string audio_duration:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents user contact @id Unique identifier of this result @contact User contact @thumb_url Url of the result thumb, if exists @thumb_width Thumb width, if known @thumb_height Thumb height, if known //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultContact id:string contact:contact thumb_url:string thumb_width:int thumb_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a file @id Unique identifier of this result @title Title of the result @param_description Short description of the result, if known @document_url Url of the file @mime_type MIME type of the file content, only “application/pdf” and “application/zip” are allowed now //@thumb_url Url of the file thumb, if exists @thumb_width Width of the thumb @thumb_height Height of the thumb //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageDocument or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultDocument id:string title:string description:string document_url:string mime_type:string thumb_url:string thumb_width:int thumb_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents a game @id Unique identifier of this result @game_short_name Game short name @reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null inputInlineQueryResultGame id:string game_short_name:string reply_markup:ReplyMarkup = InputInlineQueryResult; //@description Represents a point on the map @id Unique identifier of this result @location Result @title Title of the result @thumb_url Url of the result thumb, if exists @thumb_width Thumb width, if known @thumb_height Thumb height, if known //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultLocation id:string location:location title:string thumb_url:string thumb_width:int thumb_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a jpeg photo @id Unique identifier of this result @title Title of the result, if known @param_description Short description of the result, if known @thumb_url Url of the photo thumb, if exists //@photo_url Url of the jpeg photo (photo must not exceed 5MB) @photo_width Width of the photo @photo_height Height of the photo //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessagePhoto or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultPhoto id:string title:string description:string thumb_url:string photo_url:string photo_width:int photo_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a webp sticker @id Unique identifier of this result @thumb_url Url of the sticker thumb, if exists //@sticker_url Url of the webp sticker (file with a sticker must not exceed 5MB) @sticker_width Width of the sticker @sticker_height Height of the sticker //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageSticker or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultSticker id:string thumb_url:string sticker_url:string sticker_width:int sticker_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents information about a venue @id Unique identifier of this result @venue Result @thumb_url Url of the result thumb, if exists @thumb_width Thumb width, if known @thumb_height Thumb height, if known //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultVenue id:string venue:venue thumb_url:string thumb_width:int thumb_height:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a page containing an embedded video player or a video file @id Unique identifier of this result @title Title of the result @param_description Short description of the result, if known //@thumb_url Url of the video thumb (jpeg), if exists @video_url Url of the embedded video player or video file @mime_type MIME type of the content of video url, only "text/html" or "video/mp4" are allowed now //@video_width Video width @video_height Video height @video_duration Video duration in seconds //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageVideo or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultVideo id:string title:string description:string thumb_url:string video_url:string mime_type:string video_width:int video_height:int video_duration:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@description Represents link to a opus encoded audio file in ogg container @id Unique identifier of this result @title Title of the voice file //@voice_url Url of the voice file @voice_duration Voice duration in seconds //@reply_markup Message reply markup, should be of type replyMarkupInlineKeyboard or null //@input_message_content Content of the message to be sent, should be of type inputMessageText or inputMessageVoice or InputMessageLocation or InputMessageVenue or InputMessageContact inputInlineQueryResultVoice id:string title:string voice_url:string voice_duration:int reply_markup:ReplyMarkup input_message_content:InputMessageContent = InputInlineQueryResult; //@class InlineQueryResult @description Represents one result of the inline query //@description Represents link to an article or web page @id Unique identifier of this result @url Url of the result, if exists @hide_url True, if url must be not shown @title Title of the result //@param_description Short description of the result @thumb Result thumb, nullable inlineQueryResultArticle id:string url:string hide_url:Bool title:string description:string thumb:photoSize = InlineQueryResult; //@description Represents user contact @id Unique identifier of this result @contact User contact @thumb Result thumb, nullable inlineQueryResultContact id:string contact:contact thumb:photoSize = InlineQueryResult; //@description Represents a point on the map @id Unique identifier of this result @location The result @title Title of the result @thumb Result thumb, nullable inlineQueryResultLocation id:string location:location title:string thumb:photoSize = InlineQueryResult; //@description Represents information about a venue @id Unique identifier of this result @venue The result @thumb Result thumb, nullable inlineQueryResultVenue id:string venue:venue thumb:photoSize = InlineQueryResult; //@description Represents information about a game @id Unique identifier of this result @game The result inlineQueryResultGame id:string game:game = InlineQueryResult; //@description Represents an animation cached on the telegram server @id Unique identifier of this result @animation The animation @title Animation title inlineQueryResultAnimation id:string animation:animation title:string = InlineQueryResult; //@description Represents an audio cached on the telegram server @id Unique identifier of this result @audio The audio inlineQueryResultAudio id:string audio:audio = InlineQueryResult; //@description Represents a document cached on the telegram server @id Unique identifier of this result @document The document @title Document title @param_description Document description inlineQueryResultDocument id:string document:document title:string description:string = InlineQueryResult; //@description Represents a photo cached on the telegram server @id Unique identifier of this result @photo The photo @title Title of the result, if known @param_description Short description of the result, if known inlineQueryResultPhoto id:string photo:photo title:string description:string = InlineQueryResult; //@description Represents a sticker cached on the telegram server @id Unique identifier of this result @sticker The sticker inlineQueryResultSticker id:string sticker:sticker = InlineQueryResult; //@description Represents a video cached on the telegram server @id Unique identifier of this result @video The video @title Title of the video @param_description Description of the video inlineQueryResultVideo id:string video:video title:string description:string = InlineQueryResult; //@description Represents a voice cached on the telegram server @id Unique identifier of this result @voice The voice @title Title of the voice file inlineQueryResultVoice id:string voice:voice title:string = InlineQueryResult; //@description Represents results of the inline query. Use sendInlineQueryResultMessage to send the result of the query @inline_query_id Unique identifier of the inline query @next_offset Offset for the next request. If it is empty, there is no more results @results Results of the query //@switch_pm_text If non-empty, this text should be shown on the button, which opens private chat with the bot and sends bot start message with parameter switch_pm_parameter @switch_pm_parameter Parameter for the bot start message inlineQueryResults inline_query_id:int64 next_offset:string results:vector switch_pm_text:string switch_pm_parameter:string = InlineQueryResults; //@class CallbackQueryPayload @description Represents payload of a callback query //@description Payload from a general callback button @data Data that was attached to the callback button callbackQueryPayloadData data:bytes = CallbackQueryPayload; //@description Payload from a game callback button @game_short_name Short name of the game that was attached to the callback button callbackQueryPayloadGame game_short_name:string = CallbackQueryPayload; //@description Contains answer of a bot to a callback query @text Text of the answer @show_alert If true, an alert should be shown to the user instead of a toast @url URL to be open callbackQueryAnswer text:string show_alert:Bool url:string = CallbackQueryAnswer; //@description Contains result of a custom request @result JSON-serialized result customRequestResult result:string = CustomRequestResult; //@description Contains one row of the game high scores table @position Position in the high score table @user_id User identifier @score User score gameHighScore position:int user_id:int score:int = GameHighScore; //@description Contains list of game high scores @scores List of game high scores gameHighScores scores:vector = GameHighScores; //@class ChatEventAction @description Represents a chat event //@description A message was edited @old_message Message before edit @new_message Message after edit chatEventMessageEdited old_message:message new_message:message = ChatEventAction; //@description A message was deleted @message Deleted message chatEventMessageDeleted message:message = ChatEventAction; //@description A message was pinned @message Pinned message chatEventMessagePinned message:message = ChatEventAction; //@description A message was unpinned chatEventMessageUnpinned = ChatEventAction; //@description New chat member joined chatEventMemberJoined = ChatEventAction; //@description A chat member left chatEventMemberLeft = ChatEventAction; //@description New chat member invited @user_id New chat member user identifier @status New chat member status chatEventMemberInvited user_id:int status:ChatMemberStatus = ChatEventAction; //@description A chat member promoted to/demoted from administrators @user_id Chat member user identifier @old_status Old chat member status @new_status New chat member status chatEventMemberPromoted user_id:int old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; //@description A chat member restricted/unrestircted or banned/unbanned @user_id Chat member user identifier @old_status Old chat member status @new_status New chat member status chatEventMemberRestricted user_id:int old_status:ChatMemberStatus new_status:ChatMemberStatus = ChatEventAction; //@description Chat title was changed @old_title Old title value @new_title New title value chatEventTitleChanged old_title:string new_title:string = ChatEventAction; //@description Chat description was changed @old_description Old description value @new_description New description value chatEventDescriptionChanged old_description:string new_description:string = ChatEventAction; //@description Chat username was changed @old_username Old username value @new_username New username value chatEventUsernameChanged old_username:string new_username:string = ChatEventAction; //@description Chat photo was changed @old_photo Old photo value, nullable @new_photo New photo value, nullable chatEventPhotoChanged old_photo:chatPhoto new_photo:chatPhoto = ChatEventAction; //@description Supergroup channel chat anyone_can_invite setting was toggled @anyone_can_invite New value of anyone_can_invite chatEventInvitesToggled anyone_can_invite:Bool = ChatEventAction; //@description Broadcast channel chat sign_messages setting was toggled @sign_messages New value of sign_messages chatEventSignMessagesToggled sign_messages:Bool = ChatEventAction; //@description Supergroup sticker set was changed @old_sticker_set_id Old identifier of chat sticker set, 0 if none @new_sticker_set_id New identifier of chat sticker set, 0 if none chatEventStickerSetChanged old_sticker_set_id:int64 new_sticker_set_id:int64 = ChatEventAction; //@description Represents a chat event @id Chat event identifier @date Date of the event, unix time @user_id Identifier of a user who made the action @action Action done by the user chatEvent id:int64 date:int user_id:int action:ChatEventAction = ChatEvent; //@description Contains list of chat events @events The events chatEvents events:vector = ChatEvents; //@description Represents a set of filters used to obtain a chat event log //@message_edits True, if message edits should be returned //@message_deletions True, if message deletions should be returned //@message_pins True, if message pins should be returned //@member_joins True, if chat member joins should be returned //@member_leaves True, if chat member leaves should be returned //@member_invites True, if chat member invites should be returned //@member_promotions True, if chat member promotions/demotions should be returned //@member_restrictions True, if chat member restrictions/unrestrictions including bans/unbans should be returned //@info_changes True, if changes of chat information should be returned //@setting_changes True, if changes of chat settings should be returned chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool = ChatEventLogFilters; //@class DeviceToken @description Represents a token for push notifications //@description Token for APNS @token The token, may be empty to unregister device deviceTokenApns token:string = DeviceToken; //@description Token for GCM @token The token, may be empty to unregister device deviceTokenGcm token:string = DeviceToken; //@description Token for MPNS @token The token, may be empty to unregister device deviceTokenMpns token:string = DeviceToken; //@description Token for simple push @token The token, may be empty to unregister device deviceTokenSimplePush token:string = DeviceToken; //@description Token for Ubuntu Push Service @token The token, may be empty to unregister device deviceTokenUbuntuPhone token:string = DeviceToken; //@description Token for Blackberry Push Service @token The token, may be empty to unregister device deviceTokenBlackberry token:string = DeviceToken; //@description Contains information about one wallpaper @id Unique persistent wallpaper identifier @sizes Available variants of wallpaper of different sizes. These photos can be only downloaded and can't be sent in a message @color Main color of wallpaper in RGB24, should be treated as background color if no photos are specified wallpaper id:int sizes:vector color:int = Wallpaper; //@description Contains list of wallpapers @wallpapers List of wallpapers wallpapers wallpapers:vector = Wallpapers; //@description Contatins list of hashtags @hashtags List of hashtags hashtags hashtags:vector = Hashtags; //@class OptionValue @description Represents value of an option //@description Boolean option @value Value of an option optionValueBoolean value:Bool = OptionValue; //@description Unknown option or option having default value optionValueEmpty = OptionValue; //@description Integer option @value Value of an option optionValueInteger value:int = OptionValue; //@description String option @value Value of an option optionValueString value:string = OptionValue; //@class PrivacyRule @description Represents one rule for managing privacy settings //@description Rule to allow all users privacyRuleAllowAll = PrivacyRule; //@description Rule to allow all user contacts privacyRuleAllowContacts = PrivacyRule; //@description Rule to allow specified users @user_ids User identifiers privacyRuleAllowUsers user_ids:vector = PrivacyRule; //@description Rule to disallow all users privacyRuleDisallowAll = PrivacyRule; //@description Rule to disallow all user contacts privacyRuleDisallowContacts = PrivacyRule; //@description Rule to disallow all specified users @user_ids User identifiers privacyRuleDisallowUsers user_ids:vector = PrivacyRule; //@description List of privacy rules. Rules are matched in the specified order. First matched rule defines privacy setting for a given user. If no rule matches action is not allowed @rules List of rules privacyRules rules:vector = PrivacyRules; //@class PrivacyKey @description Describes available privacy settings //@description Privacy key for managing visibility of the user status privacyKeyUserStatus = PrivacyKey; //@description Privacy key for managing ability of invitation of the user to chats privacyKeyChatInvite = PrivacyKey; //@description Privacy key for managing ability to call the user privacyKeyCall = PrivacyKey; //@description Contains information about period of inactivity, after which the account of currently logged in user will be automatically deleted @days Number of days of inactivity before account deletion, should be from 30 and up to 366 accountTtl days:int = AccountTtl; //@description Contains information about one session in some application used by the user @id Session identifier @is_current True, if it is current session @app_id Application identifier, provided by the application @app_name Name of the application, provided by the application //@app_version Version of the application, provided by the application @is_official_app True, if the application is an official application or uses the app_id of some official application @device_model Model of a device application is runned on, provided by the application @platform Operating system application is runned on, provided by the application //@system_version Version of operating system application is runned on, provided by the application @log_in_date Date the user has logged in, unix time @last_active_date Date the session was used last time, unix time @ip An ip address from which session was created in a human-readable format //@country Two-letter country code from which session was created based on the ip @region Region code from which session was created based on the ip session id:int64 is_current:Bool app_id:int app_name:string app_version:string is_official_app:Bool device_model:string platform:string system_version:string log_in_date:int last_active_date:int ip:string country:string region:string = Session; //@description Contains list of sessions @sessions List of sessions sessions sessions:vector = Sessions; //@description Contains information about chat report spam state @can_report_spam If true, prompt with "Report spam" action should be shown to the user chatReportSpamState can_report_spam:Bool = ChatReportSpamState; //@class ChatReportReason @description Describes a reason, why a chat is reported //@description The chat contains spam messages chatReportReasonSpam = ChatReportReason; //@description The chat contains violent messages chatReportReasonViolence = ChatReportReason; //@description The chat contains pornography messages chatReportReasonPornography = ChatReportReason; //@description Other reason provided by the user @text Report text chatReportReasonOther text:string = ChatReportReason; //@description Contains public HTTPS link to a message in a public channel @url The link publicMessageLink url:string = PublicMessageLink; //@class FileType @description Represents type of a file //@description Data is not a file fileTypeNone = FileType; //@description File is an animation fileTypeAnimation = FileType; //@description File is an audio fileTypeAudio = FileType; //@description File is a document fileTypeDocument = FileType; //@description File is a photo fileTypePhoto = FileType; //@description File is a profile photo fileTypeProfilePhoto = FileType; //@description File sent to a secret chat fileTypeSecret = FileType; //@description File is a sticker fileTypeSticker = FileType; //@description File is a thumbnail of another file fileTypeThumb = FileType; //@description File type is yet unknown fileTypeUnknown = FileType; //@description File is a video fileTypeVideo = FileType; //@description File is a video note fileTypeVideoNote = FileType; //@description File is a voice audio fileTypeVoice = FileType; //@description File is a wallpaper fileTypeWallpaper = FileType; //@description File is a thumbnail of a file from a secret chat fileTypeSecretThumb = FileType; //@description Contains storage usage statistics for the specific file type @file_type The file type @size Total size of files @count Total number of files storageStatisticsByFileType file_type:FileType size:int53 count:int = StorageStatisticsByFileType; //@description Contains storage usage statistics for the specific chat @chat_id Chat identifier, 0 if none @size Total size of files @count Total number of files @by_file_type Statistics splitted by file types storageStatisticsByChat chat_id:int53 size:int53 count:int by_file_type:vector = StorageStatisticsByChat; //@description Contains exact storage usage statistics splitted by chats and file types @size Total size of files @count Total number of files @by_chat Statistics splitted by chats storageStatistics size:int53 count:int by_chat:vector = StorageStatistics; //@description Contains approximate storage usage statistics, not containing files of Unknown type @files_size Approximate total size of files @files_count Approximate number of files @database_size Size of database storageStatisticsFast files_size:int53 files_count:int database_size:int53 = StorageStatisticsFast; //@class NetworkType @description Represents type of a network //@description Network is not available networkTypeNone = NetworkType; //@description Mobile network networkTypeMobile = NetworkType; //@description Mobile roaming network networkTypeMobileRoaming = NetworkType; //@description Wi-Fi network networkTypeWiFi = NetworkType; //@description Other network type, for example, Ethernet network networkTypeOther = NetworkType; //@class NetworkStatisticsEntry @description Contains statistics about network usage //@description Contains information about total received and sent files data @file_type Type of a file the data is part of @network_type Type of a network the data was sent through. Call setNetworkType to maintain actual network type //@sent_bytes Total number of sent bytes @received_bytes Total number of received bytes networkStatisticsEntryFile file_type:FileType network_type:NetworkType sent_bytes:int53 received_bytes:int53 = NetworkStatisticsEntry; //@description Contains information about total received and sent calls data @network_type Type of a network the data was sent through. Call setNetworkType to maintain actual network type //@sent_bytes Total number of sent bytes @received_bytes Total number of received bytes @duration Total calls duration in seconds networkStatisticsEntryCall network_type:NetworkType sent_bytes:int53 received_bytes:int53 duration:double = NetworkStatisticsEntry; //@description Full list of available network statistics entries @since_date Date since which statistics are collected, unix time @entries Network statistics entries networkStatistics since_date:int entries:vector = NetworkStatistics; //@class ConnectionState @description Describes current state of the connection to Telegram servers //@description Waiting for network to be available. Use SetNetworkType to change available network type connectionStateWaitingForNetwork = ConnectionState; //@description Establishing connection to set up proxy server connectionStateConnectingToProxy = ConnectionState; //@description Establishing connection to Telegram servers connectionStateConnecting = ConnectionState; //@description Downloading date received, while client was offline connectionStateUpdating = ConnectionState; //@description There is a working connection to the Telegram servers connectionStateReady = ConnectionState; //@class TopChatCategory @description Represents categories of chats for which list of frequently used chats can be retrieved //@description The category containing private chats with non-bot users topChatCategoryUsers = TopChatCategory; //@description The category containing private chats with bot users topChatCategoryBots = TopChatCategory; //@description The category containing group chats and supergroup channel chats topChatCategoryGroups = TopChatCategory; //@description The category containing broadcast channel chats topChatCategoryChannels = TopChatCategory; //@description The category containing chats with inline bots sorted by their usage in the inline mode topChatCategoryInlineBots = TopChatCategory; //@description The category containing chats frequently used for calls topChatCategoryCalls = TopChatCategory; //@description Contains some count @count The count count count:int = Count; //@description Contains some text @text The text text text:string = Text; //@class Proxy @description Contains information about a proxy server //@description An empty proxy proxyEmpty = Proxy; //@description A SOCKS5 proxy @server Proxy server ip address @port Proxy server port @username Username to log in @password Password to log in proxySocks5 server:string port:int username:string password:string = Proxy; //@description Description of a sticker which should be added to a sticker set @png_sticker Png image with the sticker, must be up to 512 kilobytes in size and fit in 512x512 square @emojis Emojis corresponding to the sticker @mask_position Position where the mask should be placed, nullable inputSticker png_sticker:InputFile emojis:string mask_position:maskPosition = InputSticker; //@class Update @description Contains notifications about data changes //@description User authorization state has changed @auth_state New authorization state updateAuthState auth_state:AuthState = Update; //@description New message received, maybe outcoming message sent from other device @message New message @disable_notification If true, notification about the message should be disabled @contains_mention True, if the message contains mention of the current user updateNewMessage message:message disable_notification:Bool contains_mention:Bool = Update; //@description Message send request has reached Telegram server. It doesn't mean that message send will be successful or even that message send request will be processed. Update will not come, unless option "use_quick_ack" is set to true. The update may come many times for the same message //@chat_id Chat identifier of sent message @message_id Temporary message identifier updateMessageSendAcknowledged chat_id:int53 message_id:int53 = Update; //@description Message is successfully sent @message Information about sent message. Usually only message identifier, date and content are changed, but almost any other fields can also change @old_message_id Previous temporary message identifier updateMessageSendSucceeded message:message old_message_id:int53 = Update; //@description Message fails to send. Be aware that some being sent messages can be irrecoverably deleted and updateDeleteMessages will come instead of this update //@message Information about failed to send message @old_message_id Previous temporary message identifier @error_code Error code @error_message Error message updateMessageSendFailed message:message old_message_id:int53 error_code:int error_message:string = Update; //@description Message content has changed @chat_id Chat identifier @message_id Message identifier @new_content New message content updateMessageContent chat_id:int53 message_id:int53 new_content:MessageContent = Update; //@description Message was edited. Changes in the message content will come in a separate updateMessageContent @chat_id Chat identifier @message_id Message identifier @edit_date Date the message was edited, unix time @reply_markup New message reply markup, nullable updateMessageEdited chat_id:int53 message_id:int53 edit_date:int reply_markup:ReplyMarkup = Update; //@description View count of the message has changed @chat_id Chat identifier @message_id Message identifier @views New value of view count updateMessageViews chat_id:int53 message_id:int53 views:int = Update; //@description Message content was opened. It makes voice messages listened, video note messages viewed and runs ttl timer @chat_id Chat identifier @message_id Message identifier updateOpenMessageContent chat_id:int53 message_id:int53 = Update; //@description Message with an unread mention was read @chat_id Chat identifier @message_id Message identifier @unread_mention_count New number of unread mention messages left in the chat updateMessageMentionRead chat_id:int53 message_id:int53 unread_mention_count:int = Update; //@description New chat has been loaded/created. This update is guaranteed to come before chat identifier is returned to the client. Chat field changes will be reported through separate updates @chat The chat updateNewChat chat:chat = Update; //@description Title of the chat was changed @chat_id Chat identifier @title New chat title updateChatTitle chat_id:int53 title:string = Update; //@description Chat photo was changed @chat_id Chat identifier @photo New chat photo, nullable updateChatPhoto chat_id:int53 photo:chatPhoto = Update; //@description Top message of the chat has changed. If top_message is null then top message in the chat became unknown. Some new unknown messages might be added to the chat in that case @chat_id Chat identifier @top_message New top message of the chat, nullable @order New value of the chat order updateChatTopMessage chat_id:int53 top_message:message order:int64 = Update; //@description Order of the chat in the chat list has changed. Instead of that update updateChatTopMessage, updateChatIsPinned or updateChatDraftMessage may be sent @chat_id Chat identifier @order New value of the order updateChatOrder chat_id:int53 order:int64 = Update; //@description Chat was pinned or unpinned @chat_id Chat identifier @is_pinned New value of is_pinned @order New value of the chat order updateChatIsPinned chat_id:int53 is_pinned:Bool order:int64 = Update; //@description Some incoming messages was read @chat_id Chat identifier @last_read_inbox_message_id Identifier of last read incoming message @unread_count Number of unread messages left in the chat updateChatReadInbox chat_id:int53 last_read_inbox_message_id:int53 unread_count:int = Update; //@description Some outcoming messages was read @chat_id Chat identifier @last_read_outbox_message_id Identifier of last read outgoing message updateChatReadOutbox chat_id:int53 last_read_outbox_message_id:int53 = Update; //@description Chat unread_mention_count has changed @chat_id Chat identifier @unread_mention_count Number of unread mention messages left in the chat updateChatUnreadMentionCount chat_id:int53 unread_mention_count:int = Update; //@description Notification settings for some chats was updated @scope Kinds of chats for which notification settings was updated @notification_settings New notification settings updateNotificationSettings scope:NotificationSettingsScope notification_settings:notificationSettings = Update; //@description Default chat reply markup has changed. It can happen because new message with reply markup has come or old reply markup was hidden by user //@chat_id Chat identifier @reply_markup_message_id Identifier of the message from which reply markup need to be used or 0 if there is no default custom reply markup in the chat updateChatReplyMarkup chat_id:int53 reply_markup_message_id:int53 = Update; //@description Chat draft has changed. Be aware that the update may come in the currently open chat with the old content of the draft. If the user has changed the content of the draft, the update shouldn't be applied @chat_id Chat identifier @draft_message New chat draft_message, nullable @order New value of the chat order updateChatDraftMessage chat_id:int53 draft_message:draftMessage order:int64 = Update; //@description Some messages was deleted @chat_id Chat identifier @message_ids Identifiers of deleted message updateDeleteMessages chat_id:int53 message_ids:vector = Update; //@description User activity in the chat has changed @chat_id Chat identifier @user_id Identifier of user doing action @action Action description updateUserChatAction chat_id:int53 user_id:int action:ChatAction = Update; //@description User went online/offline @user_id User identifier @status New user status updateUserStatus user_id:int status:UserStatus = Update; //@description Some data about a user has been changed. This update is guaranteed to come before user identifier is returned to the client, if library knows anything about the user @user New data about the user updateUser user:user = Update; //@description Some data about a group has been changed. This update is guaranteed to come before group identifier is returned to the client, if library knows anything about the group @group New data about the group updateGroup group:group = Update; //@description Some data about a channel has been changed. This update is guaranteed to come before channel identifier is returned to the client, if library knows anything about the channel @channel New data about the channel updateChannel channel:channel = Update; //@description Some data about a secret chat has been changed. This update is guaranteed to come before secret chat identifier is returned to the client, if library knows anything about the secret chat @secret_chat New data about the secret chat updateSecretChat secret_chat:secretChat = Update; //@description Some data from userFull has been changed @user_id User identifier @user_full New full information about the user updateUserFull user_id:int user_full:userFull = Update; //@description Some data from groupFull has been changed @group_id Group identifier @group_full New full information about the group updateGroupFull group_id:int group_full:groupFull = Update; //@description Some data from channelFull has been changed @channel_id Channel identifier @channel_full New full information about the channel updateChannelFull channel_id:int channel_full:channelFull = Update; //@description Service notification from the server. Upon receiving client should show popup with content of the notification @type Type of the notification @content Notification content updateServiceNotification type:string content:MessageContent = Update; //@description DEPRECATED. Use updateFile instead. File is partly downloaded/uploaded @file_id File identifier @size Total file size (0 means unknown) @ready Number of bytes already downloaded/uploaded. Negative number means that download/upload has failed and was terminated updateFileProgress file_id:int size:int ready:int = Update; //@description Information about a file was updated @file New data about a file updateFile file:file = Update; //@description File generation process need to be started by the client @generation_id Unique identifier for the generation process @original_path Path to a file from which new file is generated, may be empty //@destination_path Path to a file which should be created and to which new file should be generated @conversion String specifying conversion applied to the original file updateFileGenerationStart generation_id:int64 original_path:string destination_path:string conversion:string = Update; //@description Informs that a file is being generated @file_id File identifier @size Expected size of the generated file @ready Number of bytes already generated. Negative number means that generation has failed and was terminated updateFileGenerationProgress file_id:int size:int ready:int = Update; //@description DEPRECATED. Use updateFile instead. File generation is finished @file Generated file updateFileGenerationFinish file:file = Update; //@description Information about a call was updated @call New data about a call updateCall call:call = Update; //@description Some privacy settings has changed @key Privacy key @rules New privacy rules updatePrivacy key:PrivacyKey rules:privacyRules = Update; //@description Some option changed its value @name Option name @value New option value updateOption name:string value:OptionValue = Update; //@description List of installed sticker sets was updated @is_masks True, if list of installed mask sticker sets was updated @sticker_set_ids New list of installed ordinary sticker sets updateInstalledStickerSets is_masks:Bool sticker_set_ids:vector = Update; //@description List of trending sticker sets was updated or some of them was viewed @sticker_sets New list of trending sticker sets updateTrendingStickerSets sticker_sets:stickerSets = Update; //@description List of recently used stickers was updated @is_attached True, if the list of stickers attached to photo or video files was updated, otherwise the list of sent stickers is updated @sticker_ids New list of file identifiers of recently used stickers updateRecentStickers is_attached:Bool sticker_ids:vector = Update; //@description List of favorite stickers was updated @sticker_ids New list of file identifiers of favorite stickers updateFavoriteStickers sticker_ids:vector = Update; //@description List of saved animations was updated @animation_ids New list of file identifiers of saved animations updateSavedAnimations animation_ids:vector = Update; //@description Connection state has changed @state New connection state updateConnectionState state:ConnectionState = Update; //@description Bots only. New incoming inline query @id Unique query identifier @sender_user_id Identifier of the user who sent the query @user_location User location, provided by the client, nullable @query Text of the query @offset Offset of the first entry to return updateNewInlineQuery id:int64 sender_user_id:int user_location:location query:string offset:string = Update; //@description Bots only. User has chosen a result of the inline query @sender_user_id Identifier of the user who sent the query @user_location User location, provided by the client, nullable @query Text of the query @result_id Identifier of the chosen result @inline_message_id Identifier of the sent inline message, if known updateNewChosenInlineResult sender_user_id:int user_location:location query:string result_id:string inline_message_id:string = Update; //@description Bots only. New incoming callback query @id Unique query identifier @sender_user_id Identifier of the user who sent the query @chat_id Identifier of the chat, in which the query was sent //@message_id Identifier of the message, from which the query is originated @chat_instance Identifier, uniquely corresponding to the chat a message was sent to @payload Query payload updateNewCallbackQuery id:int64 sender_user_id:int chat_id:int53 message_id:int53 chat_instance:int64 payload:CallbackQueryPayload = Update; //@description Bots only. New incoming callback query from message sent via bot @id Unique query identifier @sender_user_id Identifier of the user who sent the query @inline_message_id Identifier of the inline message, from which the query is originated //@chat_instance Identifier, uniquely corresponding to the chat a message was sent to @payload Query payload updateNewInlineCallbackQuery id:int64 sender_user_id:int inline_message_id:string chat_instance:int64 payload:CallbackQueryPayload = Update; //@description Bots only. New incoming shipping query. Only for invoices with flexible price @id Unique query identifier @sender_user_id Identifier of the user who sent the query @invoice_payload Invoice payload @shipping_address User shipping address updateNewShippingQuery id:int64 sender_user_id:int invoice_payload:string shipping_address:shippingAddress = Update; //@description Bots only. New incoming pre-checkout query. Contains full information about checkout @id Unique query identifier @sender_user_id Identifier of the user who sent the query @currency Currency for goods price @total_amount Goods total price in minimal quantity of the currency //@invoice_payload Invoice payload @shipping_option_id Identifier of a choosed by user shipping option, may be empty if not applicable @order_info Information about the order, nullable updateNewPreCheckoutQuery id:int64 sender_user_id:int currency:string total_amount:int53 invoice_payload:bytes shipping_option_id:string order_info:orderInfo = Update; //@description Bots only. New incoming event @event JSON-serialized event updateNewCustomEvent event:string = Update; //@description Bots only. New incoming query @id Query identifier @data JSON-serialized query data @timeout Query timeout updateNewCustomQuery id:int64 data:string timeout:int = Update; //@description Tests only. A simple object containing just a number @value The number testInt value:int = TestInt; //@description Tests only. A simple object containing just a string @value The string testString value:string = TestString; //@description Tests only. A simple object containing just a bytes @value The bytes testBytes value:bytes = TestBytes; //@description Tests only. A simple object containing just a vector of numbers @value The vector of numbers testVectorInt value:vector = TestVectorInt; //@description Tests only. A simple object containing just a vector of objects containing a number @value The vector of objects testVectorIntObject value:vector = TestVectorIntObject; //@description Tests only. A simple object containing just a vector of strings @value The vector of strings testVectorString value:vector = TestVectorString; //@description Tests only. A simple object containing just a vector of objects containing a string @value The vector of objects testVectorStringObject value:vector = TestVectorStringObject; ---functions--- //@description Returns current authorization state, offline request getAuthState = AuthState; //@description Sets user's phone number and sends authentication code to the user. Works only when getAuthState returns authStateWaitPhoneNumber. If phone number is not recognized or another error has happened, returns an error. Otherwise returns authStateWaitCode //@phone_number User's phone number in any reasonable format @allow_flash_call Pass True, if code can be sent via flash call to the specified phone number @is_current_phone_number Pass true, if the phone number is used on the current device. Ignored if allow_flash_call is False setAuthPhoneNumber phone_number:string allow_flash_call:Bool is_current_phone_number:Bool = AuthState; //@description Resends authentication code to the user. Works only when getAuthState returns authStateWaitCode and next_code_type of result is not null. Returns authStateWaitCode on success resendAuthCode = AuthState; //@description Checks authentication code. Works only when getAuthState returns authStateWaitCode. Returns authStateWaitPassword or authStateOk on success @code Verification code from SMS, Telegram message, phone call or flash call //@first_name User first name, if user is yet not registered, 1-255 characters @last_name Optional user last name, if user is yet not registered, 0-255 characters checkAuthCode code:string first_name:string last_name:string = AuthState; //@description Checks password for correctness. Works only when getAuthState returns authStateWaitPassword. Returns authStateOk on success @password Password to check checkAuthPassword password:string = AuthState; //@description Requests to send password recovery code to email. Works only when getAuthState returns authStateWaitPassword. Returns authStateWaitPassword on success requestAuthPasswordRecovery = AuthState; //@description Recovers password with recovery code sent to email. Works only when getAuthState returns authStateWaitPassword. Returns authStateOk on success @recovery_code Recovery code to check recoverAuthPassword recovery_code:string = AuthState; //@description Logs out user. If force == false, begins to perform soft log out, returns authStateLoggingOut after completion. If force == true then succeeds almost immediately without cleaning anything at the server, but returns error with code 401 and description "Unauthorized" //@force If true, just delete all local data. Session will remain in list of active sessions resetAuth force:Bool = AuthState; //@description Check bot's authentication token to log in as a bot. Works only when getAuthState returns authStateWaitPhoneNumber. Can be used instead of setAuthPhoneNumber and checkAuthCode to log in. Returns authStateOk on success @token Bot token checkAuthBotToken token:string = AuthState; //@description Returns current state of two-step verification getPasswordState = PasswordState; //@description Changes user password. If new recovery email is specified, then error EMAIL_UNCONFIRMED is returned and password change will not be applied until email confirmation. Application should call getPasswordState from time to time to check if email is already confirmed //@old_password Old user password @new_password New user password, may be empty to remove the password @new_hint New password hint, can be empty @set_recovery_email Pass True, if recovery email should be changed @new_recovery_email New recovery email, may be empty setPassword old_password:string new_password:string new_hint:string set_recovery_email:Bool new_recovery_email:string = PasswordState; //@description Returns set up recovery email. This method can be used to verify a password provided by the user @password Current user password getRecoveryEmail password:string = RecoveryEmail; //@description Changes user recovery email. If new recovery email is specified, then error EMAIL_UNCONFIRMED is returned and email will not be changed until email confirmation. Application should call getPasswordState from time to time to check if email is already confirmed. -If new_recovery_email coincides with the current set up email succeeds immediately and aborts all other requests waiting for email confirmation @password Current user password @new_recovery_email New recovery email setRecoveryEmail password:string new_recovery_email:string = PasswordState; //@description Requests to send password recovery code to email requestPasswordRecovery = PasswordRecoveryInfo; //@description Recovers password with recovery code sent to email @recovery_code Recovery code to check recoverPassword recovery_code:string = PasswordState; //@description Creates new temporary password for payments processing @password Persistent user password @valid_for Time before temporary password will expire, seconds. Should be between 60 and 86400 createTemporaryPassword password:string valid_for:int = TemporaryPasswordState; //@description Returns information about current temporary password getTemporaryPasswordState = TemporaryPasswordState; //@description Handles DC_UPDATE push service notification. Can be called before authorization @dc Value of 'dc' paramater of the notification @addr Value of 'addr' parameter of the notification processDcUpdate dc:string addr:string = Ok; //@description Returns current logged in user getMe = User; //@description Returns information about a user by its identifier, offline request if current user is not a bot @user_id User identifier getUser user_id:int = User; //@description Returns full information about a user by its identifier @user_id User identifier getUserFull user_id:int = UserFull; //@description Returns information about a group by its identifier, offline request if current user is not a bot @group_id Group identifier getGroup group_id:int = Group; //@description Returns full information about a group by its identifier @group_id Group identifier getGroupFull group_id:int = GroupFull; //@description Returns information about a channel by its identifier, offline request if current user is not a bot @channel_id Channel identifier getChannel channel_id:int = Channel; //@description Returns full information about a channel by its identifier, cached for at most 1 minute @channel_id Channel identifier getChannelFull channel_id:int = ChannelFull; //@description Returns information about a secret chat by its identifier, offline request @secret_chat_id Secret chat identifier getSecretChat secret_chat_id:int = SecretChat; //@description Returns information about a chat by its identifier, offline request if current user is not a bot @chat_id Chat identifier getChat chat_id:int53 = Chat; //@description Returns information about a message @chat_id Identifier of the chat, message belongs to @message_id Identifier of the message to get getMessage chat_id:int53 message_id:int53 = Message; //@description Returns information about messages. If message is not found, returns null on the corresponding position of the result @chat_id Identifier of the chat, messages belongs to @message_ids Identifiers of the messages to get getMessages chat_id:int53 message_ids:vector = Messages; //@description Returns information about a file, offline request @file_id Identifier of the file to get getFile file_id:int = File; //@description Returns information about a file by its persistent id, offline request. May be used to register a URL as a file for further uploading or sending as message @persistent_file_id Persistent identifier of the file to get @file_type File type, if known getFilePersistent persistent_file_id:string file_type:FileType = File; //@description Returns list of chats in the right order, chats are sorted by (order, chat_id) in decreasing order. For example, to get list of chats from the beginning, the offset_order should be equal 2^63 - 1 @offset_order Chat order to return chats from @offset_chat_id Chat identifier to return chats from //@limit Maximum number of chats to be returned. There may be less than limit chats returned even the end of the list is not reached getChats offset_order:int64 offset_chat_id:int53 limit:int = Chats; //@description Searches public chat by its username. Currently only private and channel chats can be public. Returns chat if found, otherwise some error is returned @username Username to be resolved searchPublicChat username:string = Chat; //@description Searches public chats by prefix of their username. Currently only private and channel (including supergroup) chats can be public. Returns meaningful number of results. Returns nothing if length of the searched username prefix is less than 5. Excludes private chats with contacts from the results @username_prefix Prefix of the username to search searchPublicChats username_prefix:string = Chats; //@description Searches for specified query in the title and username of known chats, offline request. Returns chats in the order of them in the chat list @query Query to search for, if query is empty, returns up to 20 recently found chats @limit Maximum number of chats to be returned searchChats query:string limit:int = Chats; //@description Returns a list of frequently used chats. Supported only if chat info database is enabled @category Category of chats to return @limit Maximum number of chats to be returned, at most 30 getTopChats category:TopChatCategory limit:int = Chats; //@description Delete a chat from a list of frequently used chats. Supported only if chat info database is enabled @category Category of frequently used chats @chat_id Chat identifier deleteTopChat category:TopChatCategory chat_id:int53 = Ok; //@description Adds chat to the list of recently found chats. The chat is added to the beginning of the list. If the chat is already in the list, at first it is removed from the list @chat_id Identifier of the chat to add addRecentlyFoundChat chat_id:int53 = Ok; //@description Deletes chat from the list of recently found chats @chat_id Identifier of the chat to delete deleteRecentlyFoundChat chat_id:int53 = Ok; //@description Clears list of recently found chats deleteRecentlyFoundChats = Ok; //@description Returns list of common chats with an other given user. Chats are sorted by their type and creation date @user_id User identifier @offset_chat_id Chat identifier to return chats from, use 0 for the first request @limit Maximum number of chats to be returned, up to 100 getCommonChats user_id:int offset_chat_id:int53 limit:int = Chats; //@description Returns list of created public chats getCreatedPublicChats = Chats; //@description Returns messages in a chat. Returns result in reverse chronological order, i.e. in order of decreasing message.message_id. Offline request if only_local is true @chat_id Chat identifier //@from_message_id Identifier of the message near which we need a history, you can use 0 to get results from the beginning, i.e. from oldest to newest //@offset Specify 0 to get results exactly from from_message_id or negative offset to get specified message and some newer messages //@limit Maximum number of messages to be returned, should be positive and can't be greater than 100. If offset is negative, limit must be greater than -offset. There may be less than limit messages returned even the end of the history is not reached //@only_local Return only locally available messages without sending network requests getChatHistory chat_id:int53 from_message_id:int53 offset:int limit:int only_local:Bool = Messages; //@description Deletes all messages in the chat. Can't be used for channel chats @chat_id Chat identifier @remove_from_chat_list Pass true, if chat should be removed from the chat list deleteChatHistory chat_id:int53 remove_from_chat_list:Bool = Ok; //@description Searches for messages with given words in the chat. Returns result in reverse chronological order, i. e. in order of decreasing message_id. Doesn't work in secret chats with non-empty query (searchSecretMessages should be used instead) or without enabled message database @chat_id Chat identifier to search messages in //@query Query to search for //@sender_user_id If not 0, only messages sent by the specified user will be returned. Doesn't supported in secret chats //@from_message_id Identifier of the message from which we need a history, you can use 0 to get results from the beginning //@offset Specify 0 to get results exactly from from_message_id or negative offset to get specified message and some newer messages //@limit Maximum number of messages to be returned, should be positive and can't be greater than 100. If offset is negative, limit must be greater than -offset. There may be less than limit messages returned even the end of the history is not reached //@filter Filter for content of the searched messages searchChatMessages chat_id:int53 query:string sender_user_id:int from_message_id:int53 offset:int limit:int filter:SearchMessagesFilter = Messages; //@description Searches for messages in all chats except secret chats. Returns result in reverse chronological order, i. e. in order of decreasing (date, chat_id, message_id) //@query Query to search for //@offset_date Date of the message to search from, you can use 0 or any date in the future to get results from the beginning //@offset_chat_id Chat identifier of the last found message or 0 for the first request //@offset_message_id Message identifier of the last found message or 0 for the first request //@limit Maximum number of messages to be returned, at most 100 searchMessages query:string offset_date:int offset_chat_id:int53 offset_message_id:int53 limit:int = Messages; //@description Searches for messages in secret chats. Returns result in reverse chronological order @chat_id Identifier of a chat to search in. Specify 0 to search in all secret chats @query Query to search for. If empty, searchChatMessages should be used instead //@from_search_id Identifier from the result of previous request, use 0 to get results from the beginning @limit Maximum number of messages to be returned, can't be greater than 100 @filter Filter for content of searched messages searchSecretMessages chat_id:int53 query:string from_search_id:int64 limit:int filter:SearchMessagesFilter = FoundMessages; //@description Searches for call messages. Returns result in reverse chronological order, i. e. in order of decreasing message_id @from_message_id Identifier of the message from which to search, you can use 0 to get results from beginning //@limit Maximum number of messages to be returned, can't be greater than 100. There may be less than limit messages returned even the end of the history is not reached filter @only_missed If true, return only messages with missed calls searchCallMessages from_message_id:int53 limit:int only_missed:Bool = Messages; //@description Returns public HTTPS link to a message. Available only for messages in public channels @chat_id Identifier of the chat, message belongs to @message_id Identifier of the message getPublicMessageLink chat_id:int53 message_id:int53 = PublicMessageLink; //@description Sends a message. Returns sent message @chat_id Chat to send message @reply_to_message_id Identifier of a message to reply to or 0 //@disable_notification Pass true, to disable notification about the message, doesn't works in secret chats @from_background Pass true, if the message is sent from background //@reply_markup Bots only. Markup for replying to message @input_message_content Content of a message to send sendMessage chat_id:int53 reply_to_message_id:int53 disable_notification:Bool from_background:Bool reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Invites bot to a chat (if it is not in the chat) and send /start to it. Bot can't be invited to a private chat other than chat with the bot. Bots can't be invited to broadcast channel chats and secret chats. Returns sent message //@bot_user_id Identifier of the bot @chat_id Identifier of the chat @parameter Hidden parameter sent to bot for deep linking (https://api.telegram.org/bots#deep-linking) sendBotStartMessage bot_user_id:int chat_id:int53 parameter:string = Message; //@description Sends result of the inline query as a message. Returns sent message. Always clears chat draft message @chat_id Chat to send message @reply_to_message_id Identifier of a message to reply to or 0 //@disable_notification Pass true, to disable notification about the message, doesn't works in secret chats @from_background Pass true, if the message is sent from background //@query_id Identifier of the inline query @result_id Identifier of the inline result sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 disable_notification:Bool from_background:Bool query_id:int64 result_id:string = Message; //@description Forwards previously sent messages. Returns forwarded messages in the same order as message identifiers passed in message_ids. If message can't be forwarded, null will be returned instead of the message //@chat_id Identifier of a chat to forward messages @from_chat_id Identifier of a chat to forward from @message_ids Identifiers of messages to forward //@disable_notification Pass true, to disable notification about the message, doesn't works if messages are forwarded to secret chat @from_background Pass true, if the message is sent from background forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector disable_notification:Bool from_background:Bool = Messages; //@description Changes current ttl setting in a secret chat and sends corresponding message @chat_id Chat identifier @ttl New value of ttl in seconds sendChatSetTtlMessage chat_id:int53 ttl:int = Message; //@description Sends notification about screenshot taken in a chat. Works only in private and secret chats @chat_id Chat identifier sendChatScreenshotTakenNotification chat_id:int53 = Ok; //@description Deletes messages @chat_id Chat identifier @message_ids Identifiers of messages to delete @revoke Pass true to try to delete sent messages for all chat members (may fail if messages are too old). Is always true for Channels and SecretChats deleteMessages chat_id:int53 message_ids:vector revoke:Bool = Ok; //@description Deletes all messages in the chat sent by the specified user. Works only in supergroup channel chats, needs can_delete_messages administrator privileges @chat_id Chat identifier @user_id User identifier deleteMessagesFromUser chat_id:int53 user_id:int = Ok; //@description Edits text of text or game message. Non-bots can edit message in a limited period of time. Returns edited message after edit is complete server side //@chat_id Chat the message belongs to @message_id Identifier of the message @reply_markup Bots only. New message reply markup @input_message_content New text content of the message. Should be of type InputMessageText editMessageText chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_message_content:InputMessageContent = Message; //@description Edits message content caption. Non-bots can edit message in a limited period of time. Returns edited message after edit is complete server side //@chat_id Chat the message belongs to @message_id Identifier of the message @reply_markup Bots only. New message reply markup @caption New message content caption, 0-200 characters editMessageCaption chat_id:int53 message_id:int53 reply_markup:ReplyMarkup caption:string = Message; //@description Bots only. Edits message reply markup. Returns edited message after edit is complete server side //@chat_id Chat the message belongs to @message_id Identifier of the message @reply_markup New message reply markup editMessageReplyMarkup chat_id:int53 message_id:int53 reply_markup:ReplyMarkup = Message; //@description Bots only. Edits text of an inline text or game message sent via bot @inline_message_id Inline message identifier @reply_markup New message reply markup @input_message_content New text content of the message. Should be of type InputMessageText editInlineMessageText inline_message_id:string reply_markup:ReplyMarkup input_message_content:InputMessageContent = Ok; //@description Bots only. Edits caption of an inline message content sent via bot @inline_message_id Inline message identifier @reply_markup New message reply markup @caption New message content caption, 0-200 characters editInlineMessageCaption inline_message_id:string reply_markup:ReplyMarkup caption:string = Ok; //@description Bots only. Edits reply markup of an inline message sent via bot @inline_message_id Inline message identifier @reply_markup New message reply markup editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup = Ok; //@description Returns all mentions, hashtags, bot commands, URLs and emails contained in the text. Offline method. Can be called before authorization. Can be called synchronously @text Text to find entites in getTextEntities text:string = TextEntities; //@description Returns file's mime type guessing only by its extension. Returns empty string on failure. Offline method. Can be called before authorization. Can be called synchronously @file_name Name of the file or path to the file getFileMimeType file_name:string = Text; //@description Returns file's extension guessing only by its mime type. Returns empty string on failure. Offline method. Can be called before authorization. Can be called synchronously @mime_type Mime type of the file getFileExtension mime_type:string = Text; //@description Sends inline query to a bot and returns its results. Returns error with code 502 if bot fails to answer the query before query timeout expires. Unavailable for bots @bot_user_id Identifier of the bot send query to //@chat_id Identifier of the chat, where the query is sent @user_location User location, only if needed @query Text of the query @offset Offset of the first entry to return getInlineQueryResults bot_user_id:int chat_id:int53 user_location:location query:string offset:string = InlineQueryResults; //@description Bots only. Sets result of an inline query @inline_query_id Identifier of the inline query @is_personal Does result of the query can be cached only for specified user //@results Results of the query @cache_time Allowed time to cache results of the query in seconds @next_offset Offset for the next inline query, pass empty string if there is no more results //@switch_pm_text If non-empty, this text should be shown on the button, which opens private chat with the bot and sends bot start message with parameter switch_pm_parameter @switch_pm_parameter Parameter for the bot start message answerInlineQuery inline_query_id:int64 is_personal:Bool results:vector cache_time:int next_offset:string switch_pm_text:string switch_pm_parameter:string = Ok; //@description Sends callback query to a bot and returns answer to it. Returns error with code 502 if bot fails to answer the query before query timeout expires. Unavailable for bots @chat_id Identifier of the chat with a message @message_id Identifier of the message, from which the query is originated @payload Query payload getCallbackQueryAnswer chat_id:int53 message_id:int53 payload:CallbackQueryPayload = CallbackQueryAnswer; //@description Bots only. Sets result of a callback query @callback_query_id Identifier of the callback query @text Text of the answer @show_alert If true, an alert should be shown to the user instead of a toast @url Url to be opened @cache_time Allowed time to cache result of the query in seconds answerCallbackQuery callback_query_id:int64 text:string show_alert:Bool url:string cache_time:int = Ok; //@description Bots only. Sets result of a shipping query @shipping_query_id Identifier of the shipping query @shipping_options Available shipping options @error_message Error message, empty on success answerShippingQuery shipping_query_id:int64 shipping_options:vector error_message:string = Ok; //@description Bots only. Sets result of a pre checkout query @pre_checkout_query_id Identifier of the pre-checkout query @error_message Error message, empty on success answerPreCheckoutQuery pre_checkout_query_id:int64 error_message:string = Ok; //@description Bots only. Updates game score of the specified user in the game @chat_id Chat a message with the game belongs to @message_id Identifier of the message @edit_message True, if message should be edited @user_id User identifier @score New score //@force Pass True to update the score even if it decreases. If score is 0, user will be deleted from the high scores table setGameScore chat_id:int53 message_id:int53 edit_message:Bool user_id:int score:int force:Bool = Message; //@description Bots only. Updates game score of the specified user in the game @inline_message_id Inline message identifier @edit_message True, if message should be edited @user_id User identifier @score New score //@force Pass True to update the score even if it decreases. If score is 0, user will be deleted from the high scores table setInlineGameScore inline_message_id:string edit_message:Bool user_id:int score:int force:Bool = Ok; //@description Bots only. Returns game high scores and some part of the score table around of the specified user in the game @chat_id Chat a message with the game belongs to @message_id Identifier of the message @user_id User identifie getGameHighScores chat_id:int53 message_id:int53 user_id:int = GameHighScores; //@description Bots only. Returns game high scores and some part of the score table around of the specified user in the game @inline_message_id Inline message identifier @user_id User identifier getInlineGameHighScores inline_message_id:string user_id:int = GameHighScores; //@description Deletes default reply markup from chat. This method needs to be called after one-time keyboard or ForceReply reply markup has been used. UpdateChatReplyMarkup will be send if reply markup will be changed @chat_id Chat identifier //@message_id Message identifier of used keyboard deleteChatReplyMarkup chat_id:int53 message_id:int53 = Ok; //@description Sends notification about user activity in a chat @chat_id Chat identifier @action Action description sendChatAction chat_id:int53 action:ChatAction = Ok; //@description Chat is opened by the user. Many useful activities depends on chat being opened or closed. For example, in channels all updates are received only for opened chats @chat_id Chat identifier openChat chat_id:int53 = Ok; //@description Chat is closed by the user. Many useful activities depends on chat being opened or closed. @chat_id Chat identifier closeChat chat_id:int53 = Ok; //@description Messages are viewed by the user. Many useful activities depends on message being viewed. For example, marking messages as read, incrementing of view counter, updating of view counter, removing of deleted messages in channels @chat_id Chat identifier @message_ids Identifiers of viewed messages viewMessages chat_id:int53 message_ids:vector = Ok; //@description Message content is opened, for example the user has opened a photo, a video, a document, a location or a venue or have listened to an audio or a voice message. You will receive updateOpenMessageContent if something has changed @chat_id Chat identifier of the message @message_id Identifier of the message with opened content openMessageContent chat_id:int53 message_id:int53 = Ok; //@description Returns existing chat corresponding to the given user @user_id User identifier createPrivateChat user_id:int = Chat; //@description Returns existing chat corresponding to the known group @group_id Group identifier createGroupChat group_id:int = Chat; //@description Returns existing chat corresponding to the known channel @channel_id Channel identifier createChannelChat channel_id:int = Chat; //@description Returns existing chat corresponding to the known secret chat @secret_chat_id SecretChat identifier createSecretChat secret_chat_id:int = Chat; //@description Creates new group chat and send corresponding messageGroupChatCreate, returns created chat @user_ids Identifiers of users to add to the group @title Title of new group chat, 1-255 characters createNewGroupChat user_ids:vector title:string = Chat; //@description Creates new channel chat and send corresponding messageChannelChatCreate, returns created chat @title Title of new channel chat, 1-255 characters @is_supergroup True, if supergroup chat should be created @param_description Channel description, 0-255 characters createNewChannelChat title:string is_supergroup:Bool description:string = Chat; //@description Creates new secret chat, returns created chat @user_id Identifier of a user to create secret chat with createNewSecretChat user_id:int = Chat; //@description Creates new channel supergroup chat from existing group chat and send corresponding messageChatMigrateTo and messageChatMigrateFrom. Deactivates group @chat_id Group chat identifier migrateGroupChatToChannelChat chat_id:int53 = Chat; //@description Changes chat title. Works only for group and channel chats. Requires administrator rights in groups and appropriate administrator right in channels. Title will not change before request to the server completes //@chat_id Chat identifier @title New title of the chat, 1-255 characters changeChatTitle chat_id:int53 title:string = Ok; //@description Changes chat photo. Works only for group and channel chats. Requires administrator rights in groups and appropriate administrator right in channels. Photo will not change before request to the server completes //@chat_id Chat identifier @photo New chat photo. You can use zero InputFileId to delete chat photo. Files accessible only by HTTP URL are not acceptable changeChatPhoto chat_id:int53 photo:InputFile = Ok; //@description Changes chat draft message @chat_id Chat identifier @draft_message New draft message, nullable changeChatDraftMessage chat_id:int53 draft_message:draftMessage = Ok; //@description Changes chat pinned state. You can pin up to getOption("pinned_chat_count_max") non-secret chats and the same number of secret chats @chat_id Chat identifier @is_pinned New value of is_pinned toggleChatIsPinned chat_id:int53 is_pinned:Bool = Ok; //@description Changes client data associated with a chat @chat_id Chat identifier @client_data New value of client_data setChatClientData chat_id:int53 client_data:string = Ok; //@description Adds new member to chat. Members can't be added to private or secret chats. Member will not be added until chat state will be synchronized with the server //@chat_id Chat identifier @user_id Identifier of the user to add @forward_limit Number of previous messages from chat to forward to new member, ignored for channel chats. Can't be greater than 300 addChatMember chat_id:int53 user_id:int forward_limit:int = Ok; //@description Adds many new members to the chat. Currently, available only for channels. Can't be used to join the channel. Members can't be added to broadcast channel if it has more than 200 members. Members will not be added until chat state will be synchronized with the server //@chat_id Chat identifier @user_ids Identifiers of the users to add addChatMembers chat_id:int53 user_ids:vector = Ok; //@description Changes status of the chat member, need appropriate privileges. This function is currently not suitable for adding new members to the chat, use addChatMember instead. Status will not be changed until chat state will be synchronized with the server //@chat_id Chat identifier @user_id Identifier of the user to edit status @status New status of the member in the chat changeChatMemberStatus chat_id:int53 user_id:int status:ChatMemberStatus = Ok; //@description Returns information about one participant of the chat @chat_id Chat identifier @user_id User identifier getChatMember chat_id:int53 user_id:int = ChatMember; //@description Searches for the specified query in the first name, last name and username among members of the specified chat. Requires administrator rights in broadcast channels @chat_id Chat identifier @query Query to search for @limit Maximum number of users to be returned searchChatMembers chat_id:int53 query:string limit:int = ChatMembers; //@description Changes list or order of pinned chats @chat_ids New list of pinned chats setPinnedChats chat_ids:vector = Ok; //@description Asynchronously downloads file from cloud. Updates updateFile will notify about download progress and successful download @file_id Identifier of file to download //@priority Priority of download, 1-32. The higher priority, the earlier file will be downloaded. If priorities of two files are equal then the last one for which downloadFile is called will be downloaded first downloadFile file_id:int priority:int = Ok; //@description Stops file downloading. If file is already downloaded, does nothing @file_id Identifier of file to cancel download cancelDownloadFile file_id:int = Ok; //@description Asynchronously uploads file to the cloud without sending it in a message. Updates updateFile will notify about upload progress and successful upload. The file will not have persistent identifier until it will be sent in a message @file File to upload @file_type File type //@priority Priority of upload, 1-32. The higher priority, the earlier file will be uploaded. If priorities of two files are equal then the first one for which uploadFile is called will be uploaded first uploadFile file:InputFile file_type:FileType priority:int = File; //@description Stops file uploading. Works only for files uploaded using uploadFile. For other files the behavior is undefined @file_id Identifier of file to cancel upload cancelUploadFile file_id:int = Ok; //@description Next part of a file was generated //@generation_id Identifier of the generation process //@size Full size of file in bytes, 0 if unknown. //@local_size Number of bytes already generated. Negative number means that generation has failed and should be terminated setFileGenerationProgress generation_id:int64 size:int local_size:int = Ok; //@description Finishes file generation @generation_id Identifier of the generation process finishFileGeneration generation_id:int64 = Ok; //@description Deletes a file from TDLib file cache @file_id Identifier of the file to delete deleteFile file_id:int = Ok; //@description Generates new chat invite link, previously generated link is revoked. Available for group and channel chats. In groups can be called only by creator, in channels requires appropriate rights @chat_id Chat identifier exportChatInviteLink chat_id:int53 = ChatInviteLink; //@description Checks chat invite link for validness and returns information about the corresponding chat @invite_link Invite link to check. Should begin with "https://t.me/joinchat/", "https://telegram.me/joinchat/" or "https://telegram.dog/joinchat/" checkChatInviteLink invite_link:string = ChatInviteLinkInfo; //@description Imports chat invite link, adds current user to a chat if possible. Member will not be added until chat state will be synchronized with the server //@invite_link Invite link to import. Should begin with "https://t.me/joinchat/", "https://telegram.me/joinchat/" or "https://telegram.dog/joinchat/" importChatInviteLink invite_link:string = Ok; //@description Creates new call @user_id Identifier of user to call @protocol Description of supported by the client call protocols createCall user_id:int protocol:callProtocol = CallId; //@description Accepts incoming call @call_id Call identifier @protocol Description of supported by the client call protocols acceptCall call_id:int protocol:callProtocol = Ok; //@description Discards a call @call_id Call identifier @is_disconnected True, if users was disconnected @duration Call duration in seconds @connection_id Identifier of a connection used during the call discardCall call_id:int is_disconnected:Bool duration:int connection_id:int64 = Ok; //@description Sends call rating @call_id Call identifier @rating Call rating, 1-5 @comment Optional user comment if rating is less than 5 rateCall call_id:int rating:int comment:string = Ok; //@description Sends call debug information @call_id Call identifier @debug Debug information in application specific format debugCall call_id:int debug:string = Ok; //@description Adds user to black list @user_id User identifier blockUser user_id:int = Ok; //@description Removes user from black list @user_id User identifier unblockUser user_id:int = Ok; //@description Returns users blocked by the current user @offset Number of users to skip in result, must be non-negative @limit Maximum number of users to return, can't be greater than 100 getBlockedUsers offset:int limit:int = Users; //@description Adds new contacts/edits existing contacts, contacts user identifiers are ignored @contacts List of contacts to import/edit importContacts contacts:vector = ImportedContacts; //@description Searches for specified query in the first name, last name and username of the known user contacts @query Query to search for, can be empty to return all contacts @limit Maximum number of users to be returned searchContacts query:string limit:int = Users; //@description Deletes users from contacts list @user_ids Identifiers of users to be deleted deleteContacts user_ids:vector = Ok; //@description Returns total number of imported contacts getImportedContactCount = Count; //@description Deletes all imported contacts deleteImportedContacts = Ok; //@description Returns profile photos of the user. Result of this query may be outdated: some photos may be already deleted @user_id User identifier @offset Photos to skip, must be non-negative @limit Maximum number of photos to be returned, can't be greater than 100 getUserProfilePhotos user_id:int offset:int limit:int = UserProfilePhotos; //@description Returns stickers from installed ordinary sticker sets corresponding to the given emoji. If emoji is not empty, elso favorite and recently used stickers may be returned @emoji String representation of emoji. If empty, returns all known stickers @limit Maximum number of stickers to return getStickers emoji:string limit:int = Stickers; //@description Returns list of installed sticker sets @is_masks Pass true to return mask sticker sets, pass false to return ordinary sticker sets getInstalledStickerSets is_masks:Bool = StickerSets; //@description Returns list of archived sticker sets @is_masks Pass true to return mask stickers sets, pass false to return ordinary sticker sets @offset_sticker_set_id Identifier of the sticker set from which return the result @limit Maximum number of sticker sets to return getArchivedStickerSets is_masks:Bool offset_sticker_set_id:int64 limit:int = StickerSets; //@description Returns list of trending sticker sets getTrendingStickerSets = StickerSets; //@description Returns list of sticker sets attached to a file, currently only photos and videos can have attached sticker sets @file_id File identifier getAttachedStickerSets file_id:int = StickerSets; //@description Returns information about sticker set by its identifier @set_id Identifier of the sticker set getStickerSet set_id:int64 = StickerSet; //@description Searches sticker set by its short name @name Name of the sticker set searchStickerSet name:string = StickerSet; //@description Installs/uninstalls or enables/archives sticker set @set_id Identifier of the sticker set @is_installed New value of is_installed @is_archived New value of is_archived. A sticker set can't be installed and archived simultaneously changeStickerSet set_id:int64 is_installed:Bool is_archived:Bool = Ok; //@description Informs that some trending sticker sets are viewed by the user @sticker_set_ids Identifiers of viewed trending sticker sets viewTrendingStickerSets sticker_set_ids:vector = Ok; //@description Changes the order of installed sticker sets @is_masks Pass true to change mask sticker sets order, pass false to change ordinary sticker sets order @sticker_set_ids Identifiers of installed sticker sets in the new right order reorderInstalledStickerSets is_masks:Bool sticker_set_ids:vector = Ok; //@description Returns list of recently used stickers @is_attached Pass true to return stickers and masks recently attached to photo or video files, pass false to return recently sent stickers getRecentStickers is_attached:Bool = Stickers; //@description Manually adds new sticker to the list of recently used stickers. New sticker is added to the beginning of the list. If the sticker is already in the list, at first it is removed from the list. Only stickers belonging to a sticker set can be added to the list //@is_attached Pass true to add the sticker to the list of stickers recently attached to photo or video files, pass false to add the sticker to the list of recently sent stickers @sticker Sticker file to add addRecentSticker is_attached:Bool sticker:InputFile = Stickers; //@description Removes a sticker from the list of recently used stickers @is_attached Pass true to remove the sticker from the list of stickers recently attached to photo or video files, pass false to remove the sticker from the list of recently sent stickers @sticker Sticker file to delete deleteRecentSticker is_attached:Bool sticker:InputFile = Ok; //@description Clears list of recently used stickers @is_attached Pass true to clear list of stickers recently attached to photo or video files, pass false to clear the list of recently sent stickers clearRecentStickers is_attached:Bool = Ok; //@description Returns favorite stickers getFavoriteStickers = Stickers; //@description Adds new sticker to the list of favorite stickers. New sticker is added to the beginning of the list. If the sticker is already in the list, at first it is removed from the list. Only stickers belonging to a sticker set can be added to the list //@sticker Sticker file to add addFavoriteSticker sticker:InputFile = Ok; //@description Removes a sticker from the list of favorite stickers @sticker Sticker file to delete from the list deleteFavoriteSticker sticker:InputFile = Ok; //@description Returns emojis corresponding to a sticker @sticker Sticker file identifier getStickerEmojis sticker:InputFile = StickerEmojis; //@description Returns saved animations getSavedAnimations = Animations; //@description Manually adds new animation to the list of saved animations. New animation is added to the beginning of the list. If the animation is already in the list, at first it is removed from the list. Only non-secret video animations with MIME type "video/mp4" can be added to the list //@animation Animation file to add. Only known to server animations (i. e. successfully sent via message) can be added to the list addSavedAnimation animation:InputFile = Ok; //@description Removes an animation from the list of saved animations @animation Animation file to delete deleteSavedAnimation animation:InputFile = Ok; //@description Returns up to 20 recently used inline bots in the order of the last usage getRecentInlineBots = Users; //@description Searches for recently used hashtags by their prefix @prefix Hashtag prefix to search for @limit Maximum number of hashtags to return searchHashtags prefix:string limit:int = Hashtags; //@description Deletes a hashtag from the list of recently used hashtags @hashtag The hashtag to delete deleteRecentHashtag hashtag:string = Ok; //@description Returns web page preview by text of the message. Do not call this function to often. Returns error 404 if web page has no preview @message_text Message text getWebPagePreview message_text:string = WebPage; //@description Returns web page instant view if available. Returns error 404 if web page has no instant view @url Web page URL @force_full If true, full web page instant view will be returned getWebPageInstantView url:string force_full:Bool = WebPageInstantView; //@description Returns notification settings for a given scope @scope Scope to return information about notification settings getNotificationSettings scope:NotificationSettingsScope = NotificationSettings; //@description Changes notification settings for a given scope @scope Scope to change notification settings //@notification_settings New notification settings for given scope setNotificationSettings scope:NotificationSettingsScope notification_settings:notificationSettings = Ok; //@description Resets all notification settings to the default value. By default the only muted chats are supergroups, sound is set to 'default' and message previews are showed resetAllNotificationSettings = Ok; //@description Uploads new profile photo for logged in user. If something changes, updateUser will be sent @photo Profile photo to set. inputFileId and inputFilePersistentId may be unsupported setProfilePhoto photo:InputFile = Ok; //@description Deletes profile photo. If something changes, updateUser will be sent @profile_photo_id Identifier of profile photo to delete deleteProfilePhoto profile_photo_id:int64 = Ok; //@description Changes first and last names of logged in user. If something changes, updateUser will be sent @first_name New value of user first name, 1-255 characters @last_name New value of optional user last name, 0-255 characters changeName first_name:string last_name:string = Ok; //@description Changes about information of logged in user @about New value of userFull.about, 0-70 characters without line feeds changeAbout about:string = Ok; //@description Changes username of logged in user. If something changes, updateUser will be sent @username New value of username. Use empty string to remove username changeUsername username:string = Ok; //@description Changes user's phone number and sends authentication code to the new user's phone number. Returns authStateWaitCode with information about sent code on success //@phone_number New user's phone number in any reasonable format @allow_flash_call Pass True, if code can be sent via flash call to the specified phone number @is_current_phone_number Pass true, if the phone number is used on the current device. Ignored if allow_flash_call is False changePhoneNumber phone_number:string allow_flash_call:Bool is_current_phone_number:Bool = AuthState; //@description Resends authentication code sent to change user's phone number. Wotks only if in previously received authStateWaitCode next_code_type was not null. Returns authStateWaitCode on success resendChangePhoneNumberCode = AuthState; //@description Checks authentication code sent to change user's phone number. Returns authStateOk on success @code Verification code from SMS, phone call or flash call checkChangePhoneNumberCode code:string = AuthState; //@description Returns all active sessions of logged in user getActiveSessions = Sessions; //@description Terminates another session of logged in user @session_id Session identifier terminateSession session_id:int64 = Ok; //@description Terminates all other sessions of logged in user terminateAllOtherSessions = Ok; //@description Gives or revokes all members of the group administrator rights. Needs creator privileges in the group @group_id Identifier of the group @everyone_is_administrator New value of everyone_is_administrator toggleGroupAdministrators group_id:int everyone_is_administrator:Bool = Ok; //@description Changes username of the channel. Needs creator privileges in the channel @channel_id Identifier of the channel @username New value of username. Use empty string to remove username changeChannelUsername channel_id:int username:string = Ok; //@description Changes sticker set of the channel. Needs appropriate rights in the channel @channel_id Identifier of the channel @sticker_set_id New value of channel sticker set identifier. Use 0 to remove channel sticker set setChannelStickerSet channel_id:int sticker_set_id:int64 = Ok; //@description Gives or revokes right to invite new members to all current members of the channel. Needs appropriate rights in the channel. Available only for supergroups @channel_id Identifier of the channel @anyone_can_invite New value of anyone_can_invite toggleChannelInvites channel_id:int anyone_can_invite:Bool = Ok; //@description Enables or disables sender signature on sent messages in the channel. Needs appropriate rights in the channel. Not available for supergroups @channel_id Identifier of the channel @sign_messages New value of sign_messages toggleChannelSignMessages channel_id:int sign_messages:Bool = Ok; //@description Changes information about the channel. Needs appropriate rights in the channel @channel_id Identifier of the channel @param_description New channel description, 0-255 characters changeChannelDescription channel_id:int description:string = Ok; //@description Pins a message in a supergroup channel chat. Needs appropriate rights in the channel @channel_id Identifier of the channel @message_id Identifier of the new pinned message @disable_notification True, if there should be no notification about the pinned message pinChannelMessage channel_id:int message_id:int53 disable_notification:Bool = Ok; //@description Removes pinned message in the supergroup channel. Needs appropriate rights in the channel @channel_id Identifier of the channel unpinChannelMessage channel_id:int = Ok; //@description Reports some supergroup channel messages from a user as spam messages @channel_id Channel identifier @user_id User identifier @message_ids Identifiers of messages sent in the supergroup by the user, the list should be non-empty reportChannelSpam channel_id:int user_id:int message_ids:vector = Ok; //@description Returns information about channel members or banned users. Can be used only if channel_full->can_get_members == true. Administrator privileges may be additionally needed for some filters @channel_id Identifier of the channel //@filter Kind of channel users to return, defaults to channelMembersRecent @offset Number of channel users to skip @limit Maximum number of users be returned, can't be greater than 200 getChannelMembers channel_id:int filter:ChannelMembersFilter offset:int limit:int = ChatMembers; //@description Deletes channel along with all messages in corresponding chat. Releases channel username and removes all members. Needs creator privileges in the channel. Channels with more than 1000 members can't be deleted @channel_id Identifier of the channel deleteChannel channel_id:int = Ok; //@description Closes secret chat, effectively transfering its state to "Closed" @secret_chat_id Secret chat identifier closeSecretChat secret_chat_id:int = Ok; //@description Returns list of service actions taken by chat members and administrators in the last 48 hours, available only in channels. Requires administrator rights. Returns result in reverse chronological order, i. e. in order of decreasing event_id //@chat_id Chat identifier @query Search query to filter events @from_event_id Identifier of an event from which to return result, you can use 0 to get results from the latest events @limit Maximum number of events to return, can't be greater than 100 //@filters Types of events to return, defaults to all @user_ids User identifiers, which events to return, defaults to all users getChatEventLog chat_id:int53 query:string from_event_id:int64 limit:int filters:chatEventLogFilters user_ids:vector = ChatEvents; //@description Returns invoice payment form. The method should be called when user presses inlineKeyboardButtonBuy @chat_id Chat identifier of the Invoice message @message_id Message identifier getPaymentForm chat_id:int53 message_id:int53 = PaymentForm; //@description Validates order information provided by the user and returns available shipping options for flexible invoice @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info Order information, provided by the user @allow_save True, if order information can be saved validateOrderInfo chat_id:int53 message_id:int53 order_info:orderInfo allow_save:Bool = ValidatedOrderInfo; //@description Sends filled payment form to the bot for the final verification @chat_id Chat identifier of the Invoice message @message_id Message identifier @order_info_id Identifier returned by ValidateOrderInfo or empty string @shipping_option_id Identifier of a chosen shipping option, if applicable //@credentials Credentials choosed by user for payment sendPaymentForm chat_id:int53 message_id:int53 order_info_id:string shipping_option_id:string credentials:InputCredentials = PaymentResult; //@description Returns information about successful payment @chat_id Chat identifier of the PaymentSuccessful message @message_id Message identifier getPaymentReceipt chat_id:int53 message_id:int53 = PaymentReceipt; //@description Returns saved order info if any getSavedOrderInfo = OrderInfo; //@description Deletes saved order info deleteSavedOrderInfo = Ok; //@description Deletes saved credentials for all payments provider bots deleteSavedCredentials = Ok; //@description Returns user that can be contacted to get support getSupportUser = User; //@description Returns background wallpapers getWallpapers = Wallpapers; //@description Registers current used device for receiving push notifications @device_token Device token registerDevice device_token:DeviceToken = Ok; //@description Changes privacy settings @key Privacy key @rules New privacy rules setPrivacy key:PrivacyKey rules:privacyRules = Ok; //@description Returns current privacy settings @key Privacy key getPrivacy key:PrivacyKey = PrivacyRules; //@description Returns value of an option by its name. See list of available options on https://core.telegram.org/tdlib/options. Can be called before authorization //@name Name of the option getOption name:string = OptionValue; //@description Sets value of an option. See list of available options on https://core.telegram.org/tdlib/options. Only writable options can be set. Can be called before authorization //@name Name of the option @value New value of the option setOption name:string value:OptionValue = Ok; //@description Changes period of inactivity, after which the account of currently logged in user will be automatically deleted @ttl New account TTL changeAccountTtl ttl:accountTtl = Ok; //@description Returns period of inactivity, after which the account of currently logged in user will be automatically deleted getAccountTtl = AccountTtl; //@description Deletes the account of currently logged in user, deleting from the server all information associated with it. Account's phone number can be used to create new account, but only once in two weeks @reason Optional reason of account deletion deleteAccount reason:string = Ok; //@description Returns current chat report spam state @chat_id Chat identifier getChatReportSpamState chat_id:int53 = ChatReportSpamState; //@description Reports chat as a spam chat or as not a spam chat. Can be used only if ChatReportSpamState.can_report_spam is true. After this request ChatReportSpamState.can_report_spam became false forever @chat_id Chat identifier @is_spam_chat If true, chat will be reported as a spam chat, otherwise it will be marked as not a spam chat changeChatReportSpamState chat_id:int53 is_spam_chat:Bool = Ok; //@description Reports chat to Telegram moderators. Can be used only for a channel chat or a private chat with a bot, because all other chats can't be checked by moderators @chat_id Chat identifier @reason Reason, the chat is reported reportChat chat_id:int53 reason:ChatReportReason = Ok; //@description Returns storage usage statistics @chat_limit Maximum number of chats with biggest storage usage for which separate statistics should be returned. All other chats will be grouped in entries with chat_id == 0. If chat info database is not used, chat_limit is ignored and is always set to 0 getStorageStatistics chat_limit:int = StorageStatistics; //@description Quickly returns approximate storage usage statistics getStorageStatisticsFast = StorageStatisticsFast; //@description Optimizes storage usage, i.e. deletes some files and return new storage usage statistics. Secret thumbnails can't be deleted //@size Limit on total size of files after deletion. Pass -1 to use default limit //@ttl Limit on time passed since last access time (or creation time on some filesystems) to a file. Pass -1 to use default limit //@count Limit on total count of files after deletion. Pass -1 to use default limit //@immunity_delay Number of seconds after creation of a file, it can't be delited. Pass -1 to use default value //@file_types If not empty, only files with given types are considered. By default, all types except thumbnails, profile photos, stickers and wallpapers are deleted //@chat_ids If not empty, only files from the given chats are considered. Use 0 as chat identifier to delete files not belonging to any chat, for example profile photos //@exclude_chat_ids If not empty, files from the given chats are exluded. Use 0 as chat identifier to exclude all files not belonging to any chat, for example profile photos //@chat_limit Same as in getStorageStatistics. Affects only returned statistics optimizeStorage size:int53 ttl:int count:int immunity_delay:int file_types:vector chat_ids:vector exclude_chat_ids:vector chat_limit:int = StorageStatistics; //@description Sets current network type. Can be called before authorization. Call to this method forces reopening of all network connections mitigating delay in switching between different networks, so it should be called whenever network is changed even network type remains the same. -Network type is used to check if library can use network at all and for collecting detailed network data usage statistics @type New network type, defaults to networkTypeNone setNetworkType type:NetworkType = Ok; //@description Returns network data usage statistics. Can be called before authorization @only_current If true, returns only data for the current library launch getNetworkStatistics only_current:Bool = NetworkStatistics; //@description Adds specified data to data usage statistics. Can be called before authorization @entry Network statistics entry with a data to add to statistics addNetworkStatistics entry:NetworkStatisticsEntry = Ok; //@description Resets all network data usage statistics to zero. Can be called before authorization resetNetworkStatistics = Ok; //@description Bots only. Informs server about number of pending bot updates if they aren't processed for a long time @pending_update_count Number of pending updates @error_message Last error's message setBotUpdatesStatus pending_update_count:int error_message:string = Ok; //@description Bots only. Uploads a png image with a sticker. Returns uploaded file @user_id Sticker file owner @png_sticker Png image with the sticker, must be up to 512 kilobytes in size and fit in 512x512 square uploadStickerFile user_id:int png_sticker:InputFile = File; //@description Bots only. Creates new sticker set. Returns created sticker set @user_id Sticker set owner @title Sticker set title, 1-64 characters @name Sticker set name. Can contain only english letters, digits and underscores. Should end on *"_by_"*. ** is case insensitive, 1-64 characters //@is_masks True, is stickers are masks @stickers List of stickers to add to the set createNewStickerSet user_id:int title:string name:string is_masks:Bool stickers:vector = StickerSet; //@description Bots only. Adds new sticker to a set. Returns the sticker set @user_id Sticker set owner @name Sticker set name @sticker Sticker to add to the set addStickerToSet user_id:int name:string sticker:inputSticker = StickerSet; //@description Bots only. Changes position of a sticker in the set it belongs to. Sticker set should be created by the bot @sticker The sticker @position New sticker position in the set, zero-based setStickerPositionInSet sticker:InputFile position:int = Ok; //@description Bots only. Deletes a sticker from the set it belongs to. Sticker set should be created by the bot @sticker The sticker deleteStickerFromSet sticker:InputFile = Ok; //@description Bots only. Sends custom request @method Method name @parameters JSON-serialized method parameters sendCustomRequest method:string parameters:string = CustomRequestResult; //@description Bots only. Answers a custom query @custom_query_id Identifier of a custom query @data JSON-serialized answer to the query answerCustomQuery custom_query_id:int64 data:string = Ok; //@description Returns Ok after specified amount of the time passed. Can be called before authorization @seconds Number of seconds before that function returns setAlarm seconds:double = Ok; //@description Returns invite text for invitation of new users getInviteText = Text; //@description Returns terms of service. Can be called before authorization getTermsOfService = Text; //@description Sets proxy server for network requests. Can be called before authorization @proxy The proxy to use. You can specify null to remove proxy server setProxy proxy:Proxy = Ok; //@description Returns current set up proxy. Can be called before authorization getProxy = Proxy; //@description Test request. Does nothing testCallEmpty = Ok; //@description Test request. Returns back received string @x String to return testCallString x:string = TestString; //@description Test request. Returns back received bytes @x Bytes to return testCallBytes x:bytes = TestBytes; //@description Test request. Returns back received vector of numbers @x Vector of numbers to return testCallVectorInt x:vector = TestVectorInt; //@description Test request. Returns back received vector of objects containing a number @x Vector of objects to return testCallVectorIntObject x:vector = TestVectorIntObject; //@description Test request. Returns back received vector of strings @x Vector of strings to return testCallVectorString x:vector = TestVectorString; //@description Test request. Returns back received vector of objects containing a string @x Vector of objects to return testCallVectorStringObject x:vector = TestVectorStringObject; //@description Test request. Returns squared received number @x Number to square testSquareInt x:int = TestInt; //@description Test request. Sends simple network request to telegram servers testNetwork = Ok; //@description Test request. Forces updates.getDifference call to telegram servers testGetDifference = Ok; //@description Test request. Does nothing, ensures that the Update object is used testUseUpdate = Update; //@description Test request. Does nothing, ensures that the Error object is used testUseError = Error; { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "270785512", "predicate": "inputPeerContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1690012891", "predicate": "inputPeerForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-2031530139", "predicate": "inputUserContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputUser" }, { "id": "1700689151", "predicate": "inputUserForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "767900285", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" } ], "type": "InputMedia" }, { "id": "-1893027092", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "322623222", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1726817601", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "2130852582", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "476112392", "predicate": "userSelf", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-894214632", "predicate": "userContact", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-640891665", "predicate": "userRequest", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "123533224", "predicate": "userForeign", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-704549510", "predicate": "userDeleted", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1855757255", "predicate": "chat", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "left", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-83047359", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "date", "type": "int" } ], "type": "Chat" }, { "id": "1661886910", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "265468810", "predicate": "chatParticipantsForbidden", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-1481959023", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "Message" }, { "id": "495384334", "predicate": "messageService", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "-926655958", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageMedia" }, { "id": "-1563278704", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "582313809", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "948937617", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-155815004", "predicate": "auth.authorization", "params": [ { "name": "expires", "type": "int" }, { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1997575642", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "real_first_name", "type": "string" }, { "name": "real_last_name", "type": "string" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "909233996", "predicate": "chatLocated", "params": [ { "name": "chat_id", "type": "int" }, { "name": "distance", "type": "int" } ], "type": "ChatLocated" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1062078024", "predicate": "messages.messageEmpty", "params": [], "type": "messages.Message" }, { "id": "131615560", "predicate": "messages.statedMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.StatedMessages" }, { "id": "-1776022422", "predicate": "messages.statedMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-1878086592", "predicate": "messages.sentMessage", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "777696872", "predicate": "updateReadMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-312729305", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" } ], "type": "Updates" }, { "id": "1378061116", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "784507964", "predicate": "dcOption", "params": [ { "name": "id", "type": "int" }, { "name": "hostname", "type": "string" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1047491370", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1371430169", "predicate": "messages.statedMessagesLinks", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "links", "type": "Vector" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessages" }, { "id": "155755144", "predicate": "messages.statedMessageLink", "params": [ { "name": "message", "type": "Message" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "links", "type": "Vector" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-383565811", "predicate": "messages.sentMessageLink", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "links", "type": "Vector" }, { "name": "seq", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "1960072954", "predicate": "inputGeoChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputGeoChat" }, { "id": "1301143240", "predicate": "inputNotifyGeoChatPeer", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "InputNotifyPeer" }, { "id": "1978329690", "predicate": "geoChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "venue", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "checked_in", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "1613830811", "predicate": "geoChatMessageEmpty", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" } ], "type": "GeoChatMessage" }, { "id": "1158019297", "predicate": "geoChatMessage", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "GeoChatMessage" }, { "id": "-749755826", "predicate": "geoChatMessageService", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "GeoChatMessage" }, { "id": "397498251", "predicate": "geochats.statedMessage", "params": [ { "name": "message", "type": "GeoChatMessage" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "seq", "type": "int" } ], "type": "geochats.StatedMessage" }, { "id": "1224651367", "predicate": "geochats.located", "params": [ { "name": "results", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "geochats.Located" }, { "id": "-783127119", "predicate": "geochats.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "geochats.Messages" }, { "id": "-1135057944", "predicate": "geochats.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "geochats.Messages" }, { "id": "1862504124", "predicate": "messageActionGeoChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "address", "type": "string" } ], "type": "MessageAction" }, { "id": "209540062", "predicate": "messageActionGeoChatCheckin", "params": [], "type": "MessageAction" }, { "id": "1516823543", "predicate": "updateNewGeoChatMessage", "params": [ { "name": "message", "type": "GeoChatMessage" } ], "type": "Update" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "974056226", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-945003370", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1845219337", "predicate": "sendMessageUploadVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-424899985", "predicate": "sendMessageUploadAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-1727382502", "predicate": "sendMessageUploadPhotoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1884362354", "predicate": "sendMessageUploadDocumentAction", "params": [], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "-360210539", "predicate": "contactFound", "params": [ { "name": "user_id", "type": "int" } ], "type": "ContactFound" }, { "id": "90570766", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1467017129", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" } ], "type": "account.Password" }, { "id": "1939758962", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" } ], "type": "account.Password" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "-1723033470", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "85215461", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-588304126", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-321970698", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1834885329", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "132772523", "method": "messages.search", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-1336990448", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "682347368", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "480793249", "method": "messages.sendMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "messages.SentMessage" }, { "id": "-51478592", "method": "messages.sendMedia", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "messages.StatedMessage" }, { "id": "-556523451", "method": "messages.forwardMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" } ], "type": "messages.StatedMessages" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-1262720843", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "messages.StatedMessage" }, { "id": "-662601187", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "messages.StatedMessage" }, { "id": "787082910", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-1010447069", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.StatedMessage" }, { "id": "1100847854", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "messages.StatedMessage" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1209117380", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "66319602", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "messages.StatedMessage" }, { "id": "1102776690", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "messages.StatedMessages" }, { "id": "2132356495", "method": "geochats.getLocated", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "radius", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Located" }, { "id": "-515735953", "method": "geochats.getRecents", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "1437853947", "method": "geochats.checkin", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "geochats.StatedMessage" }, { "id": "1730338159", "method": "geochats.getFullChat", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "messages.ChatFull" }, { "id": "1284383347", "method": "geochats.editChatTitle", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" } ], "type": "geochats.StatedMessage" }, { "id": "903355029", "method": "geochats.editChatPhoto", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "geochats.StatedMessage" }, { "id": "-808598451", "method": "geochats.search", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "-1254131096", "method": "geochats.getHistory", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "146319145", "method": "geochats.setTyping", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "102432836", "method": "geochats.sendMessage", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "geochats.StatedMessage" }, { "id": "-1192173825", "method": "geochats.sendMedia", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "geochats.StatedMessage" }, { "id": "235482646", "method": "geochats.createGeoChat", "params": [ { "name": "title", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "address", "type": "string" }, { "name": "venue", "type": "string" } ], "type": "geochats.StatedMessage" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "200282908", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-584430193", "method": "account.setPassword", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "new_password_hash", "type": "bytes" }, { "name": "hint", "type": "string" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" } ] }int ?= Int; long ?= Long; double ?= Double; string ?= String; bytes string = Bytes; int128 long long = Int128; int256 long long long long = Int256; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#f7aff1c0 file:InputFile caption:string = InputMedia; inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedVideo#82713fdf file:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia; inputMediaUploadedThumbVideo#7780ddf9 file:InputFile thumb:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia; inputMediaVideo#936a4ebd video:InputVideo caption:string = InputMedia; inputMediaUploadedAudio#4e498cab file:InputFile duration:int mime_type:string = InputMedia; inputMediaAudio#89938781 audio:InputAudio = InputMedia; inputMediaUploadedDocument#1d89306d file:InputFile mime_type:string attributes:Vector caption:string = InputMedia; inputMediaUploadedThumbDocument#ad613491 file:InputFile thumb:InputFile mime_type:string attributes:Vector caption:string = InputMedia; inputMediaDocument#1a77f29c document_id:InputDocument caption:string = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto; inputChatPhoto#b2e1bf08 id:InputPhoto crop:InputPhotoCrop = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 latitude:double longitude:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputVideoEmpty#5508ec75 = InputVideo; inputVideo#ee579652 id:long access_hash:long = InputVideo; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputVideoFileLocation#3d0364ec id:long access_hash:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation; inputPhotoCropAuto#ade6b004 = InputPhotoCrop; inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#4b1b7506 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat; channelForbidden#2d85832c id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#9e341ddf flags:# can_view_participants:flags.3?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#c992e15c flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int = Message; messageService#c06b9607 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaVideo#5bcf1675 video:Video caption:string = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaAudio#c6b68300 audio:Audio = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog; dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog; photoEmpty#2331b22d id:long = Photo; photo#cded42fe id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; videoEmpty#c10658a8 id:long = Video; video#f72887d3 id:long access_hash:long date:int duration:int mime_type:string size:int thumb:PhotoSize dc_id:int w:int h:int = Video; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c longitude:double latitude:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode; auth.sentAppCode#e325edcf phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode; auth.authorization#ff036af1 user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#46a2ce98 mute_until:int sound:string show_previews:Bool events_mask:int = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool events_mask:int = PeerNotifySettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#5a89ac5b user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool bot_info:BotInfo = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; contacts.importedContacts#ad524315 imported:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; contacts.suggested#5649dcc5 results:Vector users:Vector = contacts.Suggested; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#bc0f17bc flags:# pts:int count:int messages:Vector collapsed:flags.0?Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterAudio#cfc87522 = MessagesFilter; inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewAuthorization#8f06529a auth_key_id:long date:int device:string location:string = Update; updateNewEncryptedMessage#12bcbd9a encr_message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d encr_chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef notify_peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#382dd3e4 type:string message_text:string media:MessageMedia popup:Bool = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#60946422 channel_id:int = Update; updateChannel#b6d45656 channel_id:int = Update; updateChannelGroup#c36c1e3c channel_id:int group:MessageGroup = Update; updateNewChannelMessage#62ba04d9 message:Message channel_pts:int channel_pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector channel_pts:int channel_pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#f0dfb451 order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#c01eea08 query_id:long user_id:int query:string offset:string = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#13e4deaa flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#248afa62 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# unread:flags.0?true out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true id:int ip_address:string port:int = DcOption; config#6bbc5f8 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputAudioEmpty#d95adc84 = InputAudio; inputAudio#77d440ff id:long access_hash:long = InputAudio; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; audioEmpty#586988d8 id:long = Audio; audio#f9e35055 id:long access_hash:long date:int duration:int mime_type:string size:int dc_id:int = Audio; documentEmpty#36f8c871 id:long = Document; document#f9a39f4f id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; account.sentChangePhoneCode#a4f58c4c phone_code_hash:string send_call_timeout:int = account.SentChangePhoneCode; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute; documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#ca820ed7 flags:# id:long url:string display_url:string type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#bcfc532c flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true disabled:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfoEmpty#bb2e37ce = BotInfo; botInfo#9cf585d user_id:int version:int share_text:string description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; help.appChangelogEmpty#af7e0394 = help.AppChangelog; help.appChangelog#4668e6bd text:string = help.AppChangelog; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; messageGroup#e8346f53 min_id:int max_id:int count:int date:int = MessageGroup; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true channel_pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#5e167646 flags:# final:flags.0?true channel_pts:int timeout:flags.1?int top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true channel_pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# important_only:flags.0?true exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole; channelRoleEditor#820bfe8c = ChannelParticipantRole; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#2e43e587 caption:string = InputBotInlineMessage; inputBotInlineMessageText#adf0df71 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#fc56e87d caption:string = BotInlineMessage; botInlineMessageText#a56197a9 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector = BotInlineMessage; botInlineMediaResultDocument#f897d33e id:string type:string document:Document send_message:BotInlineMessage = BotInlineResult; botInlineMediaResultPhoto#c5528587 id:string type:string photo:Photo send_message:BotInlineMessage = BotInlineResult; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; messages.botResults#1170b0a3 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string results:Vector = messages.BotResults; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#768d5f4d phone_number:string sms_type:int api_id:int api_hash:string lang_code:string = auth.SentCode; auth.sendCall#3c51564 phone_number:string phone_code_hash:string = Bool; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.sendSms#da9f3e8 phone_number:string phone_code_hash:string = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; account.registerDevice#446c712c token_type:int token:string device_model:string system_version:string app_version:string app_sandbox:Bool lang_code:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#f0888d68 first_name:string last_name:string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#a407a8f4 phone_number:string = account.SentChangePhoneCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; contacts.getSuggested#cd773428 limit:int = contacts.Suggested; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#6b47f94d offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#8a8ec2da peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#d4569248 flags:# important_only:flags.0?true peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#b7c13bd9 peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#a5f18925 id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# broadcast:flags.4?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.sendBroadcast#bf73f4da contacts:Vector random_id:Vector message:string media:InputMedia = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#9fcfbc30 order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#9324600d bot:InputUser query:string offset:string = messages.BotResults; messages.setInlineBotResults#3f23ec12 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string = Bool; messages.sendInlineBotResult#b16e06fe flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; updates.getChannelDifference#bb32d7c0 channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#eef579a0 id:InputPhoto crop:InputPhotoCrop = UserProfilePhoto; photos.uploadProfilePhoto#d50f9c88 file:InputFile caption:string geo_point:InputGeoPoint crop:InputPhotoCrop = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#c812ac7e device_model:string system_version:string app_version:string lang_code:string = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#a4a95186 lang_code:string = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#5bab7fb2 device_model:string system_version:string app_version:string lang_code:string = help.AppChangelog; help.getTermsOfService#37d78f83 lang_code:string = help.TermsOfService; channels.getDialogs#a9d3d249 offset:int limit:int = messages.Dialogs; channels.getImportantHistory#ddb929cb channel:InputChannel offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.toggleComments#aaa29e88 channel:InputChannel enabled:Bool = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "270785512", "predicate": "inputPeerContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1690012891", "predicate": "inputPeerForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-2031530139", "predicate": "inputUserContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputUser" }, { "id": "1700689151", "predicate": "inputUserForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "767900285", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" } ], "type": "InputMedia" }, { "id": "-1893027092", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "322623222", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1726817601", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "2130852582", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "476112392", "predicate": "userSelf", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-894214632", "predicate": "userContact", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-640891665", "predicate": "userRequest", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "123533224", "predicate": "userForeign", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-704549510", "predicate": "userDeleted", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1855757255", "predicate": "chat", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "left", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-83047359", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "date", "type": "int" } ], "type": "Chat" }, { "id": "1661886910", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "265468810", "predicate": "chatParticipantsForbidden", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-1481959023", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "Message" }, { "id": "495384334", "predicate": "messageService", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "-926655958", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageMedia" }, { "id": "-1563278704", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "582313809", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "948937617", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-155815004", "predicate": "auth.authorization", "params": [ { "name": "expires", "type": "int" }, { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1997575642", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "real_first_name", "type": "string" }, { "name": "real_last_name", "type": "string" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "909233996", "predicate": "chatLocated", "params": [ { "name": "chat_id", "type": "int" }, { "name": "distance", "type": "int" } ], "type": "ChatLocated" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1062078024", "predicate": "messages.messageEmpty", "params": [], "type": "messages.Message" }, { "id": "1279084531", "predicate": "messages.sentMessage", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "MessageMedia" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "777696872", "predicate": "updateReadMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-312729305", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" } ], "type": "Updates" }, { "id": "1378061116", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "784507964", "predicate": "dcOption", "params": [ { "name": "id", "type": "int" }, { "name": "hostname", "type": "string" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1757069895", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "899786339", "predicate": "messages.sentMessageLink", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "MessageMedia" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "links", "type": "Vector" }, { "name": "seq", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "1960072954", "predicate": "inputGeoChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputGeoChat" }, { "id": "1301143240", "predicate": "inputNotifyGeoChatPeer", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "InputNotifyPeer" }, { "id": "1978329690", "predicate": "geoChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "venue", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "checked_in", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "1613830811", "predicate": "geoChatMessageEmpty", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" } ], "type": "GeoChatMessage" }, { "id": "1158019297", "predicate": "geoChatMessage", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "GeoChatMessage" }, { "id": "-749755826", "predicate": "geoChatMessageService", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "GeoChatMessage" }, { "id": "397498251", "predicate": "geochats.statedMessage", "params": [ { "name": "message", "type": "GeoChatMessage" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "seq", "type": "int" } ], "type": "geochats.StatedMessage" }, { "id": "1224651367", "predicate": "geochats.located", "params": [ { "name": "results", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "geochats.Located" }, { "id": "-783127119", "predicate": "geochats.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "geochats.Messages" }, { "id": "-1135057944", "predicate": "geochats.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "geochats.Messages" }, { "id": "1862504124", "predicate": "messageActionGeoChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "address", "type": "string" } ], "type": "MessageAction" }, { "id": "209540062", "predicate": "messageActionGeoChatCheckin", "params": [], "type": "MessageAction" }, { "id": "1516823543", "predicate": "updateNewGeoChatMessage", "params": [ { "name": "message", "type": "GeoChatMessage" } ], "type": "Update" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "974056226", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-945003370", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1845219337", "predicate": "sendMessageUploadVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-424899985", "predicate": "sendMessageUploadAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-1727382502", "predicate": "sendMessageUploadPhotoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1884362354", "predicate": "sendMessageUploadDocumentAction", "params": [], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "-360210539", "predicate": "contactFound", "params": [ { "name": "user_id", "type": "int" } ], "type": "ContactFound" }, { "id": "90570766", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "-1723033470", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "85215461", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-588304126", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "751004017", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-1558273867", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-321970698", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1834885329", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "132772523", "method": "messages.search", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-1336990448", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "682347368", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-1696755930", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "messages.SentMessage" }, { "id": "762913713", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "1440838285", "method": "messages.forwardMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" } ], "type": "Updates" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1209117380", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "2132356495", "method": "geochats.getLocated", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "radius", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Located" }, { "id": "-515735953", "method": "geochats.getRecents", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "1437853947", "method": "geochats.checkin", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "geochats.StatedMessage" }, { "id": "1730338159", "method": "geochats.getFullChat", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "messages.ChatFull" }, { "id": "1284383347", "method": "geochats.editChatTitle", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" } ], "type": "geochats.StatedMessage" }, { "id": "903355029", "method": "geochats.editChatPhoto", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "geochats.StatedMessage" }, { "id": "-808598451", "method": "geochats.search", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "-1254131096", "method": "geochats.getHistory", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "146319145", "method": "geochats.setTyping", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "102432836", "method": "geochats.sendMessage", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "geochats.StatedMessage" }, { "id": "-1192173825", "method": "geochats.sendMedia", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "geochats.StatedMessage" }, { "id": "235482646", "method": "geochats.createGeoChat", "params": [ { "name": "title", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "address", "type": "string" }, { "name": "venue", "type": "string" } ], "type": "geochats.StatedMessage" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "200282908", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" } ] }. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; interface Proxy { public function __construct(int $domain, int $type, int $protocol); public function setOption(int $level, int $name, $value); public function getOption(int $level, int $name); public function setBlocking(bool $blocking); public function bind(string $address, int $port = 0); public function listen(int $backlog = 0); public function accept(); public function connect(string $address, int $port = 0); public function read(int $length, int $flags = 0); public function write(string $buffer, int $length = -1); public function send(string $data, int $length, int $flags); public function close(); public function getPeerName(bool $port = true); public function getSockName(bool $port = true); public function getProxyHeaders(); public function setExtra(array $extra = []); public function getResource(); } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Async; /** * Async parameters class. * * Manages asynchronous generation of method parameters * * @author Daniil Gentili */ class AsyncParameters extends Parameters { private $callable; private $refetchable = true; public function __construct(callable $callable, bool $refetchable = true) { $this->callable = $callable; $this->refetchable = $refetchable; } public function setRefetchable(bool $refetchable) { $this->refetchable = $refetchable; } public function setCallable(callable $callable) { $this->callable = $callable; } public function isRefetchable(): bool { return $this->refetchable; } public function getParameters() { $callable = $this->callable; return yield $callable(); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Async; use danog\MadelineProto\Tools; /** * Async constructor class. * * Manages asynchronous construction and wakeup of classes * * @author Daniil Gentili */ class AsyncConstruct { use Tools; public $asyncInitPromise; public function init() { if ($this->asyncInitPromise) { $this->wait($this->asyncInitPromise); } } public function initAsync() { if ($this->asyncInitPromise) { yield $this->asyncInitPromise; } } public function setInitPromise($promise) { $this->asyncInitPromise = $this->callFork($promise); $this->asyncInitPromise->onResolve(function ($error, $result) { if ($error) { throw $error; } $this->asyncInitPromise = null; }); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Async; use Amp\Promise; /** * Parameters module. * * Manages asynchronous generation of method parameters * * @author Daniil Gentili */ abstract class Parameters { private $params = []; /** * Fetch parameters asynchronously. * * @return Promise */ public function fetchParameters() { $refetchable = $this->isRefetchable(); if ($this->params && !$refetchable) { return $this->params; } $params = yield $this->getParameters(); if (!$refetchable) { $this->params = $params; } return $params; } /** * Check if the parameters can be fetched more than once. * * @return bool */ abstract public function isRefetchable(): bool; /** * Gets the parameters asynchronously. * * @return \Generator */ abstract public function getParameters(); } // Core types (no need to gen) //vector#1cb5c415 {t:Type} # [ t ] = Vector t; /////////////////////////////// /////////////////// Layer cons /////////////////////////////// //invokeAfterMsg#cb9f372d msg_id:long query:!X = X; //invokeAfterMsgs#3dc4b4f0 msg_ids:Vector query:!X = X; //invokeWithLayer1#53835315 query:!X = X; //invokeWithLayer2#289dd1f6 query:!X = X; //invokeWithLayer3#b7475268 query:!X = X; //invokeWithLayer4#dea0d430 query:!X = X; //invokeWithLayer5#417a57ae query:!X = X; //invokeWithLayer6#3a64d54d query:!X = X; //invokeWithLayer7#a5be56d3 query:!X = X; //invokeWithLayer8#e9abd9fd query:!X = X; //invokeWithLayer9#76715a63 query:!X = X; //invokeWithLayer10#39620c41 query:!X = X; //invokeWithLayer11#a6b88fdf query:!X = X; //invokeWithLayer12#dda60d3c query:!X = X; //invokeWithLayer13#427c8ea2 query:!X = X; //invokeWithLayer14#2b9b08fa query:!X = X; //invokeWithLayer15#b4418b64 query:!X = X; //invokeWithLayer16#cf5f0987 query:!X = X; //invokeWithLayer17#50858a19 query:!X = X; //invokeWithLayer18#1c900537 query:!X = X; //invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer /////////////////////////////// /// Authorization key creation /////////////////////////////// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ////////////// System messages /////////////////////////////// ---types--- msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; //message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually //msg_container#73f1f8dc messages:vector = MessageContainer; // parsed manually //msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container //gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ipPort ipv4:int port:int = IpPort; help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector = help.ConfigSimple; ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#e39621fd flags:# file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#cb44b1c flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#95cb5f57 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#90dddc11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#b5223b0f flags:# photo:flags.0?Photo caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; dialog#66ffba14 flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; config#7feec888 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#410dee07 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#fadff4ac flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#f288a275 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector; // LAYER 70 . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class SecurityException extends \Exception { } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class EventHandler extends APIFactory { public function __construct($MadelineProto) { $this->API = $MadelineProto->API; $this->async = &$MadelineProto->async; $this->methods = &$MadelineProto->methods; foreach ($this->API->get_method_namespaces() as $namespace) { $this->{$namespace} = new APIFactory($namespace, $this->API, $this->async); } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class RPCErrorException extends \Exception { use TL\PrettyException; private $fetched = false; public static $rollbar = true; public function getMess() { if ($this->fetched === false) { $res = json_decode(@file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$additional[0].'&code='.$code.'&error='.$this->rpc), true); if (isset($res['ok']) && $res['ok']) { $this->message = $res['result']; } } return $this->message; } public function __toString() { $result = sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], $this->getMess(), $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL; if (php_sapi_name() !== 'cli') { $result = str_replace(PHP_EOL, '
'.PHP_EOL, $result); } return $result; } public function __construct($message = null, $code = 0, $caller = '', Exception $previous = null) { $this->rpc = $message; switch ($message) { case 'RPC_MCGET_FAIL': case 'RPC_CALL_FAIL': $message = 'Telegram is having internal issues, please try again later.'; break; case 'USER_PRIVACY_RESTRICTED': $message = "The user's privacy settings do not allow you to do this"; break; case 'CHANNEL_PRIVATE': $message = "You haven't joined this channel/supergroup"; break; case 'FLOOD_WAIT_666': $message = 'Spooky af m8'; break; case 'USER_IS_BOT': $message = "Bots can't send messages to other bots"; break; case 'BOT_METHOD_INVALID': $message = 'This method cannot be run by a bot'; break; case 'PHONE_CODE_EXPIRED': $message = 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)'; break; case 'USERNAME_INVALID': $message = 'The provided username is not valid'; break; case 'ACCESS_TOKEN_INVALID': $message = 'The provided token is not valid'; break; case 'ACTIVE_USER_REQUIRED': $message = 'The method is only available to already activated users'; break; case 'FIRSTNAME_INVALID': $message = 'The first name is invalid'; break; case 'LASTNAME_INVALID': $message = 'The last name is invalid'; break; case 'PHONE_NUMBER_INVALID': $message = 'The phone number is invalid'; break; case 'PHONE_CODE_HASH_EMPTY': $message = 'phone_code_hash is missing'; break; case 'PHONE_CODE_EMPTY': $message = 'phone_code is missing'; break; case 'PHONE_CODE_EXPIRED': $message = 'The confirmation code has expired'; break; case 'API_ID_INVALID': $message = 'The api_id/api_hash combination is invalid'; break; case 'PHONE_NUMBER_OCCUPIED': $message = 'The phone number is already in use'; break; case 'PHONE_NUMBER_UNOCCUPIED': $message = 'The phone number is not yet being used'; break; case 'USERS_TOO_FEW': $message = 'Not enough users (to create a chat, for example)'; break; case 'USERS_TOO_MUCH': $message = 'The maximum number of users has been exceeded (to create a chat, for example)'; break; case 'TYPE_CONSTRUCTOR_INVALID': $message = 'The type constructor is invalid'; break; case 'FILE_PART_INVALID': $message = 'The file part number is invalid'; break; case 'FILE_PARTS_INVALID': $message = 'The number of file parts is invalid'; break; case 'MD5_CHECKSUM_INVALID': $message = 'The MD5 checksums do not match'; break; case 'PHOTO_INVALID_DIMENSIONS': $message = 'The photo dimensions are invalid'; break; case 'FIELD_NAME_INVALID': $message = 'The field with the name FIELD_NAME is invalid'; break; case 'FIELD_NAME_EMPTY': $message = 'The field with the name FIELD_NAME is missing'; break; case 'MSG_WAIT_FAILED': $message = 'A waiting call returned an error'; break; case 'USERNAME_NOT_OCCUPIED': $message = 'The provided username is not occupied'; break; case 'PHONE_NUMBER_BANNED': $message = 'The provided phone number is banned from telegram'; break; case 'AUTH_KEY_UNREGISTERED': $message = 'The authorization key has expired'; break; case 'INVITE_HASH_EXPIRED': $message = 'The invite link has expired'; break; case 'USER_DEACTIVATED': $message = 'The user was deactivated'; break; case 'USER_ALREADY_PARTICIPANT': $message = 'The user is already in the group'; break; case 'MESSAGE_ID_INVALID': $message = 'The provided message id is invalid'; break; case 'PEER_ID_INVALID': $message = 'The provided peer id is invalid'; break; case 'CHAT_ID_INVALID': $message = 'The provided chat id is invalid'; break; case 'MESSAGE_DELETE_FORBIDDEN': $message = "You can't delete one of the messages you tried to delete, most likely because it is a service message."; break; case 'CHAT_ADMIN_REQUIRED': $message = 'You must be an admin in this chat to do this'; break; case -429: case 'PEER_FLOOD': $message = 'Too many requests'; break; } parent::__construct($message, $code, $previous); $this->prettify_tl($caller); $additional = []; foreach ($this->getTrace() as $level) { if (isset($level['function']) && $level['function'] === 'method_call') { $this->line = $level['line']; $this->file = $level['file']; $additional = $level['args']; break; } } if ($this->rpc !== $message) { $this->fetched = true; } if (!self::$rollbar || !class_exists('\\Rollbar\\Rollbar')) { return; } if (in_array($this->rpc, ['CHANNEL_PRIVATE', -404, -429, 'USERNAME_NOT_OCCUPIED', 'ACCESS_TOKEN_INVALID', 'AUTH_KEY_UNREGISTERED', 'SESSION_PASSWORD_NEEDED', 'PHONE_NUMBER_UNOCCUPIED', 'PEER_ID_INVALID', 'CHAT_ID_INVALID', 'USERNAME_INVALID', 'CHAT_WRITE_FORBIDDEN', 'CHAT_ADMIN_REQUIRED', 'PEER_FLOOD'])) { return; } if (strpos($this->rpc, 'FLOOD_WAIT_') !== false) { return; } $message === 'Telegram is having internal issues, please try again later.' ? \Rollbar\Rollbar::log(\Rollbar\Payload\Level::critical(), $message) : \Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, $additional); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use danog\MadelineProto\Async\AsyncConstruct; class APIFactory extends AsyncConstruct { /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var langpack */ public $langpack; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var phone */ public $phone; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var stickers */ public $stickers; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var payments */ public $payments; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var bots */ public $bots; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var channels */ public $channels; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var help */ public $help; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var upload */ public $upload; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var photos */ public $photos; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var updates */ public $updates; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var messages */ public $messages; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var contacts */ public $contacts; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var users */ public $users; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var account */ public $account; /** * @internal this is a internal property generated by build_docs.php, don't change manually * * @var auth */ public $auth; use Tools; public $namespace = ''; public $API; public $lua = false; public $async = false; public $asyncAPIPromise; protected $methods = []; public function __construct($namespace, &$API, &$async) { $this->namespace = $namespace.'.'; $this->API = &$API; $this->async = &$async; } public function __call($name, $arguments) { $yielded = $this->call($this->__call_async($name, $arguments)); $async = $this->lua === false && (is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop')); if ($async) { return $yielded; } if (!$this->lua) { return $this->wait($yielded); } try { $yielded = $this->wait($yielded); Lua::convert_objects($yielded); return $yielded; } catch (\Throwable $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } } public function __call_async($name, $arguments) { if ($this->asyncInitPromise) { yield $this->initAsync(); $this->API->logger->logger('Finished init asynchronously'); } if (Magic::is_fork() && !Magic::$processed_fork) { throw new Exception('Forking not supported, use async logic, instead: https://docs.madelineproto.xyz/docs/ASYNC.html'); } if (!$this->API) { throw new Exception('API did not init!'); } if ($this->API->asyncInitPromise) { yield $this->API->initAsync(); $this->API->logger->logger('Finished init asynchronously'); } if (isset($this->session) && !is_null($this->session) && time() - $this->serialized > $this->API->settings['serialization']['serialization_interval']) { Logger::log("Didn't serialize in a while, doing that now..."); $this->serialize($this->session); } if ($this->API->setdem) { $this->API->setdem = false; $this->API->__construct($this->API->settings); yield $this->API->initAsync(); } if ($this->API->asyncInitPromise) { yield $this->API->initAsync(); $this->API->logger->logger('Finished init asynchronously'); } $lower_name = strtolower($name); if ($this->namespace !== '' || !isset($this->methods[$lower_name])) { $name = $this->namespace.$name; $aargs = isset($arguments[1]) && is_array($arguments[1]) ? $arguments[1] : []; $aargs['apifactory'] = true; $aargs['datacenter'] = $this->API->datacenter->curdc; $args = isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : []; return yield $this->API->method_call_async_read($name, $args, $aargs); } else { return yield $this->methods[$lower_name](...$arguments); } } public function &__get($name) { if ($this->asyncAPIPromise) { $this->wait($this->asyncAPIPromise); } if ($name === 'settings') { $this->API->setdem = true; return $this->API->settings; } if ($name === 'logger') { return $this->API->logger; } return $this->API->storage[$name]; } public function __set($name, $value) { if ($this->asyncAPIPromise) { $this->wait($this->asyncAPIPromise); } if ($name === 'settings') { if ($this->API->asyncInitPromise) { $this->API->init(); } return $this->API->__construct(array_replace_recursive($this->API->settings, $value)); } return $this->API->storage[$name] = $value; } public function __isset($name) { if ($this->asyncAPIPromise) { $this->wait($this->asyncAPIPromise); } return isset($this->API->storage[$name]); } public function __unset($name) { if ($this->asyncAPIPromise) { $this->wait($this->asyncAPIPromise); } unset($this->API->storage[$name]); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class RSA { use \danog\MadelineProto\TL\TL; use \danog\MadelineProto\Tools; use \danog\Serializable; public $e; public $n; public $fp; public function load($rsa_key) { \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_init'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['loading_key'], Logger::ULTRA_VERBOSE); $key = \phpseclib\Crypt\RSA::load($rsa_key); $this->n = self::getVar($key, 'modulus'); $this->e = self::getVar($key, 'exponent'); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE); $this->fp = substr(sha1((yield $this->serialize_object_async(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield $this->serialize_object_async(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8); return $this; } public function __sleep() { return ['e', 'n', 'fp']; } public function encrypt($data) { \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE); return (new \phpseclib\Math\BigInteger($data, 256))->powMod($this->e, $this->n)->toBytes(); } /** * Accesses a private variable from an object * * @param object $obj * @param string $var * @return mixed * @access public */ public static function getVar($obj, $var) { $reflection = new \ReflectionClass(get_class($obj)); $prop = $reflection->getProperty($var); $prop->setAccessible(true); return $prop->getValue($obj); } } /////////////////////////////// /// Authorization key creation /////////////////////////////// //resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector = ResPQ; //p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; //server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; //server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; //server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; //client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; //dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; //dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; //dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- //req_pq#60469778 nonce:int128 = ResPQ; //req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; //set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#630c9af1 flags:# file:InputFile caption:string stickers:flags.0?Vector = InputMedia; inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#d070f1e9 flags:# file:InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector = InputMedia; inputMediaUploadedThumbDocument#50d88cae flags:# file:InputFile thumb:InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector = InputMedia; inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia; inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#a14dca52 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat; channelForbidden#8537784f flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#c3d5512f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#c09be45f flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; dialog#66ffba14 flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; contacts.importedContacts#ad524315 imported:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true id:int ip_address:string port:int = DcOption; config#3af6fb5f flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; help.appChangelogEmpty#af7e0394 = help.AppChangelog; help.appChangelog#2a137e7c message:string media:MessageMedia entities:Vector = help.AppChangelog; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#410dee07 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole; channelRoleEditor#820bfe8c = ChannelParticipantRole; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#c786ddcb flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pagePart#8dee6c44 blocks:Vector photos:Vector videos:Vector = Page; pageFull#d7a19d69 blocks:Vector photos:Vector videos:Vector = Page; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#6c448ae8 id:long access_hash:long date:int admin_id:int participant_id:int g_a:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#d4569248 flags:# peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#b921197a = help.AppChangelog; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; phone.requestCall#a41aa5e4 user_id:InputUser random_id:int g_a:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#220f0b20 peer:InputPhoneCall g_b:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.discardCall#5dfbcddc peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Bool; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; // LAYER 62 . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Lua { use \danog\Serializable; public $MadelineProto; protected $Lua; protected $script; public function __magic_construct($script, $MadelineProto) { if (!file_exists($script)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['script_not_exist']); } $this->MadelineProto = $MadelineProto; $this->MadelineProto->settings['updates']['handle_updates'] = true; $this->MadelineProto->API->datacenter->sockets[$this->MadelineProto->settings['connection_settings']['default_dc']]->startUpdateLoop(); $this->script = $script; $this->__wakeup(); } public function __sleep() { return ['MadelineProto', 'script']; } public function __wakeup() { $this->Lua = new \Lua($this->script); $this->madelineproto_lua = 1; $this->Lua->registerCallback('tdcli_function', [$this, 'tdcli_function']); $this->Lua->registerCallback('madeline_function', [$this, 'madeline_function']); $this->Lua->registerCallback('var_dump', 'var_dump'); foreach (get_class_methods($this->MadelineProto->API) as $method) { $this->Lua->registerCallback($method, [$this->MadelineProto, $method]); } $methods = []; foreach ($this->MadelineProto->get_methods_namespaced() as $pair) { $namespace = key($pair); $method = $pair[$namespace]; if ($namespace === 'upload') { continue; } $methods[$namespace][$method] = [$this->MadelineProto->{$namespace}, $method]; } foreach ($this->MadelineProto->get_methods_namespaced() as $pair) { $namespace = key($pair); $method = $pair[$namespace]; if ($namespace === 'upload') { continue; } $this->{$namespace} = $methods[$namespace]; } $this->MadelineProto->lua = true; foreach ($this->MadelineProto->get_methods_namespaced() as $pair) { $namespace = key($pair); $this->MadelineProto->{$namespace}->lua = true; } } public function tdcli_function($params, $cb = null, $cb_extra = null) { $params = $this->MadelineProto->td_to_mtproto($this->MadelineProto->tdcli_to_td($params)); if ($params === 0) { return 0; } $result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]); if (is_callable($cb)) { $cb($this->MadelineProto->mtproto_to_td($result), $cb_extra); } return $result; } public function madeline_function($params, $cb = null, $cb_extra = null) { $result = $this->MadelineProto->API->method_call($params['_'], $params, ['datacenter' => $this->MadelineProto->API->datacenter->curdc]); if (is_callable($cb)) { $cb($result, $cb_extra); } self::convert_objects($result); return $result; } public function tdcli_update_callback($update) { $this->Lua->tdcli_update_callback($this->MadelineProto->mtproto_to_tdcli($update)); } private function convert_array($array) { if (!is_array($array)) { return $array; } if ($this->is_seqential($array)) { return array_flip(array_map(function ($el) { return $el + 1; }, array_flip($array))); } } private function is_sequential(array $arr) { if ([] === $arr) { return false; } return isset($arr[0]) && array_keys($arr) === range(0, count($arr) - 1); } public function __get($name) { if ($name === 'API') { return $this->MadelineProto->API; } return $this->Lua->{$name}; } public function __call($name, $params) { self::convert_objects($params); try { return $this->Lua->{$name}(...$params); } catch (\danog\MadelineProto\RPCErrorException $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } catch (\danog\MadelineProto\Exception $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } catch (\danog\MadelineProto\TL\Exception $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } catch (\danog\MadelineProto\NothingInTheSocketException $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } catch (\danog\MadelineProto\PTSException $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } catch (\danog\MadelineProto\SecurityException $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } catch (\danog\MadelineProto\TL\Conversion\Exception $e) { return ['error_code' => $e->getCode(), 'error' => $e->getMessage()]; } } public function __set($name, $value) { return $this->Lua->{$name} = $value; } public static function convert_objects(&$data) { array_walk_recursive($data, function (&$value, $key) { if (is_object($value) && !$value instanceof \phpseclib\Math\BigInteger) { $newval = []; foreach (get_class_methods($value) as $name) { $newval[$name] = [$value, $name]; } foreach ($value as $key => $name) { if ($key === 'madeline') { continue; } $newval[$key] = $name; } if ($newval === []) { $newval = $value->__toString(); } $value = $newval; } }); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; /* * Controls script shutdown */ class Shutdown { /** * Callbacks to call on shutdown * * @var array */ private static $callbacks = []; /** * Whether the main shutdown was registered * * @var boolean */ private static $registered = false; /** * Incremental ID for new callback * * @var integer */ private static $id = 0; /** * Function to be called on shutdown * * @return void */ public static function shutdown() { foreach (self::$callbacks as $callback) { $callback(); } } /** * Add a callback for script shutdown * * @param callable $callback The callback to set * @param null|string $id The optional callback ID * * @return The callback ID */ public static function addCallback($callback, $id = null) { if (!$id) { $id = self::$id++; } self::$callbacks[$id] = $callback; if (!self::$registered) { register_shutdown_function([__CLASS__, 'shutdown']); self::$registered = true; } return $id; } /** * Remove a callback from the script shutdown callable list * * @param null|string $id The optional callback ID * * @return bool true if the callback was removed correctly, false otherwise */ public static function removeCallback($id) { if (isset(self::$callbacks[$id])) { unset(self::$callbacks[$id]); return true; } return false; } }. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { /** * Manages storage of VoIP server config. */ class VoIPServerConfig extends VoIPServerConfigInternal { /** * The configuration. * * @var array */ private static $_config = []; /** * The default configuration. * * @var array */ private static $_configDefault = []; /** * Update shared call settings. * * @param array $config The settings * * @return void */ public static function update(array $config) { self::$_config = $config; self::updateInternal(self::getFinal()); } /** * Get shared call settings. * * @return array The settings */ public static function get(): array { return self::$_config; } /** * Update default shared call settings. * * @param array $configDefault The settings * * @return void */ public static function updateDefault(array $configDefault) { self::$_configDefault = $configDefault; self::updateInternal(self::getFinal()); } /** * Get default shared call settings. * * @return array The settings */ public static function getDefault(): array { return self::$_configDefault; } /** * Get final settings. * * @return void */ public static function getFinal(): array { return array_merge(self::$_configDefault, self::$_config); } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\DoH\DoHConfig; use Amp\DoH\Nameserver; use Amp\DoH\Rfc8484StubResolver; use Amp\Loop; use function Amp\Dns\resolver; use function Amp\Promise\wait; class Magic { public static $storage = []; public static $has_thread = false; public static $BIG_ENDIAN = false; public static $bigint = true; public static $isatty = false; public static $is_fork = false; public static $can_getmypid = true; public static $can_parallel = false; public static $can_getcwd = false; public static $processed_fork = false; public static $ipv6; public static $pid; public static $inited = false; public static $zero; public static $one; public static $two; public static $three; public static $four; public static $twoe1984; public static $twoe2047; public static $twoe2048; public static $zeroeight; public static $twozerotwosixone; public static $emojis; public static $revision; public static $cwd; public static $script_cwd; public static $altervista = false; const JSON_EMOJIS = '["\\ud83d\\ude09","\\ud83d\\ude0d","\\ud83d\\ude1b","\\ud83d\\ude2d","\\ud83d\\ude31","\\ud83d\\ude21","\\ud83d\\ude0e","\\ud83d\\ude34","\\ud83d\\ude35","\\ud83d\\ude08","\\ud83d\\ude2c","\\ud83d\\ude07","\\ud83d\\ude0f","\\ud83d\\udc6e","\\ud83d\\udc77","\\ud83d\\udc82","\\ud83d\\udc76","\\ud83d\\udc68","\\ud83d\\udc69","\\ud83d\\udc74","\\ud83d\\udc75","\\ud83d\\ude3b","\\ud83d\\ude3d","\\ud83d\\ude40","\\ud83d\\udc7a","\\ud83d\\ude48","\\ud83d\\ude49","\\ud83d\\ude4a","\\ud83d\\udc80","\\ud83d\\udc7d","\\ud83d\\udca9","\\ud83d\\udd25","\\ud83d\\udca5","\\ud83d\\udca4","\\ud83d\\udc42","\\ud83d\\udc40","\\ud83d\\udc43","\\ud83d\\udc45","\\ud83d\\udc44","\\ud83d\\udc4d","\\ud83d\\udc4e","\\ud83d\\udc4c","\\ud83d\\udc4a","\\u270c","\\u270b","\\ud83d\\udc50","\\ud83d\\udc46","\\ud83d\\udc47","\\ud83d\\udc49","\\ud83d\\udc48","\\ud83d\\ude4f","\\ud83d\\udc4f","\\ud83d\\udcaa","\\ud83d\\udeb6","\\ud83c\\udfc3","\\ud83d\\udc83","\\ud83d\\udc6b","\\ud83d\\udc6a","\\ud83d\\udc6c","\\ud83d\\udc6d","\\ud83d\\udc85","\\ud83c\\udfa9","\\ud83d\\udc51","\\ud83d\\udc52","\\ud83d\\udc5f","\\ud83d\\udc5e","\\ud83d\\udc60","\\ud83d\\udc55","\\ud83d\\udc57","\\ud83d\\udc56","\\ud83d\\udc59","\\ud83d\\udc5c","\\ud83d\\udc53","\\ud83c\\udf80","\\ud83d\\udc84","\\ud83d\\udc9b","\\ud83d\\udc99","\\ud83d\\udc9c","\\ud83d\\udc9a","\\ud83d\\udc8d","\\ud83d\\udc8e","\\ud83d\\udc36","\\ud83d\\udc3a","\\ud83d\\udc31","\\ud83d\\udc2d","\\ud83d\\udc39","\\ud83d\\udc30","\\ud83d\\udc38","\\ud83d\\udc2f","\\ud83d\\udc28","\\ud83d\\udc3b","\\ud83d\\udc37","\\ud83d\\udc2e","\\ud83d\\udc17","\\ud83d\\udc34","\\ud83d\\udc11","\\ud83d\\udc18","\\ud83d\\udc3c","\\ud83d\\udc27","\\ud83d\\udc25","\\ud83d\\udc14","\\ud83d\\udc0d","\\ud83d\\udc22","\\ud83d\\udc1b","\\ud83d\\udc1d","\\ud83d\\udc1c","\\ud83d\\udc1e","\\ud83d\\udc0c","\\ud83d\\udc19","\\ud83d\\udc1a","\\ud83d\\udc1f","\\ud83d\\udc2c","\\ud83d\\udc0b","\\ud83d\\udc10","\\ud83d\\udc0a","\\ud83d\\udc2b","\\ud83c\\udf40","\\ud83c\\udf39","\\ud83c\\udf3b","\\ud83c\\udf41","\\ud83c\\udf3e","\\ud83c\\udf44","\\ud83c\\udf35","\\ud83c\\udf34","\\ud83c\\udf33","\\ud83c\\udf1e","\\ud83c\\udf1a","\\ud83c\\udf19","\\ud83c\\udf0e","\\ud83c\\udf0b","\\u26a1","\\u2614","\\u2744","\\u26c4","\\ud83c\\udf00","\\ud83c\\udf08","\\ud83c\\udf0a","\\ud83c\\udf93","\\ud83c\\udf86","\\ud83c\\udf83","\\ud83d\\udc7b","\\ud83c\\udf85","\\ud83c\\udf84","\\ud83c\\udf81","\\ud83c\\udf88","\\ud83d\\udd2e","\\ud83c\\udfa5","\\ud83d\\udcf7","\\ud83d\\udcbf","\\ud83d\\udcbb","\\u260e","\\ud83d\\udce1","\\ud83d\\udcfa","\\ud83d\\udcfb","\\ud83d\\udd09","\\ud83d\\udd14","\\u23f3","\\u23f0","\\u231a","\\ud83d\\udd12","\\ud83d\\udd11","\\ud83d\\udd0e","\\ud83d\\udca1","\\ud83d\\udd26","\\ud83d\\udd0c","\\ud83d\\udd0b","\\ud83d\\udebf","\\ud83d\\udebd","\\ud83d\\udd27","\\ud83d\\udd28","\\ud83d\\udeaa","\\ud83d\\udeac","\\ud83d\\udca3","\\ud83d\\udd2b","\\ud83d\\udd2a","\\ud83d\\udc8a","\\ud83d\\udc89","\\ud83d\\udcb0","\\ud83d\\udcb5","\\ud83d\\udcb3","\\u2709","\\ud83d\\udceb","\\ud83d\\udce6","\\ud83d\\udcc5","\\ud83d\\udcc1","\\u2702","\\ud83d\\udccc","\\ud83d\\udcce","\\u2712","\\u270f","\\ud83d\\udcd0","\\ud83d\\udcda","\\ud83d\\udd2c","\\ud83d\\udd2d","\\ud83c\\udfa8","\\ud83c\\udfac","\\ud83c\\udfa4","\\ud83c\\udfa7","\\ud83c\\udfb5","\\ud83c\\udfb9","\\ud83c\\udfbb","\\ud83c\\udfba","\\ud83c\\udfb8","\\ud83d\\udc7e","\\ud83c\\udfae","\\ud83c\\udccf","\\ud83c\\udfb2","\\ud83c\\udfaf","\\ud83c\\udfc8","\\ud83c\\udfc0","\\u26bd","\\u26be","\\ud83c\\udfbe","\\ud83c\\udfb1","\\ud83c\\udfc9","\\ud83c\\udfb3","\\ud83c\\udfc1","\\ud83c\\udfc7","\\ud83c\\udfc6","\\ud83c\\udfca","\\ud83c\\udfc4","\\u2615","\\ud83c\\udf7c","\\ud83c\\udf7a","\\ud83c\\udf77","\\ud83c\\udf74","\\ud83c\\udf55","\\ud83c\\udf54","\\ud83c\\udf5f","\\ud83c\\udf57","\\ud83c\\udf71","\\ud83c\\udf5a","\\ud83c\\udf5c","\\ud83c\\udf61","\\ud83c\\udf73","\\ud83c\\udf5e","\\ud83c\\udf69","\\ud83c\\udf66","\\ud83c\\udf82","\\ud83c\\udf70","\\ud83c\\udf6a","\\ud83c\\udf6b","\\ud83c\\udf6d","\\ud83c\\udf6f","\\ud83c\\udf4e","\\ud83c\\udf4f","\\ud83c\\udf4a","\\ud83c\\udf4b","\\ud83c\\udf52","\\ud83c\\udf47","\\ud83c\\udf49","\\ud83c\\udf53","\\ud83c\\udf51","\\ud83c\\udf4c","\\ud83c\\udf50","\\ud83c\\udf4d","\\ud83c\\udf46","\\ud83c\\udf45","\\ud83c\\udf3d","\\ud83c\\udfe1","\\ud83c\\udfe5","\\ud83c\\udfe6","\\u26ea","\\ud83c\\udff0","\\u26fa","\\ud83c\\udfed","\\ud83d\\uddfb","\\ud83d\\uddfd","\\ud83c\\udfa0","\\ud83c\\udfa1","\\u26f2","\\ud83c\\udfa2","\\ud83d\\udea2","\\ud83d\\udea4","\\u2693","\\ud83d\\ude80","\\u2708","\\ud83d\\ude81","\\ud83d\\ude82","\\ud83d\\ude8b","\\ud83d\\ude8e","\\ud83d\\ude8c","\\ud83d\\ude99","\\ud83d\\ude97","\\ud83d\\ude95","\\ud83d\\ude9b","\\ud83d\\udea8","\\ud83d\\ude94","\\ud83d\\ude92","\\ud83d\\ude91","\\ud83d\\udeb2","\\ud83d\\udea0","\\ud83d\\ude9c","\\ud83d\\udea6","\\u26a0","\\ud83d\\udea7","\\u26fd","\\ud83c\\udfb0","\\ud83d\\uddff","\\ud83c\\udfaa","\\ud83c\\udfad","\\ud83c\\uddef\\ud83c\\uddf5","\\ud83c\\uddf0\\ud83c\\uddf7","\\ud83c\\udde9\\ud83c\\uddea","\\ud83c\\udde8\\ud83c\\uddf3","\\ud83c\\uddfa\\ud83c\\uddf8","\\ud83c\\uddeb\\ud83c\\uddf7","\\ud83c\\uddea\\ud83c\\uddf8","\\ud83c\\uddee\\ud83c\\uddf9","\\ud83c\\uddf7\\ud83c\\uddfa","\\ud83c\\uddec\\ud83c\\udde7","1\\u20e3","2\\u20e3","3\\u20e3","4\\u20e3","5\\u20e3","6\\u20e3","7\\u20e3","8\\u20e3","9\\u20e3","0\\u20e3","\\ud83d\\udd1f","\\u2757","\\u2753","\\u2665","\\u2666","\\ud83d\\udcaf","\\ud83d\\udd17","\\ud83d\\udd31","\\ud83d\\udd34","\\ud83d\\udd35","\\ud83d\\udd36","\\ud83d\\udd37"]'; public static function class_exists() { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); //set_exception_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionHandler']); if (!self::$inited) { self::$has_thread = class_exists('\\Thread') && method_exists('\\Thread', 'getCurrentThread'); self::$BIG_ENDIAN = pack('L', 1) === pack('N', 1); self::$bigint = PHP_INT_SIZE < 8; self::$ipv6 = (bool) strlen(@file_get_contents('http://v6.ipv6-test.com/api/myip.php', false, stream_context_create(['http' => ['timeout' => 1]]))) > 0; preg_match('/const V = (\\d+);/', @file_get_contents('https://raw.githubusercontent.com/danog/MadelineProto/master/src/danog/MadelineProto/MTProto.php'), $matches); if (isset($matches[1]) && \danog\MadelineProto\MTProto::V < (int) $matches[1]) { throw new \danog\MadelineProto\Exception(hex2bin(\danog\MadelineProto\Lang::$current_lang['v_error']), 0, null, 'MadelineProto', 1); } if (class_exists('\\danog\\MadelineProto\\VoIP')) { if (!defined('\\danog\\MadelineProto\\VoIP::PHP_LIBTGVOIP_VERSION') || !in_array(\danog\MadelineProto\VoIP::PHP_LIBTGVOIP_VERSION, ['1.3.0'])) { throw new \danog\MadelineProto\Exception(hex2bin(\danog\MadelineProto\Lang::$current_lang['v_tgerror']), 0, null, 'MadelineProto', 1); } } self::$emojis = json_decode(self::JSON_EMOJIS); self::$zero = new \phpseclib\Math\BigInteger(0); self::$one = new \phpseclib\Math\BigInteger(1); self::$two = new \phpseclib\Math\BigInteger(2); self::$three = new \phpseclib\Math\BigInteger(3); self::$four = new \phpseclib\Math\BigInteger(4); self::$twoe1984 = new \phpseclib\Math\BigInteger('1751908409537131537220509645351687597690304110853111572994449976845956819751541616602568796259317428464425605223064365804210081422215355425149431390635151955247955156636234741221447435733643262808668929902091770092492911737768377135426590363166295684370498604708288556044687341394398676292971255828404734517580702346564613427770683056761383955397564338690628093211465848244049196353703022640400205739093118270803778352768276670202698397214556629204420309965547056893233608758387329699097930255380715679250799950923553703740673620901978370802540218870279314810722790539899334271514365444369275682816'); self::$twoe2047 = new \phpseclib\Math\BigInteger('16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328'); self::$twoe2048 = new \phpseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656'); self::$twozerotwosixone = new \phpseclib\Math\BigInteger(20261); self::$zeroeight = new \phpseclib\Math\BigInteger('2147483648'); try { self::$isatty = defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT); } catch (\danog\MadelineProto\Exception $e) { } self::$can_getmypid = !(isset($_SERVER['SERVER_ADMIN']) && strpos($_SERVER['SERVER_ADMIN'], 'altervista.org')); self::$altervista = !self::$can_getmypid; self::$revision = @file_get_contents(__DIR__.'/../../../.git/refs/heads/master'); if (self::$revision) { self::$revision = trim(self::$revision); $latest = @file_get_contents('https://phar.madelineproto.xyz/release'); if ($latest) { $latest = self::$revision === trim($latest) ? '' : ' (AN UPDATE IS REQUIRED)'; } self::$revision = 'Revision: '.self::$revision.$latest; } self::$can_parallel = false; if (php_sapi_name() === 'cli' && !(class_exists('\\Phar') && \Phar::running())) { try { $back = debug_backtrace(0); define('AMP_WORKER', 1); $promise = \Amp\File\get(end($back)['file']); do { try { if (wait($promise)) { self::$can_parallel = true; break; } } catch (\Throwable $e) { if ($e->getMessage() !== 'Loop stopped without resolving the promise') { throw $e; } } } while (true); } catch (\Throwable $e) { } } if (!self::$can_parallel && !defined('AMP_WORKER') || true) { //define('AMP_WORKER', 1); } $backtrace = debug_backtrace(0); self::$script_cwd = self::$cwd = dirname(end($backtrace)['file']); try { self::$cwd = getcwd(); self::$can_getcwd = true; } catch (\danog\MadelineProto\Exception $e) { } // Even an empty handler is enough to catch ctrl+c if (defined('SIGINT')) { //if (function_exists('pcntl_async_signals')) pcntl_async_signals(true); Loop::onSignal(SIGINT, static function () { Logger::log('Got sigint', Logger::FATAL_ERROR); die(); }); /*Loop::onSignal(SIGTERM, static function () { Logger::log('Got sigterm', Logger::FATAL_ERROR); Loop::stop(); die(); });*/ } $DohConfig = new DoHConfig( [ new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), new Nameserver('https://google.com/resolve', Nameserver::GOOGLE_JSON, ["Host" => "dns.google.com"]), ] ); resolver(new Rfc8484StubResolver($DohConfig)); if (php_sapi_name() !== 'cli') { try { error_reporting(E_ALL); ini_set('log_errors', 1); ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log'); error_log('Enabled PHP logging'); } catch (\danog\MadelineProto\Exception $e) { //$this->logger->logger('Could not enable PHP logging'); } } self::$inited = true; } } public static function is_fork() { if (self::$is_fork) { return true; } if (!self::$can_getmypid) { return false; } try { if (self::$pid === null) { self::$pid = getmypid(); } return self::$is_fork = self::$pid !== getmypid(); } catch (\danog\MadelineProto\Exception $e) { return self::$can_getmypid = false; } } public static function getcwd() { return self::$can_getcwd ? getcwd() : self::$cwd; } } { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-2106507297", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "2004934137", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "-652419756", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "admins_enabled", "type": "flags.3?true" }, { "name": "admin", "type": "flags.4?true" }, { "name": "deactivated", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "migrated_to", "type": "flags.6?InputChannel" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "1061556205", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "1537633299", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector" }, { "name": "views", "type": "flags.10?int" } ], "type": "Message" }, { "id": "-1066691065", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1217033015", "predicate": "messageActionChatAddUser", "params": [ { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-136766906", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-892863022", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?Peer" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "ipv6", "type": "flags.0?true" }, { "name": "media_only", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1823925854", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_size_max", "type": "int" }, { "name": "megagroup_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-719474725", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "sets", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "channel", "type": "flags.0?true" }, { "name": "broadcast", "type": "flags.1?true" }, { "name": "public", "type": "flags.2?true" }, { "name": "megagroup", "type": "flags.3?true" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "installed", "type": "flags.0?true" }, { "name": "disabled", "type": "flags.1?true" }, { "name": "official", "type": "flags.2?true" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.StickerSet" }, { "id": "585404530", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "self", "type": "flags.10?true" }, { "name": "contact", "type": "flags.11?true" }, { "name": "mutual_contact", "type": "flags.12?true" }, { "name": "deleted", "type": "flags.13?true" }, { "name": "bot", "type": "flags.14?true" }, { "name": "bot_chat_history", "type": "flags.15?true" }, { "name": "bot_nochats", "type": "flags.16?true" }, { "name": "verified", "type": "flags.17?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "resize", "type": "flags.0?true" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" }, { "name": "rows", "type": "Vector" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "unread", "type": "flags.0?true" }, { "name": "out", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "1737397639", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "editor", "type": "flags.3?true" }, { "name": "moderator", "type": "flags.4?true" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "verified", "type": "flags.7?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "763724588", "predicate": "channelForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1640751649", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "can_view_participants", "type": "flags.3?true" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector" }, { "name": "migrated_from_chat_id", "type": "flags.4?int" }, { "name": "migrated_from_max_id", "type": "flags.4?int" } ], "type": "ChatFull" }, { "id": "1535415986", "predicate": "dialogChannel", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "int" } ], "type": "Dialog" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-399216813", "predicate": "messageGroup", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "count", "type": "int" }, { "name": "date", "type": "int" } ], "type": "MessageGroup" }, { "id": "-1139861572", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "collapsed", "type": "flags.0?Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "1620337698", "predicate": "updateChannelTooLong", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "-1016324548", "predicate": "updateChannelGroup", "params": [ { "name": "channel_id", "type": "int" }, { "name": "group", "type": "MessageGroup" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1578530374", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "top_important_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "unread_important_count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "exclude_new_messages", "type": "flags.1?true" }, { "name": "ranges", "type": "Vector" } ], "type": "ChannelMessagesFilter" }, { "id": "-100588754", "predicate": "channelMessagesFilterCollapsed", "params": [], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector" } ], "type": "channels.ChannelParticipant" }, { "id": "-636267638", "predicate": "chatParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-489233354", "predicate": "chatParticipantAdmin", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "1855224129", "predicate": "updateChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1232070311", "predicate": "updateChatParticipantAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "is_admin", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1371385889", "predicate": "messageActionChatMigrateTo", "params": [ { "name": "channel_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1336546578", "predicate": "messageActionChannelMigrateFrom", "params": [ { "name": "title", "type": "string" }, { "name": "chat_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1328445861", "predicate": "channelParticipantsBots", "params": [], "type": "ChannelParticipantsFilter" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "1799878989", "method": "messages.getDialogs", "params": [ { "name": "offset_date", "type": "int" }, { "name": "offset_id", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1970355494", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "important_only", "type": "flags.0?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "238054714", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "-1212072999", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.4?true" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "random_id", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-421563528", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" }, { "name": "increment", "type": "Bool" } ], "type": "Vector" }, { "id": "-1445735863", "method": "channels.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-575067701", "method": "channels.getImportantHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "offset_id", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "-192332417", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.0?true" }, { "name": "megagroup", "type": "flags.1?true" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "-344583728", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Updates" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-1432183160", "method": "channels.toggleComments", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" }, { "id": "-326379039", "method": "messages.toggleChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1444503762", "method": "messages.editChatAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "is_admin", "type": "Bool" } ], "type": "Bool" }, { "id": "363051235", "method": "messages.migrateChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Updates" }, { "id": "-1640190800", "method": "messages.searchGlobal", "params": [ { "name": "q", "type": "string" }, { "name": "offset_date", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" } ] }. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; /** * Manages logging in and out. */ trait TOS { public function check_tos_async() { if ($this->authorized === self::LOGGED_IN && !$this->authorization['user']['bot']) { if ($this->tos['expires'] < time()) { $this->logger->logger('Fetching TOS...'); $this->tos = yield $this->method_call_async_read('help.getTermsOfServiceUpdate', [], ['datacenter' => $this->datacenter->curdc]); $this->tos['accepted'] = $this->tos['_'] === 'help.termsOfServiceUpdateEmpty'; } if (!$this->tos['accepted']) { $this->logger->logger('Telegram has updated their Terms Of Service', \danog\MadelineProto\Logger::ERROR); $this->logger->logger('Accept the TOS before proceeding by calling $MadelineProto->accept_tos().', \danog\MadelineProto\Logger::ERROR); $this->logger->logger('You can also decline the TOS by calling $MadelineProto->decline_tos().', \danog\MadelineProto\Logger::ERROR); $this->logger->logger('By declining the TOS, the currently logged in account will be PERMANENTLY DELETED.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Read the following TOS very carefully: ', \danog\MadelineProto\Logger::ERROR); $this->logger->logger($this->tos); throw new \danog\MadelineProto\Exception('TOS action required, check the logs', 0, null, 'MadelineProto', 1); } } } public function accept_tos_async() { $this->tos['accepted'] = yield $this->method_call_async_read('help.acceptTermsOfService', ['id' => $this->tos['terms_of_service']['id']], ['datacenter' => $this->datacenter->curdc]); if ($this->tos['accepted']) { $this->logger->logger('TOS accepted successfully'); } else { throw new \danog\MadelineProto\Exception('An error occurred while accepting the TOS'); } } public function decline_tos_async() { yield $this->method_call_async_read('account.deleteAccount', ['reason' => 'Decline ToS update'], ['datacenter' => $this->datacenter->curdc]); yield $this->logout_async(); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; use Amp\Promise; use danog\MadelineProto\Shutdown; /** * Manages logging in and out. */ trait Loop { private $loop_callback; public function setLoopCallback($callback) { $this->loop_callback = $callback; } public function loop_async($max_forks = 0) { if (is_callable($max_forks)) { $this->logger->logger('Running async callable'); return yield $max_forks(); } if ($max_forks instanceof Promise) { $this->logger->logger('Resolving async promise'); return yield $max_forks; } if (!$this->authorized) { $this->logger->logger('Not authorized, not starting event loop', \danog\MadelineProto\Logger::FATAL_ERROR); return false; } if (in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler'])) { $this->logger->logger('Getupdates event handler is enabled, exiting from loop', \danog\MadelineProto\Logger::FATAL_ERROR); return false; } $this->logger->logger('Starting event loop'); if (!is_callable($this->loop_callback) || (is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !method_exists(...$this->loop_callback))) { $this->loop_callback = null; } if (php_sapi_name() !== 'cli') { $needs_restart = true; try { set_time_limit(-1); } catch (\danog\MadelineProto\Exception $e) { $needs_restart = true; } $this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart'); $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $lockfile = dirname(end($backtrace)['file']).'/bot'.$this->authorization['user']['id'].'.lock'; unset($backtrace); $try_locking = true; if (!file_exists($lockfile)) { touch($lockfile); $lock = fopen($lockfile, 'r+'); } elseif (isset($GLOBALS['lock'])) { $try_locking = false; $lock = $GLOBALS['lock']; } else { $lock = fopen($lockfile, 'r+'); } if ($try_locking) { $try = 1; $locked = false; while (!$locked) { $locked = flock($lock, LOCK_EX | LOCK_NB); if (!$locked) { $this->closeConnection('Bot is already running'); if ($try++ >= 30) { exit; } sleep(1); } } } Shutdown::addCallback(static function () use ($lock) { flock($lock, LOCK_UN); fclose($lock); }); if ($needs_restart) { $logger = &$this->logger; Shutdown::addCallback(static function () use (&$logger) { $a = fsockopen((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT']); fwrite($a, $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n"); $logger->logger('Self-restarted'); }, 'restarter'); } $this->closeConnection('Bot was started'); } if (!$this->settings['updates']['handle_updates']) { $this->settings['updates']['handle_updates'] = true; } if (!$this->settings['updates']['run_callback']) { $this->settings['updates']['run_callback'] = true; } $this->startUpdateSystem(); $this->logger->logger('Started update loop', \danog\MadelineProto\Logger::NOTICE); while (true) { $updates = $this->updates; $this->updates = []; foreach ($updates as $update) { $r = $this->settings['updates']['callback']($update); if (is_object($r)) { $this->callFork($r); } } $updates = []; if ($this->loop_callback !== null) { $callback = $this->loop_callback; $callback(); } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); yield $this->waitUpdate(); } } public function closeConnection($message = 'OK!') { if (php_sapi_name() === 'cli' || isset($GLOBALS['exited']) || headers_sent()) { return; } $this->logger->logger($message); @ob_end_clean(); header('Connection: close'); ignore_user_abort(true); ob_start(); echo '

'.$message.'

'; $size = ob_get_length(); header("Content-Length: $size"); header('Content-Type: text/html'); ob_end_flush(); flush(); $GLOBALS['exited'] = true; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; /** * Manages logging in and out. */ trait Callback { public function setCallback($callback) { $this->settings['updates']['callback'] = $callback; $this->settings['updates']['run_callback'] = true; $this->settings['updates']['handle_updates'] = true; $this->startUpdateSystem(); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; use function Amp\ByteStream\getStdout; /** * Manages simple logging in and out. */ trait ApiStart { public function api_start_async($settings) { if (php_sapi_name() === 'cli') { $stdout = getStdout(); yield $stdout->write('You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a) Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id'.PHP_EOL); if (strpos(yield $this->readLine('Your choice (m/a): '), 'm') !== false) { yield $stdout->write('1) Login to my.telegram.org 2) Go to API development tools 3) App title: your app\'s name, can be anything Short name: your app\'s short name, can be anything URL: your app/website\'s URL, or t.me/yourusername Platform: anything Description: Describe your app here 4) Click on create application'.PHP_EOL); $app['api_id'] = yield $this->readLine('5) Enter your API ID: '); $app['api_hash'] = yield $this->readLine('6) Enter your API hash: '); return $app; } else { $this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings); yield $this->my_telegram_org_wrapper->login_async(yield $this->readLine('Enter a phone number that is already registered on Telegram: ')); yield $this->my_telegram_org_wrapper->complete_login_async(yield $this->readLine('Enter the verification code you received in telegram: ')); if (!yield $this->my_telegram_org_wrapper->has_app_async()) { $app_title = yield $this->readLine('Enter the app\'s name, can be anything: '); $short_name = yield $this->readLine('Enter the app\'s short name, can be anything: '); $url = yield $this->readLine('Enter the app/website\'s URL, or t.me/yourusername: '); $description = yield $this->readLine('Describe your app: '); $app = yield $this->my_telegram_org_wrapper->create_app_async(['app_title' => $app_title, 'app_shortname' => $short_name, 'app_url' => $url, 'app_platform' => 'web', 'app_desc' => $description]); } else { $app = yield $this->my_telegram_org_wrapper->get_app_async(); } return $app; } } else { $this->getting_api_id = true; if (!isset($this->my_telegram_org_wrapper)) { if (isset($_POST['api_id']) && isset($_POST['api_hash'])) { $app['api_id'] = (int) $_POST['api_id']; $app['api_hash'] = $_POST['api_hash']; $this->getting_api_id = false; return $app; } elseif (isset($_POST['phone_number'])) { yield $this->web_api_phone_login_async($settings); } else { yield $this->web_api_echo_async(); } } elseif (!$this->my_telegram_org_wrapper->logged_in()) { if (isset($_POST['code'])) { yield $this->web_api_complete_login_async(); if (yield $this->my_telegram_org_wrapper->has_app_async()) { return yield $this->my_telegram_org_wrapper->get_app_async(); } yield $this->web_api_echo_async(); } elseif (isset($_POST['api_id']) && isset($_POST['api_hash'])) { $app['api_id'] = (int) $_POST['api_id']; $app['api_hash'] = $_POST['api_hash']; $this->getting_api_id = false; return $app; } elseif (isset($_POST['phone_number'])) { yield $this->web_api_phone_login_async($settings); } else { $this->my_telegram_org_wrapper = null; yield $this->web_api_echo_async(); } } else { if (isset($_POST['app_title'], $_POST['app_shortname'], $_POST['app_url'], $_POST['app_platform'], $_POST['app_desc'])) { $app = yield $this->web_api_create_app_async(); $this->getting_api_id = false; return $app; } else { yield $this->web_api_echo_async("You didn't provide all of the required parameters!"); } } $this->asyncInitPromise = null; exit; } } public function web_api_phone_login_async($settings) { try { $this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings); yield $this->my_telegram_org_wrapper->login_async($_POST['phone_number']); yield $this->web_api_echo_async(); } catch (\Throwable $e) { yield $this->web_api_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } public function web_api_complete_login_async() { try { yield $this->my_telegram_org_wrapper->complete_login_async($_POST['code']); } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_api_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_api_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } public function web_api_create_app_async() { try { $params = $_POST; unset($params['creating_app']); $app = yield $this->my_telegram_org_wrapper->create_app_async($params); return $app; } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_api_echo_async('ERROR: '.$e->getMessage().' Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_api_echo_async('ERROR: '.$e->getMessage().' Try again.'); } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; trait DialogHandler { public function get_dialogs_async($force = true) { if ($this->authorization['user']['bot']) { $res = []; foreach ($this->chats as $chat) { $res[] = $this->gen_all($chat)['Peer']; } return $res; } $res = []; foreach (yield $this->get_full_dialogs_async($force) as $dialog) { $res[] = $dialog['peer']; } return $res; } public function get_full_dialogs_async($force = true) { if ($force || !isset($this->dialog_params['offset_date']) || is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || is_null($this->dialog_params['count'])) { $this->dialog_params = ['limit' => 100, 'offset_date' => 0, 'offset_id' => 0, 'offset_peer' => ['_' => 'inputPeerEmpty'], 'count' => 0, 'hash' => 0]; } if (!isset($this->dialog_params['hash'])) { $this->dialog_params['hash'] = 0; } $res = ['dialogs' => [0], 'count' => 1]; $datacenter = $this->datacenter->curdc; $dialogs = []; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getting_dialogs']); while ($this->dialog_params['count'] < $res['count']) { $res = yield $this->method_call_async_read('messages.getDialogs', $this->dialog_params, ['datacenter' => $datacenter, 'FloodWaitLimit' => 100]); $last_peer = 0; $last_date = 0; $last_id = 0; $res['messages'] = array_reverse($res['messages']); foreach (array_reverse($res['dialogs']) as $dialog) { $id = $this->get_id($dialog['peer']); if (!isset($dialogs[$id])) { $dialogs[$id] = $dialog; } if (!$last_date) { if (!$last_peer) { $last_peer = $id; } if (!$last_id) { $last_id = $dialog['top_message']; } foreach ($res['messages'] as $message) { if ($this->get_id($message) === $last_peer && $last_id === $message['id']) { $last_date = $message['date']; break; } } } } if ($last_date) { $this->dialog_params['offset_date'] = $last_date; $this->dialog_params['offset_peer'] = $last_peer; $this->dialog_params['offset_id'] = $last_id; $this->dialog_params['count'] = count($dialogs); } else { break; } if (!isset($res['count'])) { break; } } return $dialogs; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; use danog\MadelineProto\MTProtoTools\PasswordCalculator; /** * Manages logging in and out. */ trait Login { public function logout_async() { yield $this->method_call_async_read('auth.logOut', [], ['datacenter' => $this->datacenter->curdc]); $this->resetSession(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['logout_ok'], \danog\MadelineProto\Logger::NOTICE); $this->startUpdateSystem(); return true; } public function bot_login_async($token) { if ($this->authorized === self::LOGGED_IN) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_logged_in'], \danog\MadelineProto\Logger::NOTICE); yield $this->logout_async(); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_bot'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->method_call_async_read('auth.importBotAuthorization', ['bot_auth_token' => $token, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash']], ['datacenter' => $this->datacenter->curdc]); $this->authorized = self::LOGGED_IN; $this->authorized_dc = $this->datacenter->curdc; $this->datacenter->sockets[$this->datacenter->curdc]->authorized = true; $this->updates = []; $this->updates_key = 0; yield $this->init_authorization_async(); $this->startUpdateSystem(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE); return $this->authorization; } public function phone_login_async($number, $sms_type = 5) { if ($this->authorized === self::LOGGED_IN) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_logged_in'], \danog\MadelineProto\Logger::NOTICE); yield $this->logout_async(); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_code_sending'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->method_call_async_read('auth.sendCode', ['settings' => ['_' => 'codeSettings'], 'phone_number' => $number, 'sms_type' => $sms_type, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash'], 'lang_code' => $this->settings['app_info']['lang_code']], ['datacenter' => $this->datacenter->curdc]); $this->authorized_dc = $this->datacenter->curdc; $this->authorization['phone_number'] = $number; //$this->authorization['_'] .= 'MP'; $this->authorized = self::WAITING_CODE; $this->updates = []; $this->updates_key = 0; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_code_sent'], \danog\MadelineProto\Logger::NOTICE); return $this->authorization; } public function complete_phone_login_async($code) { if ($this->authorized !== self::WAITING_CODE) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['login_code_uncalled']); } $this->authorized = self::NOT_LOGGED_IN; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_user'], \danog\MadelineProto\Logger::NOTICE); try { $authorization = yield $this->method_call_async_read('auth.signIn', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => (string) $code], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'SESSION_PASSWORD_NEEDED') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_2fa_enabled'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->method_call_async_read('account.getPassword', [], ['datacenter' => $this->datacenter->curdc]); if (!isset($this->authorization['hint'])) { $this->authorization['hint'] = ''; } $this->authorized = self::WAITING_PASSWORD; return $this->authorization; } if ($e->rpc === 'PHONE_NUMBER_UNOCCUPIED') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_need_signup'], \danog\MadelineProto\Logger::NOTICE); $this->authorized = self::WAITING_SIGNUP; $this->authorization['phone_code'] = $code; return ['_' => 'account.needSignup']; } throw $e; } $this->authorized = self::LOGGED_IN; $this->authorization = $authorization; $this->datacenter->sockets[$this->datacenter->curdc]->authorized = true; yield $this->init_authorization_async(); yield $this->get_phone_config_async(); $this->startUpdateSystem(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE); return $this->authorization; } public function import_authorization_async($authorization) { if ($this->authorized === self::LOGGED_IN) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_logged_in'], \danog\MadelineProto\Logger::NOTICE); yield $this->logout_async(); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_auth_key'], \danog\MadelineProto\Logger::NOTICE); list($dc_id, $auth_key) = $authorization; if (!is_array($auth_key)) { $auth_key = ['auth_key' => $auth_key, 'id' => substr(sha1($auth_key, true), -8), 'server_salt' => '']; } $this->authorized_dc = $dc_id; $this->datacenter->sockets[$dc_id]->session_id = $this->random(8); $this->datacenter->sockets[$dc_id]->session_in_seq_no = 0; $this->datacenter->sockets[$dc_id]->session_out_seq_no = 0; $this->datacenter->sockets[$dc_id]->auth_key = $auth_key; $this->datacenter->sockets[$dc_id]->temp_auth_key = null; $this->datacenter->sockets[$dc_id]->incoming_messages = []; $this->datacenter->sockets[$dc_id]->outgoing_messages = []; $this->datacenter->sockets[$dc_id]->new_outgoing = []; $this->datacenter->sockets[$dc_id]->new_incoming = []; $this->datacenter->sockets[$dc_id]->authorized = true; $this->authorized = self::LOGGED_IN; yield $this->init_authorization_async(); yield $this->get_phone_config_async(); $res = yield $this->get_self_async(); $this->startUpdateSystem(); return $res; } public function export_authorization_async() { if ($this->authorized !== self::LOGGED_IN) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['not_logged_in']); } yield $this->get_self_async(); $this->authorized_dc = $this->datacenter->curdc; return [$this->datacenter->curdc, $this->datacenter->sockets[$this->datacenter->curdc]->auth_key['auth_key']]; } public function complete_signup_async($first_name, $last_name) { if ($this->authorized !== self::WAITING_SIGNUP) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['signup_uncalled']); } $this->authorized = self::NOT_LOGGED_IN; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['signing_up'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->method_call_async_read('auth.signUp', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => $this->authorization['phone_code'], 'first_name' => $first_name, 'last_name' => $last_name], ['datacenter' => $this->datacenter->curdc]); $this->authorized = self::LOGGED_IN; $this->datacenter->sockets[$this->datacenter->curdc]->authorized = true; yield $this->init_authorization_async(); yield $this->get_phone_config_async(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['signup_ok'], \danog\MadelineProto\Logger::NOTICE); $this->startUpdateSystem(); return $this->authorization; } public function complete_2fa_login_async($password) { if ($this->authorized !== self::WAITING_PASSWORD) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['2fa_uncalled']); } $this->authorized = self::NOT_LOGGED_IN; $hasher = new PasswordCalculator($this->logger); $hasher->addInfo($this->authorization); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_user'], \danog\MadelineProto\Logger::NOTICE); $this->authorization = yield $this->method_call_async_read('auth.checkPassword', ['password' => $hasher->getCheckPassword($password)], ['datacenter' => $this->datacenter->curdc]); $this->authorized = self::LOGGED_IN; $this->datacenter->sockets[$this->datacenter->curdc]->authorized = true; yield $this->init_authorization_async(); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE); yield $this->get_phone_config_async(); $this->startUpdateSystem(); return $this->authorization; } /** * Update the 2FA password * * The params can contain password, new_password, email and hint params. * * @param array $params The params * @return void */ public function update_2fa_async(array $params) { $hasher = new PasswordCalculator($this->logger); $hasher->addInfo(yield $this->method_call_async_read('account.getPassword', [], ['datacenter' => $this->datacenter->curdc])); return yield $this->method_call_async_read('account.updatePasswordSettings', $hasher->getPassword($params), ['datacenter' => $this->datacenter->curdc]); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; use function Amp\ByteStream\getOutputBufferStream; trait Templates { public function web_echo_async($message = '') { $stdout = getOutputBufferStream(); switch ($this->authorized) { case self::NOT_LOGGED_IN: if (isset($_POST['type'])) { if ($_POST['type'] === 'phone') { yield $stdout->write($this->web_echo_template('Enter your phone number
'.$message.'', '')); } else { yield $stdout->write($this->web_echo_template('Enter your bot token
'.$message.'', '')); } } else { yield $stdout->write($this->web_echo_template('Do you want to login as user or bot?
'.$message.'', '')); } break; case self::WAITING_CODE: yield $stdout->write($this->web_echo_template('Enter your code
'.$message.'', '')); break; case self::WAITING_PASSWORD: yield $stdout->write($this->web_echo_template('Enter your password
'.$message.'', '')); break; case self::WAITING_SIGNUP: yield $stdout->write($this->web_echo_template('Sign up please
'.$message.'', '')); break; } } private $web_template = ' MadelineProto

MadelineProto

%s

%s

'; public function web_echo_template($message, $form) { return sprintf($this->web_template, $form, $message); } public function get_web_template() { return $this->web_template; } public function set_web_template($template) { $this->web_template = $template; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; use function Amp\ByteStream\getOutputBufferStream; trait ApiTemplates { private $web_api_template = ' MadelineProto

MadelineProto

%s

%s
'; public function web_api_echo_template($message, $form) { return sprintf($this->web_api_template, $message, $form); } public function get_web_api_template() { return $this->web_template; } public function set_web_api_template($template) { $this->web_template = $template; } public function web_api_echo_async($message = '') { $stdout = getOutputBufferStream(); if (!isset($this->my_telegram_org_wrapper)) { if (isset($_POST['type'])) { if ($_POST['type'] === 'manual') { yield $stdout->write($this->web_api_echo_template('Enter your API ID and API hash
'.$message.'
  1. Login to my.telegram.org
  2. Go to API development tools
    • App title: your app's name, can be anything
    • Short name: your app's short name, only numbers and letters
    • Platform: Web
    • Description: describe your app here
  3. Click on create application
', '')); } else { yield $stdout->write($this->web_api_echo_template('Enter a phone number that is already registered on telegram to get the API ID
'.$message.'', '')); } } else { if ($message) { $message = '

'.$message; } yield $stdout->write($this->web_api_echo_template('Do you want to enter the API id and the API hash manually or automatically?
Note that you can also provide it directly in the code using the settings.'.$message.'', '')); } } else { if (!$this->my_telegram_org_wrapper->logged_in()) { yield $stdout->write($this->web_api_echo_template('Enter your code
'.$message.'', '')); } else { yield $stdout->write($this->web_api_echo_template( 'Enter the API info
'.$message.'', ' Enter the app name, can be anything:


Enter the app's short name, alphanumeric, 5-32 chars:


Enter the app/website URL, or https://t.me/yourusername:


Enter the app platform:


Enter the app description, can be anything:


')); } } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; /** * Manages logging in and out. */ trait Events { public $event_handler; private $event_handler_instance; private $event_handler_methods = []; public function setEventHandler($event_handler) { if (!class_exists($event_handler) || !is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) { throw new \danog\MadelineProto\Exception('Wrong event handler was defined'); } $this->event_handler = $event_handler; if (!($this->event_handler_instance instanceof $this->event_handler)) { $class_name = $this->event_handler; $this->event_handler_instance = new $class_name($this->wrapper); } elseif ($this->wrapper) { $this->event_handler_instance->__construct($this->wrapper); } $this->event_handler_methods = []; foreach (\get_class_methods($this->event_handler) as $method) { if ($method === 'onLoop') { $this->loop_callback = [$this->event_handler_instance, 'onLoop']; } elseif ($method === 'onAny') { foreach ($this->constructors->by_id as $id => $constructor) { if ($constructor['type'] === 'Update' && !isset($this->event_handler_methods[$constructor['predicate']])) { $this->event_handler_methods[$constructor['predicate']] = [$this->event_handler_instance, 'onAny']; } } } else { $method_name = lcfirst(substr($method, 2)); $this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method]; } } $this->settings['updates']['callback'] = [$this, 'event_update_handler']; $this->settings['updates']['handle_updates'] = true; $this->settings['updates']['run_callback'] = true; if (!$this->asyncInitPromise) { $this->startUpdateSystem(); } } public function getEventHandler() { return $this->event_handler_instance; } public function event_update_handler($update) { if (isset($this->event_handler_methods[$update['_']])) { return $this->event_handler_methods[$update['_']]($update); } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; use function Amp\ByteStream\getStdin; use function Amp\ByteStream\getStdout; /** * Manages simple logging in and out. */ trait Start { public function start_async() { if ($this->authorized === self::LOGGED_IN) { return yield $this->get_self_async(); } if (php_sapi_name() === 'cli') { if (strpos(yield $this->readLine('Do you want to login as user or bot (u/b)? '), 'b') !== false) { yield $this->bot_login_async(yield $this->readLine('Enter your bot token: ')); } else { yield $this->phone_login_async(yield $this->readLine('Enter your phone number: ')); $authorization = yield $this->complete_phone_login_async(yield $this->readLine('Enter the phone code: ')); if ($authorization['_'] === 'account.password') { $authorization = yield $this->complete_2fa_login_async(yield $this->readLine('Please enter your password (hint '.$authorization['hint'].'): ')); } if ($authorization['_'] === 'account.needSignup') { $authorization = yield $this->complete_signup_async(yield $this->readLine('Please enter your first name: '), yield $this->readLine('Please enter your last name (can be empty): ')); } } $this->serialize(); return yield $this->get_self_async(); } else { if ($this->authorized === self::NOT_LOGGED_IN) { if (isset($_POST['phone_number'])) { yield $this->web_phone_login_async(); } elseif (isset($_POST['token'])) { yield $this->web_bot_login_async(); } else { yield $this->web_echo_async(); } } elseif ($this->authorized === self::WAITING_CODE) { if (isset($_POST['phone_code'])) { yield $this->web_complete_phone_login_async(); } else { yield $this->web_echo_async("You didn't provide a phone code!"); } } elseif ($this->authorized === self::WAITING_PASSWORD) { if (isset($_POST['password'])) { yield $this->web_complete_2fa_login_async(); } else { yield $this->web_echo_async("You didn't provide the password!"); } } elseif ($this->authorized === self::WAITING_SIGNUP) { if (isset($_POST['first_name'])) { yield $this->web_complete_signup_async(); } else { yield $this->web_echo_async("You didn't provide the first name!"); } } if ($this->authorized === self::LOGGED_IN) { $this->serialize(); return yield $this->get_self_async(); } exit; } } public function web_phone_login_async() { try { yield $this->phone_login_async($_POST['phone_number']); yield $this->web_echo_async(); } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } public function web_complete_phone_login_async() { try { yield $this->complete_phone_login_async($_POST['phone_code']); yield $this->web_echo_async(); } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } public function web_complete_2fa_login_async() { try { yield $this->complete_2fa_login_async($_POST['password']); yield $this->web_echo_async(); } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } public function web_complete_signup_async() { try { yield $this->complete_signup_async($_POST['first_name'], isset($_POST['last_name']) ? $_POST['last_name'] : ''); yield $this->web_echo_async(); } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } public function web_bot_login_async() { try { yield $this->bot_login_async($_POST['token']); yield $this->web_echo_async(); } catch (\danog\MadelineProto\RPCErrorException $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } catch (\danog\MadelineProto\Exception $e) { yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.'); } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; /** * Manages logging in and out. */ trait Webhook { public function setWebhook($hook_url, $pem_path = null) { $this->pem_path = $pem_path; $this->hook_url = $hook_url; $this->settings['updates']['callback'] = [$this, 'pwr_webhook']; $this->settings['updates']['run_callback'] = true; $this->settings['updates']['handle_updates'] = true; $this->startUpdateSystem(); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Wrappers; trait Noop { public function setNoop() { $this->settings['updates']['callback'] = [$this, 'noop']; $this->settings['updates']['run_callback'] = false; $this->settings['updates']['handle_updates'] = true; $this->startUpdateSystem(); } public function noop() { } } ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#450b7115 flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; config#9c840964 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector photos:Vector documents:Vector = Page; pageFull#556ec7aa blocks:Vector photos:Vector documents:Vector = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; account.registerDevice#1389cc token_type:int token:string app_sandbox:Bool other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#39e9ea0 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#b0e08243 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#249431e2 peer:InputPeer limit:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector; upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector; // LAYER 75 generator = new class($generator) { private $s = ''; private $g; private $trace; public function __construct($g) { $this->g = $g; $this->s .= spl_object_hash($this).', '; } public function __call($a, $args) { $this->s .= "$a, "; try { $res = $this->g->{$a}(...$args); if (is_array($res) && isset($res['my_trace'])) { $this->trace = $res; $res = $this->g->{$a}(...$args); } return $res; } catch (\Throwable $e) { $this->s .= $e->getMessage(); $this->s .= ', '; var_dump($this->s, $this->trace); throw $e; } } //public function __destruct() { var_dump($this->s); } };*/ $this->generator = $generator; try { $yielded = $this->generator->current(); while (!$yielded instanceof Promise) { if ($yielded instanceof \YieldReturnValue) { $this->resolve($yielded->getReturn()); $this->generator->next(); return; } if (!$this->generator->valid()) { if (PHP_MAJOR_VERSION >= 7) { $this->resolve($this->generator->getReturn()); } else { $this->resolve(null); } return; } if ($yielded instanceof \Generator) { $yielded = new self($yielded); } else { $yielded = $this->generator->send($yielded); } } } catch (\Throwable $exception) { $this->fail($exception); return; } /* * @param \Throwable|null $exception Exception to be thrown into the generator. * @param mixed $value Value to be sent into the generator. */ $this->onResolve = function ($exception, $value) { $this->exception = $exception; $this->value = $value; if (!$this->immediate) { $this->immediate = true; return; } try { do { if ($this->exception) { // Throw exception at current execution point. $yielded = $this->generator->throw($this->exception); } else { // Send the new value and execute to next yield statement. $yielded = $this->generator->send($this->value); } while (!$yielded instanceof Promise) { if ($yielded instanceof \YieldReturnValue) { $this->resolve($yielded->getReturn()); $this->onResolve = null; $this->generator->next(); return; } if (!$this->generator->valid()) { if (PHP_MAJOR_VERSION >= 7) { $this->resolve($this->generator->getReturn()); } else { $this->resolve(null); } $this->onResolve = null; return; } if ($yielded instanceof \Generator) { $yielded = new self($yielded); } else { $yielded = $this->generator->send($yielded); } } $this->immediate = false; $yielded->onResolve($this->onResolve); } while ($this->immediate); $this->immediate = true; } catch (\Throwable $exception) { $this->fail($exception); $this->onResolve = null; } finally { $this->exception = null; $this->value = null; } }; $yielded->onResolve($this->onResolve); } public function offsetExists($offset): bool { throw new Exception('Not supported!'); } public function offsetGet($offset) { return Tools::call((function () use ($offset) { return (yield $this)[$offset]; })()); } public function offsetSet($offset, $value) { return Tools::call((function () use ($offset, $value) { $result = yield $this; return $result[$offset] = value; })()); } public function offsetUnset($offset) { return Tools::call((function () use ($offset) { $result = yield $this; unset($result[$offset]); })()); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; /** * Stores multiple states. */ class CombinedUpdatesState { private $states = []; public function __construct($init = []) { $this->states[false] = new UpdatesState(); if (!is_array($init)) { return; } foreach ($init as $channel => $state) { if (is_array($state)) { $state = new UpdatesState($state, $channel); } $this->states[$channel] = $state; } } /** * Update multiple parameters. * * @param array|null $init * @param int $channel * * @return UpdatesState */ public function get($channel = null, $init = []) { if ($channel === null) { return $this->states; } if (!isset($this->states[$channel])) { return $this->states[$channel] = new UpdatesState($init, $channel); } return $this->states[$channel]->update($init); } /** * Remove update state. * * @param int $channel * * @return void */ public function remove($channel) { if (isset($this->states[$channel])) { unset($this->states[$channel]); } } /** * Check if update state is present. * * @param int $channel * * @return void */ public function has($channel) { return isset($this->states[$channel]); } /** * Are we currently busy? * * @param int $channel * @param bool|null $set * * @return bool */ public function syncLoading($channel, $set = null) { return $this->get($channel)->syncLoading($set); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; /** * Stores the state of updates. */ class UpdatesState { /** * PTS. * * @var int */ private $pts = 1; /** * QTS. * * @var int */ private $qts = -1; /** * Seq. * * @var int */ private $seq = 0; /** * Date. * * @var int */ private $date = 1; /** * Channel ID. * * @var int|bool */ private $channelId; /** * Is busy? * * @var bool */ private $syncLoading = false; /** * Init function. * * @param array $init Initial parameters * @param bool $channelId Channel ID */ public function __construct($init = [], $channelId = false) { $this->channelId = $channelId; $this->update($init); } /** * Sleep function. * * @return array Parameters to serialize */ public function __sleep() { return $this->channelId ? ['pts', 'channelId'] : ['pts', 'qts', 'seq', 'date', 'channelId']; } /** * Is this state relative to a channel? * * @return bool */ public function isChannel() { return (bool) $this->channelId; } /** * Get the channel ID. * * @return int|null */ public function getChannel() { return $this->channelId; } /** * Are we currently busy? * * @param bool|null $set * * @return bool */ public function syncLoading($set = null) { if ($set !== null) { $this->syncLoading = $set; } return $this->syncLoading; } /** * Update multiple parameters. * * @param array $init * * @return self */ public function update($init) { foreach ($this->channelId ? ['pts'] : ['pts', 'qts', 'seq', 'date'] as $param) { if (isset($init[$param])) { $this->{$param}($init[$param]); } } return $this; } /** * Get/set PTS. * * @param int $set * * @return int */ public function pts($set = 0) { if ($set !== 0 && $set > $this->pts) { $this->pts = $set; } return $this->pts; } /** * Get/set QTS. * * @param int $set * * @return int */ public function qts($set = 0) { if ($set !== 0 && $set > $this->qts) { $this->qts = $set; } return $this->qts; } /** * Get/set seq. * * @param int $set * * @return int */ public function seq($set = 0) { if ($set !== 0 && $set > $this->seq) { $this->seq = $set; } return $this->seq; } /** * Get/set date. * * @param int $set * * @return int */ public function date($set = 0) { if ($set !== 0 && $set > $this->date) { $this->date = $set; } return $this->date; } /** * Check validity of PTS contained in update. * * @param array $update * * @return int -1 if it's too old, 0 if it's ok, 1 if it's too new */ public function checkPts($update) { return $update['pts'] - ($this->pts + $update['pts_count']); } /** * Check validity of seq contained in update. * * @param int $seq * * @return int -1 if it's too old, 0 if it's ok, 1 if it's too new */ public function checkSeq($seq) { return $seq ? $seq - ($this->seq + 1) : $seq; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use danog\MadelineProto\Async\AsyncParameters; use danog\MadelineProto\Exception; use danog\MadelineProto\Logger; use danog\MadelineProto\RPCErrorException; use function Amp\Promise\all; /** * Manages upload and download of files. */ trait Files { public function upload_async($file, $file_name = '', $cb = null, $encrypted = false): \Generator { if (is_object($file)) { if (!isset(class_implements($file)['danog\MadelineProto\FileCallbackInterface'])) { throw new \danog\MadelineProto\Exception('Provided object does not implement FileCallbackInterface'); } $cb = $file; $file = $file->getFile(); } $t = microtime(true); $file = \danog\MadelineProto\Absolute::absolute($file); if (!file_exists($file)) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['file_not_exist']); } if (empty($file_name)) { $file_name = basename($file); } $datacenter = $this->settings['connection_settings']['default_dc']; if (isset($this->datacenter->sockets[$datacenter.'_media'])) { $datacenter .= '_media'; } $file_size = filesize($file); if ($file_size > 512 * 1024 * 3000) { throw new \danog\MadelineProto\Exception('Given file is too big!'); } if ($cb === null) { $cb = function ($percent) { $this->logger->logger('Upload status: '.$percent.'%', \danog\MadelineProto\Logger::NOTICE); }; } $part_size = $this->settings['upload']['part_size']; $part_total_num = (int) ceil($file_size / $part_size); $part_num = 0; $method = $file_size > 10 * 1024 * 1024 ? 'upload.saveBigFilePart' : 'upload.saveFilePart'; $constructor = 'input'.($encrypted === true ? 'Encrypted' : '').($file_size > 10 * 1024 * 1024 ? 'FileBig' : 'File').($encrypted === true ? 'Uploaded' : ''); $file_id = $this->random(8); $f = fopen($file, 'r'); $seekable = stream_get_meta_data($f)['seekable']; if ($seekable) { fseek($f, 0); } $ige = null; if ($encrypted === true) { $key = $this->random(32); $iv = $this->random(32); $digest = hash('md5', $key.$iv, true); $fingerprint = $this->unpack_signed_int(substr($digest, 0, 4) ^ substr($digest, 4, 4)); $ige = new \phpseclib\Crypt\AES('ige'); $ige->setIV($iv); $ige->setKey($key); $ige->enableContinuousBuffer(); } $ctx = hash_init('md5'); $promises = []; $cur_part_num = 0; while ($part_num < $part_total_num) { $t = microtime(true); $read_deferred = yield $this->method_call_async_write( $method, new AsyncParameters( static function () use ($file_id, $part_num, $part_total_num, $part_size, $f, $ctx, $ige, $seekable) { if ($seekable) { fseek($f, $part_num * $part_size); } elseif (ftell($f) !== $part_num * $part_size) { throw new \danog\MadelineProto\Exception('Wrong position!'); } $bytes = stream_get_contents($f, $part_size); if ($ige) { $bytes = $ige->encrypt(str_pad($bytes, $part_size, chr(0))); } hash_update($ctx, $bytes); return ['file_id' => $file_id, 'file_part' => $part_num, 'file_total_parts' => $part_total_num, 'bytes' => $bytes]; }, $seekable ), ['heavy' => true, 'file' => true, 'datacenter' => $datacenter] ); $this->callFork($cb(ftell($f) * 100 / $file_size)); $this->logger->logger('Speed for chunk: '.(($part_size * 8 / 1000000) / (microtime(true) - $t))); $part_num++; $promises[] = $read_deferred->promise(); } $result = yield all($promises); foreach ($result as $key => $result) { if (!$result) { throw new \danog\MadelineProto\Exception('Upload of part '.$key.' failed'); } } $constructor = ['_' => $constructor, 'id' => $file_id, 'parts' => $part_total_num, 'name' => $file_name, 'mime_type' => $this->get_mime_from_file($file)]; if ($encrypted === true) { $constructor['key_fingerprint'] = $fingerprint; $constructor['key'] = $key; $constructor['iv'] = $iv; } fclose($f); clearstatcache(); $this->logger->logger('Speed: '.(($file_size * 8) / (microtime(true) - $t) / 1000000)); return $constructor; } public function upload_encrypted_async($file, $file_name = '', $cb = null) { return $this->upload_async($file, $file_name, $cb, true); } public function gen_all_file_async($media, $regenerate) { $res = [$this->constructors->find_by_predicate($media['_'])['type'] => $media]; switch ($media['_']) { case 'messageMediaPoll': $res['Poll'] = $media['poll']; $res['InputMedia'] = ['_' => 'inputMediaPoll', 'poll' => $res['Poll']]; break; case 'updateMessagePoll': $res['Poll'] = $media['poll']; $res['InputMedia'] = ['_' => 'inputMediaPoll', 'poll' => $res['Poll']]; $res['MessageMedia'] = ['_' => 'messageMediaPoll', 'poll' => $res['Poll'], 'results' => $media['results']]; break; case 'messageMediaPhoto': if (!isset($media['photo']['access_hash'])) { throw new \danog\MadelineProto\Exception('No access hash'); } $res['Photo'] = $media['photo']; $res['InputPhoto'] = ['_' => 'inputPhoto', 'id' => $media['photo']['id'], 'access_hash' => $media['photo']['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION, $media['photo'])]; $res['InputMedia'] = ['_' => 'inputMediaPhoto', 'id' => $res['InputPhoto']]; if (isset($media['ttl_seconds'])) { $res['InputMedia']['ttl_seconds'] = $media['ttl_seconds']; } break; case 'messageMediaDocument': if (!isset($media['document']['access_hash'])) { throw new \danog\MadelineProto\Exception('No access hash'); } $res['Document'] = $media['document']; $res['InputDocument'] = ['_' => 'inputDocument', 'id' => $media['document']['id'], 'access_hash' => $media['document']['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $media['document'])]; $res['InputMedia'] = ['_' => 'inputMediaDocument', 'id' => $res['InputDocument']]; if (isset($media['ttl_seconds'])) { $res['InputMedia']['ttl_seconds'] = $media['ttl_seconds']; } break; case 'poll': $res['InputMedia'] = ['_' => 'inputMediaPoll', 'poll' => $res['Poll']]; break; case 'document': if (!isset($media['access_hash'])) { throw new \danog\MadelineProto\Exception('No access hash'); } $res['InputDocument'] = ['_' => 'inputDocument', 'id' => $media['id'], 'access_hash' => $media['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION, $media)]; $res['InputMedia'] = ['_' => 'inputMediaDocument', 'id' => $res['InputDocument']]; $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $media]; break; case 'photo': if (!isset($media['access_hash'])) { throw new \danog\MadelineProto\Exception('No access hash'); } $res['InputPhoto'] = ['_' => 'inputPhoto', 'id' => $media['id'], 'access_hash' => $media['access_hash'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION, $media)]; $res['InputMedia'] = ['_' => 'inputMediaPhoto', 'id' => $res['InputPhoto']]; $res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $media]; break; default: throw new \danog\MadelineProto\Exception("Could not convert media object of type {$media['_']}"); } return $res; } public function get_file_info_async($constructor, $regenerate = false) { if (is_string($constructor)) { $constructor = $this->unpack_file_id($constructor)['MessageMedia']; } switch ($constructor['_']) { case 'updateNewMessage': case 'updateNewChannelMessage': case 'updateEditMessage': case 'updateEditChannelMessage': $constructor = $constructor['message']; case 'message': $constructor = $constructor['media']; } return yield $this->gen_all_file_async($constructor, $regenerate); } public function get_download_info_async($message_media) { if (is_string($message_media)) { $message_media = $this->unpack_file_id($message_media)['MessageMedia']; } if (!isset($message_media['_'])) { return $message_media; } $res = []; switch ($message_media['_']) { // Updates case 'updateNewMessage': case 'updateNewChannelMessage': $message_media = $message_media['message']; case 'message': return yield $this->get_download_info_async($message_media['media']); case 'updateNewEncryptedMessage': $message_media = $message_media['message']; // Secret media case 'encryptedMessage': if ($message_media['decrypted_message']['media']['_'] === 'decryptedMessageMediaExternalDocument') { return yield $this->get_download_info_async($message_media['decrypted_message']['media']); } $res['InputFileLocation'] = ['_' => 'inputEncryptedFileLocation', 'id' => $message_media['file']['id'], 'access_hash' => $message_media['file']['access_hash'], 'dc_id' => $message_media['file']['dc_id']]; $res['size'] = $message_media['decrypted_message']['media']['size']; $res['key_fingerprint'] = $message_media['file']['key_fingerprint']; $res['key'] = $message_media['decrypted_message']['media']['key']; $res['iv'] = $message_media['decrypted_message']['media']['iv']; if (isset($message_media['decrypted_message']['media']['file_name'])) { $pathinfo = pathinfo($message_media['decrypted_message']['media']['file_name']); if (isset($pathinfo['extension'])) { $res['ext'] = '.'.$pathinfo['extension']; } $res['name'] = $pathinfo['filename']; } if (isset($message_media['decrypted_message']['media']['mime_type'])) { $res['mime'] = $message_media['decrypted_message']['media']['mime_type']; } elseif ($message_media['decrypted_message']['media']['_'] === 'decryptedMessageMediaPhoto') { $res['mime'] = 'image/jpeg'; } if (isset($message_media['decrypted_message']['media']['attributes'])) { foreach ($message_media['decrypted_message']['media']['attributes'] as $attribute) { switch ($attribute['_']) { case 'documentAttributeFilename': $pathinfo = pathinfo($attribute['file_name']); if (isset($pathinfo['extension'])) { $res['ext'] = '.'.$pathinfo['extension']; } $res['name'] = $pathinfo['filename']; break; case 'documentAttributeAudio': $audio = $attribute; break; } } } if (isset($audio) && isset($audio['title']) && !isset($res['name'])) { $res['name'] = $audio['title']; if (isset($audio['performer'])) { $res['name'] .= ' - '.$audio['performer']; } } if (!isset($res['ext'])) { $res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], $this->get_extension_from_mime(isset($res['mime']) ? $res['mime'] : 'image/jpeg')); } if (!isset($res['mime'])) { $res['mime'] = $this->get_mime_from_extension($res['ext'], 'image/jpeg'); } if (!isset($res['name'])) { $res['name'] = $message_media['file']['access_hash']; } return $res; // Wallpapers case 'wallPaper': $photo = end($message_media['sizes']); return array_merge($res, yield $this->get_download_info_async($photo)); // Photos case 'photo': case 'messageMediaPhoto': if ($message_media['_'] == 'photo') { $res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $message_media, 'ttl_seconds' => 0]; $photo = end($message_media['sizes']); } else { $res['MessageMedia'] = $message_media; $photo = end($message_media['photo']['sizes']); } return array_merge($res, yield $this->get_download_info_async($photo)); case 'userProfilePhoto': case 'chatPhoto': return array_merge($res, yield $this->get_download_info_async($message_media['photo_big'])); case 'photoCachedSize': $res['size'] = strlen($message_media['bytes']); $res['data'] = $message_media['bytes']; if ($message_media['location']['_'] === 'fileLocationUnavailable') { $res['name'] = $message_media['volume_id'].'_'.$message_media['local_id']; $res['mime'] = $this->get_mime_from_buffer($res['data']); $res['ext'] = $this->get_extension_from_mime($res['mime']); } else { $res = array_merge($res, yield $this->get_download_info_async($message_media['location'])); } return $res; case 'photoSize': $res = yield $this->get_download_info_async($message_media['location']); if (isset($message_media['size'])) { $res['size'] = $message_media['size']; } return $res; case 'fileLocationUnavailable': throw new \danog\MadelineProto\Exception('File location unavailable'); case 'fileLocation': $res['name'] = $message_media['volume_id'].'_'.$message_media['local_id']; $res['InputFileLocation'] = ['_' => 'inputFileLocation', 'volume_id' => $message_media['volume_id'], 'local_id' => $message_media['local_id'], 'secret' => $message_media['secret'], 'dc_id' => $message_media['dc_id'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::PHOTO_LOCATION_LOCATION, $message_media)]; $res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], '.jpg'); $res['mime'] = $this->get_mime_from_extension($res['ext'], 'image/jpeg'); return $res; // Documents case 'decryptedMessageMediaExternalDocument': case 'document': $message_media = ['_' => 'messageMediaDocument', 'ttl_seconds' => 0, 'document' => $message_media]; case 'messageMediaDocument': $res['MessageMedia'] = $message_media; foreach ($message_media['document']['attributes'] as $attribute) { switch ($attribute['_']) { case 'documentAttributeFilename': $pathinfo = pathinfo($attribute['file_name']); if (isset($pathinfo['extension'])) { $res['ext'] = '.'.$pathinfo['extension']; } $res['name'] = $pathinfo['filename']; break; case 'documentAttributeAudio': $audio = $attribute; break; } } if (isset($audio) && isset($audio['title']) && !isset($res['name'])) { $res['name'] = $audio['title']; if (isset($audio['performer'])) { $res['name'] .= ' - '.$audio['performer']; } } $res['InputFileLocation'] = ['_' => 'inputDocumentFileLocation', 'id' => $message_media['document']['id'], 'access_hash' => $message_media['document']['access_hash'], 'version' => isset($message_media['document']['version']) ? $message_media['document']['version'] : 0, 'dc_id' => $message_media['document']['dc_id'], 'file_reference' => yield $this->referenceDatabase->getReference(ReferenceDatabase::DOCUMENT_LOCATION_LOCATION, $message_media['document'])]; if (!isset($res['ext'])) { $res['ext'] = $this->get_extension_from_location($res['InputFileLocation'], $this->get_extension_from_mime($message_media['document']['mime_type'])); } if (!isset($res['name'])) { $res['name'] = $message_media['document']['access_hash']; } if (isset($message_media['document']['size'])) { $res['size'] = $message_media['document']['size']; } $res['name'] .= '_'.$message_media['document']['id']; $res['mime'] = $message_media['document']['mime_type']; return $res; default: throw new \danog\MadelineProto\Exception('Invalid constructor provided: '.$message_media['_']); } } public function download_to_dir_async($message_media, $dir, $cb = null) { if (is_object($dir) && class_implements($dir)['danog\MadelineProto\FileCallbackInterface']) { $cb = $dir; $dir = $dir->getFile(); } $message_media = yield $this->get_download_info_async($message_media); return yield $this->download_to_file_async($message_media, $dir.'/'.$message_media['name'].$message_media['ext'], $cb); } public function download_to_file_async($message_media, $file, $cb = null) { if (is_object($file) && class_implements($file)['danog\MadelineProto\FileCallbackInterface']) { $cb = $file; $file = $file->getFile(); } $file = \danog\MadelineProto\Absolute::absolute(preg_replace('|/+|', '/', $file)); if (!file_exists($file)) { touch($file); } $file = realpath($file); $message_media = yield $this->get_download_info_async($message_media); $stream = fopen($file, 'r+b'); $size = fstat($stream)['size']; $this->logger->logger('Waiting for lock of file to download...'); flock($stream, LOCK_EX); try { yield $this->download_to_stream_async($message_media, $stream, $cb, $size, -1); } finally { flock($stream, LOCK_UN); fclose($stream); clearstatcache(); } return $file; } public function download_to_stream_async($message_media, $stream, $cb = null, $offset = 0, $end = -1) { if (is_object($stream) && class_implements($stream)['danog\MadelineProto\FileCallbackInterface']) { $cb = $stream; $stream = $stream->getFile(); } if ($cb === null) { $cb = function ($percent) { $this->logger->logger('Download status: '.$percent.'%', \danog\MadelineProto\Logger::NOTICE); }; } $message_media = yield $this->get_download_info_async($message_media); try { if (stream_get_meta_data($stream)['seekable']) { fseek($stream, $offset); } } catch (\danog\MadelineProto\Exception $e) { } $downloaded_size = 0; if ($end === -1 && isset($message_media['size'])) { $end = $message_media['size']; } $size = $end - $offset; $part_size = $this->settings['download']['part_size']; $percent = 0; $datacenter = isset($message_media['InputFileLocation']['dc_id']) ? $message_media['InputFileLocation']['dc_id'] : $this->settings['connection_settings']['default_dc']; if (isset($this->datacenter->sockets[$datacenter.'_media'])) { $datacenter .= '_media'; } if (isset($message_media['key'])) { $digest = hash('md5', $message_media['key'].$message_media['iv'], true); $fingerprint = $this->unpack_signed_int(substr($digest, 0, 4) ^ substr($digest, 4, 4)); if ($fingerprint !== $message_media['key_fingerprint']) { throw new \danog\MadelineProto\Exception('Fingerprint mismatch!'); } $ige = new \phpseclib\Crypt\AES('ige'); $ige->setIV($message_media['iv']); $ige->setKey($message_media['key']); $ige->enableContinuousBuffer(); } $theend = false; $cdn = false; while (true) { if ($start_at = $offset % $part_size) { $offset -= $start_at; } try { $res = $cdn ? yield $this->method_call_async_read('upload.getCdnFile', ['file_token' => $message_media['file_token'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'file' => true, 'datacenter' => $datacenter]) : yield $this->method_call_async_read('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'file' => true, 'datacenter' => &$datacenter]); } catch (\danog\MadelineProto\RPCErrorException $e) { if (strpos($e->rpc, 'FLOOD_WAIT_') === 0) { if (isset($message_media['MessageMedia']) && !$this->authorization['user']['bot'] && $this->settings['download']['report_broken_media']) { try { yield $this->method_call_async_read('messages.sendMedia', ['peer' => 'support', 'media' => $message_media['MessageMedia'], 'message' => "I can't download this file, could you please help?"], ['datacenter' => $this->datacenter->curdc]); } catch (RPCErrorException $e) { $this->logger->logger('An error occurred while reporting the broken file: '.$e->rpc, Logger::FATAL_ERROR); } catch (Exception $e) { $this->logger->logger('An error occurred while reporting the broken file: '.$e->getMessage(), Logger::FATAL_ERROR); } } throw new \danog\MadelineProto\Exception('The media server where this file is hosted is offline/overloaded, please try again later. Send the media to the telegram devs or to @danogentili to fix this.'); } switch ($e->rpc) { case 'FILE_TOKEN_INVALID': $cdn = false; continue 2; default: throw $e; } } if ($res['_'] === 'upload.fileCdnRedirect') { $cdn = true; $message_media['file_token'] = $res['file_token']; $message_media['cdn_key'] = $res['encryption_key']; $message_media['cdn_iv'] = $res['encryption_iv']; $old_dc = $datacenter; $datacenter = $res['dc_id'].'_cdn'; if (!isset($this->datacenter->sockets[$datacenter])) { $this->config['expires'] = -1; yield $this->get_config_async([], ['datacenter' => $this->datacenter->curdc]); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['stored_on_cdn'], \danog\MadelineProto\Logger::NOTICE); continue; } if ($res['_'] === 'upload.cdnFileReuploadNeeded') { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['cdn_reupload'], \danog\MadelineProto\Logger::NOTICE); yield $this->get_config_async([], ['datacenter' => $this->datacenter->curdc]); try { $this->add_cdn_hashes($message_media['file_token'], yield $this->method_call_async_read('upload.reuploadCdnFile', ['file_token' => $message_media['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $old_dc])); } catch (\danog\MadelineProto\RPCErrorException $e) { switch ($e->rpc) { case 'FILE_TOKEN_INVALID': case 'REQUEST_TOKEN_INVALID': $cdn = false; continue 2; default: throw $e; } } continue; } if ($cdn === false && $res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { $datacenter = 1; } while ($cdn === false && $res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { $res = yield $this->method_call_async_read('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]); $datacenter++; if (!isset($this->datacenter->sockets[$datacenter])) { break; } } if (isset($message_media['cdn_key'])) { $ivec = substr($message_media['cdn_iv'], 0, 12).pack('N', $offset >> 4); $res['bytes'] = $this->ctr_encrypt($res['bytes'], $message_media['cdn_key'], $ivec); $this->check_cdn_hash($message_media['file_token'], $offset, $res['bytes'], $old_dc); } if (isset($message_media['key'])) { $res['bytes'] = $ige->decrypt($res['bytes']); } if ($start_at) { $res['bytes'] = substr($res['bytes'], $start_at); } if ($end !== -1 && strlen($res['bytes']) + $downloaded_size >= $size) { $res['bytes'] = substr($res['bytes'], 0, $size - $downloaded_size); $theend = true; } if ($res['bytes'] === '') { break; } $offset += strlen($res['bytes']); $downloaded_size += strlen($res['bytes']); $this->logger->logger(fwrite($stream, $res['bytes']), \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($theend) { break; } if ($end !== -1) { $this->callFork($cb($percent = $downloaded_size * 100 / $size)); } } if ($end === -1) { $this->callFork($cb(100)); } if ($cdn) { $this->clear_cdn_hashes($message_media['file_token']); } return true; } private $cdn_hashes = []; private function add_cdn_hashes($file, $hashes) { if (!isset($this->cdn_hashes[$file])) { $this->cdn_hashes = []; } foreach ($hashes as $hash) { $this->cdn_hashes[$file][$hash['offset']] = ['limit' => $hash['limit'], 'hash' => (string) $hash['hash']]; } } private function check_cdn_hash($file, $offset, $data, &$datacenter) { while (strlen($data)) { if (!isset($this->cdn_hashes[$file][$offset])) { $this->add_cdn_hashes($file, yield $this->method_call_async_read('upload.getCdnFileHashes', ['file_token' => $file, 'offset' => $offset], ['datacenter' => $datacenter])); } if (!isset($this->cdn_hashes[$file][$offset])) { throw new \danog\MadelineProto\Exception('Could not fetch CDN hashes for offset '.$offset); } if (hash('sha256', substr($data, 0, $this->cdn_hashes[$file][$offset]['limit']), true) !== $this->cdn_hashes[$file][$offset]['hash']) { throw new \danog\MadelineProto\SecurityException('CDN hash mismatch for offset '.$offset); } $data = substr($data, $this->cdn_hashes[$file][$offset]['limit']); $offset += $this->cdn_hashes[$file][$offset]['limit']; } return true; } private function clear_cdn_hashes($file) { unset($this->cdn_hashes[$file]); return true; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use Amp\Deferred; use Amp\Promise; use danog\MadelineProto\Async\Parameters; use function Amp\Promise\all; /** * Manages method and object calls. */ trait CallHandler { public function method_recall($watcherId, $args) { $message_id = $args['message_id']; $new_datacenter = $args['datacenter']; $old_datacenter = $new_datacenter; if (isset($args['old_datacenter'])) { $old_datacenter = $args['old_datacenter']; } $postpone = false; if (isset($args['postpone'])) { $postpone = $args['postpone']; } if (isset($this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['container'])) { $message_ids = $this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['container']; } else { $message_ids = [$message_id]; } foreach ($message_ids as $message_id) { if (isset($this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['body'])) { $this->callFork($this->datacenter->sockets[$new_datacenter]->sendMessage($this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id], false)); $this->ack_outgoing_message_id($message_id, $old_datacenter); $this->got_response_for_outgoing_message_id($message_id, $old_datacenter); } else { $this->logger->logger('Could not resend '.isset($this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['_']) ? $this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['_'] : $message_id); } } if (!$postpone) { $this->datacenter->sockets[$new_datacenter]->writer->resume(); } } public function method_call($method, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]) { return $this->wait($this->method_call_async_read($method, $args, $aargs)); } public function method_call_async_read($method, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]) { $deferred = new Deferred(); $this->method_call_async_write($method, $args, $aargs)->onResolve(function ($e, $read_deferred) use ($deferred) { if ($e) { $deferred->fail($e); } else { if (is_array($read_deferred)) { $read_deferred = array_map(function ($value) { return $value->promise(); }, $read_deferred); $deferred->resolve(all($read_deferred)); } else { $deferred->resolve($read_deferred->promise()); } } }); return isset($aargs['noResponse']) && $aargs['noResponse'] ? 0 : $deferred->promise(); } public function method_call_async_write($method, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]): Promise { return $this->call($this->method_call_async_write_generator($method, $args, $aargs)); } public function method_call_async_write_generator($method, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]): \Generator { if (is_array($args) && isset($args['id']['_']) && isset($args['id']['dc_id']) && $args['id']['_'] === 'inputBotInlineMessageID') { $aargs['datacenter'] = $args['id']['dc_id']; } if ($this->wrapper instanceof \danog\MadelineProto\API && isset($this->wrapper->session) && !is_null($this->wrapper->session) && time() - $this->wrapper->serialized > $this->settings['serialization']['serialization_interval'] && !$this->asyncInitPromise) { $this->logger->logger("Didn't serialize in a while, doing that now..."); $this->wrapper->serialize($this->wrapper->session); } if (isset($aargs['file']) && $aargs['file'] && isset($this->datacenter->sockets[$aargs['datacenter'].'_media'])) { $this->logger->logger('Using media DC'); $aargs['datacenter'] .= '_media'; } if (in_array($method, ['messages.setEncryptedTyping', 'messages.readEncryptedHistory', 'messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService', 'messages.receivedQueue'])) { $aargs['queue'] = 'secret'; } if (is_array($args)) { if (isset($args['multiple'])) { $aargs['multiple'] = true; } if (isset($args['message']) && is_string($args['message']) && mb_strlen($args['message'], 'UTF-8') > $this->config['message_length_max'] && mb_strlen((yield $this->parse_mode_async($args))['message'], 'UTF-8') > $this->config['message_length_max']) { $args = yield $this->split_to_chunks_async($args); $promises = []; $aargs['queue'] = $method; $aargs['multiple'] = true; } if (isset($aargs['multiple'])) { $new_aargs = $aargs; $new_aargs['postpone'] = true; unset($new_aargs['multiple']); if (isset($args['multiple'])) { unset($args['multiple']); } foreach ($args as $single_args) { $promises[] = $this->method_call_async_write($method, $single_args, $new_aargs); } if (!isset($aargs['postpone'])) { $this->datacenter->sockets[$aargs['datacenter']]->writer->resume(); } return yield all($promises); } $args = yield $this->botAPI_to_MTProto_async($args); if (isset($args['ping_id']) && is_int($args['ping_id'])) { $args['ping_id'] = $this->pack_signed_long($args['ping_id']); } } $deferred = new Deferred(); $message = ['_' => $method, 'type' => $this->methods->find_by_method($method)['type'], 'content_related' => $this->content_related($method), 'promise' => $deferred, 'method' => true, 'unencrypted' => $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key === null && strpos($method, '.') === false]; if (is_object($args) && $args instanceof Parameters) { $message['body'] = yield $args->fetchParameters(); } else { $message['body'] = $args; } if (isset($aargs['msg_id'])) { $message['msg_id'] = $aargs['msg_id']; } if (isset($aargs['queue'])) { $message['queue'] = $aargs['queue']; } if (isset($aargs['file'])) { $message['file'] = $aargs['file']; } if (isset($aargs['botAPI'])) { $message['botAPI'] = $aargs['botAPI']; } if (isset($aargs['FloodWaitLimit'])) { $message['FloodWaitLimit'] = $aargs['FloodWaitLimit']; } if (($method === 'users.getUsers' && $args === ['id' => [['_' => 'inputUserSelf']]]) || $method === 'auth.exportAuthorization' || $method === 'updates.getDifference') { $message['user_related'] = true; } $deferred = yield $this->datacenter->sockets[$aargs['datacenter']]->sendMessage($message, isset($aargs['postpone']) ? !$aargs['postpone'] : true); $this->datacenter->sockets[$aargs['datacenter']]->checker->resume(); return $deferred; } public function object_call_async($object, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]) { $message = ['_' => $object, 'body' => $args, 'content_related' => $this->content_related($object), 'unencrypted' => $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key === null, 'method' => false]; if (isset($aargs['promise'])) { $message['promise'] = $aargs['promise']; } return $this->datacenter->sockets[$aargs['datacenter']]->sendMessage($message, isset($aargs['postpone']) ? !$aargs['postpone'] : true); } /* $message = [ // only in outgoing messages 'body' => deserialized body, (optional if container) 'serialized_body' => 'serialized body', (optional if container) 'content_related' => bool, '_' => 'predicate', 'promise' => deferred promise that gets resolved when a response to the message is received (optional), 'send_promise' => deferred promise that gets resolved when the message is sent (optional), 'file' => bool (optional), 'type' => 'type' (optional), 'queue' => queue ID (optional), 'container' => [message ids] (optional), // only in incoming messages 'content' => deserialized body, 'seq_no' => number (optional), 'from_container' => bool (optional), // can be present in both 'response' => message id (optional), 'msg_id' => message id (optional), 'sent' => timestamp, 'tries' => number ]; */ } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use danog\MadelineProto\Exception; use danog\MadelineProto\TL\TLCallback; use danog\MadelineProto\Tools; /** * Manages upload and download of files. */ class ReferenceDatabase implements TLCallback { use Tools; // Reference from a document const DOCUMENT_LOCATION = 0; // Reference from a photo const PHOTO_LOCATION = 1; // Reference from a location (can only be photo location) const PHOTO_LOCATION_LOCATION = 2; // Reference from a location (can only be document location) const DOCUMENT_LOCATION_LOCATION = 0; // Peer + photo ID const USER_PHOTO_ORIGIN = 0; // Peer (default photo ID) const PEER_PHOTO_ORIGIN = 1; // set ID const STICKER_SET_ID_ORIGIN = 2; // Peer + msg ID const MESSAGE_ORIGIN = 3; // const SAVED_GIFS_ORIGIN = 4; // const STICKER_SET_RECENT_ORIGIN = 5; // const STICKER_SET_FAVED_ORIGIN = 6; // emoticon const STICKER_SET_EMOTICON_ORIGIN = 8; // const WALLPAPER_ORIGIN = 9; const LOCATION_CONTEXT = [ 'inputFileLocation' => self::PHOTO_LOCATION_LOCATION, 'inputDocumentFileLocation' => self::DOCUMENT_LOCATION_LOCATION, 'inputPhoto' => self::PHOTO_LOCATION, 'inputDocument' => self::DOCUMENT_LOCATION, ]; const METHOD_CONTEXT = [ 'photos.updateProfilePhoto' => self::USER_PHOTO_ORIGIN, 'photos.getUserPhotos' => self::USER_PHOTO_ORIGIN, 'photos.uploadProfilePhoto' => self::USER_PHOTO_ORIGIN, 'messages.getStickers' => self::STICKER_SET_EMOTICON_ORIGIN, ]; const CONSTRUCTOR_CONTEXT = [ 'message' => self::MESSAGE_ORIGIN, 'messageService' => self::MESSAGE_ORIGIN, 'chatFull' => self::PEER_PHOTO_ORIGIN, 'channelFull' => self::PEER_PHOTO_ORIGIN, 'chat' => self::PEER_PHOTO_ORIGIN, 'channel' => self::PEER_PHOTO_ORIGIN, 'updateUserPhoto' => self::USER_PHOTO_ORIGIN, 'user' => self::USER_PHOTO_ORIGIN, 'userFull' => self::USER_PHOTO_ORIGIN, 'wallPaper' => self::WALLPAPER_ORIGIN, 'messages.savedGifs' => self::SAVED_GIFS_ORIGIN, 'messages.recentStickers' => self::STICKER_SET_RECENT_ORIGIN, 'messages.favedStickers' => self::STICKER_SET_FAVED_ORIGIN, 'messages.stickerSet' => self::STICKER_SET_ID_ORIGIN, 'document' => self::STICKER_SET_ID_ORIGIN, ]; /** * References indexed by location. * * @var array */ private $db = []; private $cache = []; private $cacheContexts = []; private $refreshed = []; private $API; private $refresh = false; private $refreshCount = 0; public function __construct($API) { $this->API = $API; $this->init(); } public function __wakeup() { $this->init(); } public function __sleep() { return ['db', 'API']; } public function init() { } public function getMethodCallbacks(): array { return array_fill_keys(array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethod']]); } public function getMethodBeforeCallbacks(): array { return array_fill_keys(array_keys(self::METHOD_CONTEXT), [[$this, 'addOriginMethodContext']]); } public function getConstructorCallbacks(): array { return array_merge( array_fill_keys(['document', 'photo', 'fileLocation'], [[$this, 'addReference']]), array_fill_keys(array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOrigin']]), ['document' => [[$this, 'addReference'], [$this, 'addOrigin']]] ); } public function getConstructorBeforeCallbacks(): array { return array_fill_keys(array_keys(self::CONSTRUCTOR_CONTEXT), [[$this, 'addOriginContext']]); } public function getConstructorSerializeCallbacks(): array { return array_fill_keys(array_keys(self::LOCATION_CONTEXT), [$this, 'populateReference']); } public function getTypeMismatchCallbacks(): array { return []; } public function reset() { if ($this->cacheContexts) { $this->API->logger->logger('Found '.count($this->cacheContexts).' pending contexts', \danog\MadelineProto\Logger::ERROR); $this->cacheContexts = []; } if ($this->cache) { $this->API->logger->logger('Found pending locations', \danog\MadelineProto\Logger::ERROR); $this->cache = []; } } public function addReference(array $location) { if (!$this->cacheContexts) { $this->API->logger->logger('Trying to add reference out of context, report the following message to @danogentili!', \danog\MadelineProto\Logger::ERROR); $frames = []; $previous = ''; foreach (debug_backtrace(0) as $k => $frame) { if (isset($frame['function']) && $frame['function'] === 'deserialize') { if (isset($frame['args'][1]['subtype'])) { if ($frame['args'][1]['subtype'] === $previous) { continue; } $frames[] = $frame['args'][1]['subtype']; $previous = $frame['args'][1]['subtype']; } elseif (isset($frame['args'][1]['type'])) { if ($frame['args'][1]['type'] === '') { break; } if ($frame['args'][1]['type'] === $previous) { continue; } $frames[] = $frame['args'][1]['type']; $previous = $frame['args'][1]['type']; } } } $frames = array_reverse($frames); $tl_trace = array_shift($frames); foreach ($frames as $frame) { $tl_trace .= "['".$frame."']"; } $this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR); return false; } if (!isset($location['file_reference'])) { $this->API->logger->logger("Object {$location['_']} does not have reference", \danog\MadelineProto\Logger::ERROR); return false; } $key = count($this->cacheContexts) - 1; switch ($location['_']) { case 'document': $locationType = self::DOCUMENT_LOCATION; break; case 'photo': $locationType = self::PHOTO_LOCATION; break; case 'fileLocation': $locationType = self::PHOTO_LOCATION_LOCATION; break; default: throw new Exception('Unknown location type provided: '.$location['_']); } $this->API->logger->logger("Caching reference from location of type $locationType from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); if (!isset($this->cache[$key])) { $this->cache[$key] = []; } $this->cache[$key][$this->serializeLocation($locationType, $location)] = (string) $location['file_reference']; return true; } public function addOriginContext(string $type) { if (!isset(self::CONSTRUCTOR_CONTEXT[$type])) { throw new \danog\MadelineProto\Exception("Unknown origin type provided: $type"); } $originContext = self::CONSTRUCTOR_CONTEXT[$type]; $this->API->logger->logger("Adding origin context $originContext for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->cacheContexts[] = $originContext; } public function addOrigin(array $data = []) { $key = count($this->cacheContexts) - 1; if ($key === -1) { throw new \danog\MadelineProto\Exception('Trying to add origin with no origin context set'); } $originType = array_pop($this->cacheContexts); if (!isset($this->cache[$key])) { $this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; } $cache = $this->cache[$key]; unset($this->cache[$key]); $origin = []; switch ($data['_']) { case 'message': case 'messageService': $origin['peer'] = $this->API->get_id($data); $origin['msg_id'] = $data['id']; break; case 'messages.savedGifs': case 'messages.recentStickers': case 'messages.favedStickers': case 'wallPaper': break; case 'user': $origin['max_id'] = $data['photo']['photo_id']; $origin['offset'] = -1; $origin['limit'] = 1; $origin['user_id'] = $data['id']; break; case 'updateUserPhoto': $origin['max_id'] = $data['photo']['photo_id']; $origin['offset'] = -1; $origin['limit'] = 1; $origin['user_id'] = $data['user_id']; break; case 'userFull': $origin['max_id'] = $data['profile_photo']['id']; $origin['offset'] = -1; $origin['limit'] = 1; $origin['user_id'] = $data['user']['id']; break; case 'chatFull': case 'chat': $origin['peer'] = -$data['id']; break; case 'channelFull': case 'channel': $origin['peer'] = $this->API->to_supergroup($data['id']); break; case 'document': foreach ($data['attributes'] as $attribute) { if ($attribute['_'] === 'documentAttributeSticker' && $attribute['stickerset']['_'] !== 'inputStickerSetEmpty') { $origin['stickerset'] = $attribute['stickerset']; } } if (!isset($origin['stickerset'])) { $key = count($this->cacheContexts) - 1; if (!isset($this->cache[$key])) { $this->cache[$key] = []; } foreach ($cache as $location => $reference) { $this->cache[$key][$location] = $reference; } $this->API->logger->logger("Skipped origin $originType ({$data['_']}) for ".count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; } break; case 'messages.stickerSet': $origin['stickerset'] = ['_' => 'inputStickerSetID', 'id' => $data['set']['id'], 'access_hash' => $data['set']['access_hash']]; break; default: throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$data['_']}"); } foreach ($cache as $location => $reference) { $this->storeReference($location, $reference, $originType, $origin); } $this->API->logger->logger("Added origin $originType ({$data['_']}) to ".count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } public function addOriginMethodContext(string $type) { if (!isset(self::METHOD_CONTEXT[$type])) { throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$type}"); } $originContext = self::METHOD_CONTEXT[$type]; $this->API->logger->logger("Adding origin context $originContext for {$type}!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->cacheContexts[] = $originContext; } public function addOriginMethod(array $data, array $res) { $key = count($this->cacheContexts) - 1; if ($key === -1) { throw new \danog\MadelineProto\Exception('Trying to add origin with no origin context set'); } $originType = array_pop($this->cacheContexts); if (!isset($this->cache[$key])) { $this->API->logger->logger("Removing origin context $originType for {$data['_']}, nothing in the reference cache!", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; } $cache = $this->cache[$key]; unset($this->cache[$key]); $origin = []; $body = $data['body']; switch ($data['_']) { case 'photos.updateProfilePhoto': $origin['max_id'] = $res['photo_id']; $origin['offset'] = -1; $origin['limit'] = 1; $origin['user_id'] = $this->API->authorization['user']['id']; break; case 'photos.uploadProfilePhoto': $origin['max_id'] = $res['photo']['id']; $origin['offset'] = -1; $origin['limit'] = 1; $origin['user_id'] = $this->API->authorization['user']['id']; break; case 'photos.getUserPhotos': $origin['user_id'] = $body['user_id']; $origin['offset'] = -1; $origin['limit'] = 1; $count = 0; foreach ($res['photos'] as $photo) { $origin['max_id'] = $photo['id']; $location = $this->serializeLocation(self::PHOTO_LOCATION, $photo); if (isset($cache[$location])) { $reference = $cache[$location]; unset($cache[$location]); $this->storeReference($location, $reference, $originType, $origin); $count++; } if (isset($photo['sizes'])) { foreach ($photo['sizes'] as $size) { if (isset($size['location'])) { $location = $this->serializeLocation(self::PHOTO_LOCATION_LOCATION, $size['location']); if (isset($cache[$location])) { $reference = $cache[$location]; unset($cache[$location]); $this->storeReference($location, $reference, $originType, $origin); $count++; } } } } } $this->API->logger->logger("Added origin $originType ({$data['_']}) to $count references", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return; case 'messages.getStickers': $origin['emoticon'] = $body['emoticon']; break; default: throw new \danog\MadelineProto\Exception("Unknown origin type provided: {$data['_']}"); } foreach ($cache as $location => $reference) { $this->storeReference($location, $reference, $originType, $origin); } $this->API->logger->logger("Added origin $originType ({$data['_']}) to ".count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); } public function storeReference(string $location, string $reference, int $originType, array $origin) { if (!isset($this->db[$location])) { $this->db[$location] = ['origins' => []]; } $this->db[$location]['reference'] = $reference; $this->db[$location]['origins'][$originType] = $origin; if ($this->refresh) { $this->refreshed[$location] = true; } $key = count($this->cacheContexts) - 1; if ($key >= 0) { $this->cache[$key][$location] = $reference; } } public function refreshNext($refresh = false) { if ($this->refreshCount === 1 && !$refresh) { $this->refreshed = []; $this->refreshCount--; $this->refresh = false; } elseif ($this->refreshCount === 0 && $refresh) { $this->refreshed = []; $this->refreshCount++; $this->refresh = true; } elseif ($this->refreshCount === 0 && !$refresh) { } elseif ($refresh) { $this->refreshCount++; } elseif (!$refresh) { $this->refreshCount--; } } public function refreshReference(int $locationType, array $location) { return $this->refreshReferenceInternal($this->serializeLocation($locationType, $location)); } public function refreshReferenceInternal(string $location) { if (isset($this->refreshed[$location])) { $this->API->logger->logger('Reference already refreshed!', \danog\MadelineProto\Logger::VERBOSE); return $this->db[$location]['reference']; } ksort($this->db[$location]['origins']); $count = 0; foreach ($this->db[$location]['origins'] as $originType => &$origin) { $count++; $this->API->logger->logger("Try {$count} refreshing file reference with origin type {$originType}", \danog\MadelineProto\Logger::VERBOSE); switch ($originType) { // Peer + msg ID case self::MESSAGE_ORIGIN: if (is_array($origin['peer'])) { $origin['peer'] = $this->API->get_id($origin['peer']); } if ($origin['peer'] < 0) { yield $this->API->method_call_async_read('channels.getMessages', ['channel' => $origin['peer'], 'id' => [$origin['msg_id']]], ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; } yield $this->API->method_call_async_read('messages.getMessages', ['id' => [$origin['msg_id']]], ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; // Peer + photo ID case self::PEER_PHOTO_ORIGIN: if (isset($this->API->full_chats[$origin['peer']]['last_update'])) { $this->API->full_chats[$origin['peer']]['last_update'] = 0; } $this->API->get_full_info($origin['peer']); break; // Peer (default photo ID) case self::USER_PHOTO_ORIGIN: yield $this->API->method_call_async_read('photos.getUserPhotos', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; case self::SAVED_GIFS_ORIGIN: yield $this->API->method_call_async_read('messages.getSavedGifs', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; case self::STICKER_SET_ID_ORIGIN: yield $this->API->method_call_async_read('messages.getStickerSet', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; case self::STICKER_SET_RECENT_ORIGIN: yield $this->API->method_call_async_read('messages.getRecentStickers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; case self::STICKER_SET_FAVED_ORIGIN: yield $this->API->method_call_async_read('messages.getFavedStickers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; case self::STICKER_SET_EMOTICON_ORIGIN: yield $this->API->method_call_async_read('messages.getStickers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; case self::WALLPAPER_ORIGIN: yield $this->API->method_call_async_read('account.getWallPapers', $origin, ['datacenter' => $this->API->settings['connection_settings']['default_dc']]); break; default: throw new \danog\MadelineProto\Exception("Unknown origin type $originType"); } if (isset($this->refreshed[$location])) { return $this->db[$location]['reference']; } } throw new Exception('Did not refresh reference'); } public function populateReference(array $object) { $object['file_reference'] = yield $this->getReference(self::LOCATION_CONTEXT[$object['_']], $object); return $object; } public function getReference(int $locationType, array $location) { $locationString = $this->serializeLocation($locationType, $location); if (!isset($this->db[$locationString]['reference'])) { if (isset($location['file_reference'])) { $this->API->logger->logger("Using outdated file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return $location['file_reference']; } if (!$this->refresh) { $this->API->logger->logger("Using null file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); return 0; } throw new \danog\MadelineProto\Exception("Could not find file reference for location of type $locationType object {$location['_']}"); } $this->API->logger->logger("Getting file reference for location of type $locationType object {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($this->refresh) { return $this->refreshReferenceInternal($locationString); } return $this->db[$locationString]['reference']; } private function serializeLocation(int $locationType, array $location) { switch ($locationType) { case self::DOCUMENT_LOCATION: case self::DOCUMENT_LOCATION_LOCATION: case self::PHOTO_LOCATION: return $locationType.(is_int($location['id']) ? $this->pack_signed_long($location['id']) : $location['id']); case self::PHOTO_LOCATION_LOCATION: $dc_id = $this->pack_signed_int($location['dc_id']); $volume_id = is_int($location['volume_id']) ? $this->pack_signed_long($location['volume_id']) : $location['volume_id']; $local_id = $this->pack_signed_int($location['local_id']); return $locationType.$dc_id.$volume_id.$local_id; } } public function __debugInfo() { return ['ReferenceDatabase instance '.spl_object_hash($this)]; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use danog\MadelineProto\MTProto; /** * Manages sequence number. */ trait SeqNoHandler { public function content_related($method) { $method = is_array($method) && isset($method['_']) ? $method['_'] : $method; return is_string($method) ? !in_array($method, MTProto::NOT_CONTENT_RELATED) : true; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; trait Crypt { public function aes_calculate($msg_key, $auth_key, $to_server = true) { $x = $to_server ? 0 : 8; $sha256_a = hash('sha256', $msg_key.substr($auth_key, $x, 36), true); $sha256_b = hash('sha256', substr($auth_key, 40 + $x, 36).$msg_key, true); $aes_key = substr($sha256_a, 0, 8).substr($sha256_b, 8, 16).substr($sha256_a, 24, 8); $aes_iv = substr($sha256_b, 0, 8).substr($sha256_a, 8, 16).substr($sha256_b, 24, 8); return [$aes_key, $aes_iv]; } public function old_aes_calculate($msg_key, $auth_key, $to_server = true) { $x = $to_server ? 0 : 8; $sha1_a = sha1($msg_key.substr($auth_key, $x, 32), true); $sha1_b = sha1(substr($auth_key, 32 + $x, 16).$msg_key.substr($auth_key, 48 + $x, 16), true); $sha1_c = sha1(substr($auth_key, 64 + $x, 32).$msg_key, true); $sha1_d = sha1($msg_key.substr($auth_key, 96 + $x, 32), true); $aes_key = substr($sha1_a, 0, 8).substr($sha1_b, 8, 12).substr($sha1_c, 4, 12); $aes_iv = substr($sha1_a, 8, 12).substr($sha1_b, 0, 8).substr($sha1_c, 16, 4).substr($sha1_d, 0, 8); return [$aes_key, $aes_iv]; } public function ctr_encrypt($message, $key, $iv) { $cipher = new \phpseclib\Crypt\AES('ctr'); $cipher->setKey($key); $cipher->setIV($iv); return @$cipher->encrypt($message); } public function ige_encrypt($message, $key, $iv) { $cipher = new \phpseclib\Crypt\AES('ige'); $cipher->setKey($key); $cipher->setIV($iv); return @$cipher->encrypt($message); } public function ige_decrypt($message, $key, $iv) { $cipher = new \phpseclib\Crypt\AES('ige'); $cipher->setKey($key); $cipher->setIV($iv); return @$cipher->decrypt($message); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use Amp\Artax\Request; /** * Manages peers. */ trait PeerHandler { public $caching_simple = []; public $caching_simple_username = []; public $caching_possible_username = []; public function to_supergroup($id) { return -($id + pow(10, (int) floor(log($id, 10) + 3))); } public function from_supergroup($id) { return -$id - pow(10, (int) floor(log(-$id, 10))); } public function is_supergroup($id) { $log = log(-$id, 10); return ($log - intval($log)) * 1000 < 10; } public function add_support($support) { $this->supportUser = $support['user']['id']; } public function add_user($user) { if (!isset($user['access_hash'])) { /*if (isset($this->chats[$user['id']]['access_hash']) && $this->chats[$user['id']]['access_hash']) { $this->logger->logger("No access hash with user {$user['id']}, using backup"); $user['access_hash'] = $this->chats[$user['id']]['access_hash']; } else { $this->logger->logger("No access hash with user {$user['id']}, not trying to fetch it"); $user['access_hash'] = 0; }*/ if (!isset($this->caching_simple[$user['id']]) && !(isset($user['username']) && isset($this->caching_simple_username[$user['username']]))) { $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by ID..."); if (isset($user['username']) && !isset($this->caching_simple_username[$user['username']])) { $this->caching_possible_username[$user['id']] = $user['username']; } $this->cache_pwr_chat($user['id'], false, true); } elseif (isset($user['username']) && !isset($this->chats[$user['id']]) && !isset($this->caching_simple_username[$user['username']])) { $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by username..."); $this->cache_pwr_chat($user['username'], false, true); } else { $this->logger->logger("No access hash with user {$user['id']}, tried and failed to fetch data..."); } return; } switch ($user['_']) { case 'user': if (!isset($this->chats[$user['id']]) || $this->chats[$user['id']] !== $user) { $this->logger->logger("Updated user {$user['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->chats[$user['id']] = $user; $this->cache_pwr_chat($user['id'], false, true); } case 'userEmpty': break; default: throw new \danog\MadelineProto\Exception('Invalid user provided', $user); break; } } public function add_chat_async($chat) { switch ($chat['_']) { case 'chat': case 'chatEmpty': case 'chatForbidden': if (!isset($this->chats[-$chat['id']]) || $this->chats[-$chat['id']] !== $chat) { $this->logger->logger("Updated chat -{$chat['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->chats[-$chat['id']] = $chat; $this->cache_pwr_chat(-$chat['id'], $this->settings['peer']['full_fetch'], true); } break; case 'channelEmpty': break; case 'channel': case 'channelForbidden': $bot_api_id = $this->to_supergroup($chat['id']); if (!isset($chat['access_hash'])) { if (!isset($this->caching_simple[$bot_api_id]) && !(isset($chat['username']) && isset($this->caching_simple_username[$chat['username']]))) { $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by ID..."); if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) { $this->caching_possible_username[$bot_api_id] = $chat['username']; } $this->cache_pwr_chat($bot_api_id, false, true); } elseif (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) { $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username..."); $this->cache_pwr_chat($chat['username'], false, true); } else { $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data..."); } return; } if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) { $this->logger->logger("Updated chat $bot_api_id", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->chats[$bot_api_id] = $chat; if ($this->settings['peer']['full_fetch'] && (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== (yield $this->get_full_info_async($bot_api_id))['full']['participants_count'])) { $this->cache_pwr_chat($bot_api_id, $this->settings['peer']['full_fetch'], true); } } break; default: throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.var_export($chat, true)); break; } } public function cache_pwr_chat($id, $full_fetch, $send) { $this->callFork((function () use ($id, $full_fetch, $send) { try { yield $this->get_pwr_chat_async($id, $full_fetch, $send); } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING); } })()); } public function peer_isset_async($id) { try { return isset($this->chats[(yield $this->get_info_async($id))['bot_api_id']]); } catch (\danog\MadelineProto\Exception $e) { return false; } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'CHAT_FORBIDDEN') { return true; } if ($e->rpc === 'CHANNEL_PRIVATE') { return true; } return false; } } public function entities_peer_isset_async($entities) { try { foreach ($entities as $entity) { if ($entity['_'] === 'messageEntityMentionName' || $entity['_'] === 'inputMessageEntityMentionName') { if (!yield $this->peer_isset_async($entity['user_id'])) { return false; } } } } catch (\danog\MadelineProto\Exception $e) { return false; } return true; } public function fwd_peer_isset_async($fwd) { try { if (isset($fwd['user_id']) && !yield $this->peer_isset_async($fwd['user_id'])) { return false; } if (isset($fwd['channel_id']) && !yield $this->peer_isset_async($this->to_supergroup($fwd['channel_id']))) { return false; } } catch (\danog\MadelineProto\Exception $e) { return false; } return true; } public function get_id($id) { if (is_array($id)) { switch ($id['_']) { case 'updateDialogPinned': case 'updateDialogUnreadMark': case 'updateNotifySettings': $id = $id['peer']; case 'updateDraftMessage': case 'inputDialogPeer': case 'dialogPeer': case 'inputNotifyPeer': case 'notifyPeer': case 'dialog': case 'help.proxyDataPromo': case 'updateChatDefaultBannedRights': return $this->get_id($id['peer']); case 'inputUserSelf': case 'inputPeerSelf': return $this->authorization['user']['id']; case 'user': return $id['id']; case 'userFull': return $id['user']['id']; case 'inputPeerUser': case 'inputUser': case 'peerUser': return $id['user_id']; case 'chat': case 'chatForbidden': case 'chatFull': return -$id['id']; case 'inputPeerChat': case 'peerChat': return -$id['chat_id']; case 'channelForbidden': case 'channel': case 'channelFull': return $this->to_supergroup($id['id']); case 'inputPeerChannel': case 'inputChannel': case 'peerChannel': return $this->to_supergroup($id['channel_id']); case 'message': case 'messageService': if (!isset($id['from_id']) || $id['to_id']['_'] !== 'peerUser' || $id['to_id']['user_id'] !== $this->authorization['user']['id']) { return $this->get_id($id['to_id']); } return $id['from_id']; case 'updateChannelReadMessagesContents': case 'updateChannelAvailableMessages': case 'updateChannel': case 'updateChannelWebPage': case 'updateChannelMessageViews': case 'updateReadChannelInbox': case 'updateReadChannelOutbox': case 'updateDeleteChannelMessages': case 'updateChannelPinnedMessage': case 'updateChannelTooLong': return $this->to_supergroup($id['channel_id']); case 'updateChatParticipants': $id = $id['participants']; case 'updateChatUserTyping': case 'updateChatParticipantAdd': case 'updateChatParticipantDelete': case 'updateChatParticipantAdmin': case 'updateChatAdmins': case 'updateChatPinnedMessage': return -$id['chat_id']; case 'updateUserTyping': case 'updateUserStatus': case 'updateUserName': case 'updateUserPhoto': case 'updateUserPhone': case 'updateUserBlocked': case 'updateContactRegistered': case 'updateContactLink': case 'updateBotInlineQuery': case 'updateInlineBotCallbackQuery': case 'updateBotInlineSend': case 'updateBotCallbackQuery': case 'updateBotPrecheckoutQuery': case 'updateBotShippingQuery': case 'updateUserPinnedMessage': return $id['user_id']; case 'updatePhoneCall': return $id->getOtherID(); case 'updateReadHistoryInbox': case 'updateReadHistoryOutbox': return $this->get_id($id['peer']); case 'updateNewMessage': case 'updateNewChannelMessage': case 'updateEditMessage': case 'updateEditChannelMessage': case 'updateNewEncryptedMessage': return $this->get_id($id['message']); default: throw new \danog\MadelineProto\Exception('Invalid constructor given '.var_export($id, true)); } } if (is_string($id)) { if (strpos($id, '#') !== false) { if (preg_match('/^channel#(\d*)/', $id, $matches)) { return $this->to_supergroup($matches[1]); } if (preg_match('/^chat#(\d*)/', $id, $matches)) { $id = '-'.$matches[1]; } if (preg_match('/^user#(\d*)/', $id, $matches)) { return $matches[1]; } } } if (is_numeric($id)) { if (is_string($id)) { $id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id; } return $id; } return false; } public function get_info_async($id, $recursive = true) { if (is_array($id)) { switch ($id['_']) { case 'updateEncryption': return $this->get_secret_chat($id['chat']['id']); case 'updateEncryptedChatTyping': case 'updateEncryptedMessagesRead': return $this->get_secret_chat($id['chat_id']); case 'encryptedMessage': case 'encryptedMessageService': $id = $id['chat_id']; if (!isset($this->secret_chats[$id])) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['sec_peer_not_in_db']); } return $this->secret_chats[$id]; } } $try_id = $this->get_id($id); if ($try_id !== false) { $id = $try_id; } $tried_simple = false; if (is_numeric($id)) { if (!isset($this->chats[$id])) { try { $this->caching_simple[$id] = true; if ($id < 0) { if ($this->is_supergroup($id)) { yield $this->method_call_async_read('channels.getChannels', ['id' => [['access_hash' => 0, 'channel_id' => $this->from_supergroup($id), '_' => 'inputChannel']]], ['datacenter' => $this->datacenter->curdc]); } else { yield $this->method_call_async_read('messages.getFullChat', ['chat_id' => -$id], ['datacenter' => $this->datacenter->curdc]); } } else { yield $this->method_call_async_read('users.getUsers', ['id' => [['access_hash' => 0, 'user_id' => $id, '_' => 'inputUser']]], ['datacenter' => $this->datacenter->curdc]); } } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); } finally { if (isset($this->caching_simple[$id])) { unset($this->caching_simple[$id]); } $tried_simple = true; } } if (isset($this->chats[$id])) { try { return $this->gen_all($this->chats[$id]); } catch (\danog\MadelineProto\Exception $e) { if ($e->getMessage() === 'This peer is not present in the internal peer database') { unset($this->chats[$id]); } else { throw $e; } } } if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) { $dbres = []; try { $dbres = json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true); } catch (\Throwable $e) { $this->logger->logger($e); } if (isset($dbres['ok']) && $dbres['ok']) { yield $this->resolve_username_async('@'.$dbres['result']); return yield $this->get_info_async($id, false); } } if ($tried_simple && isset($this->caching_possible_username[$id])) { $this->logger->logger("No access hash with $id, trying to fetch by username..."); $user = $this->caching_possible_username[$id]; unset($this->caching_possible_username[$id]); return yield $this->get_info_async($user); } throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } if (preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) { if ($matches[1] === '') { $id = $matches[2]; } else { $invite = yield $this->method_call_async_read('messages.checkChatInvite', ['hash' => $matches[2]], ['datacenter' => $this->datacenter->curdc]); if (isset($invite['chat'])) { return yield $this->get_info_async($invite['chat']); } else { throw new \danog\MadelineProto\Exception('You have not joined this chat'); } } } $id = strtolower(str_replace('@', '', $id)); if ($id === 'me') { return yield $this->get_info_async($this->authorization['user']['id']); } if ($id === 'support') { if (!$this->supportUser) { yield $this->method_call_async_read('help.getSupport', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]); } return yield $this->get_info_async($this->supportUser); } foreach ($this->chats as $chat) { if (isset($chat['username']) && strtolower($chat['username']) === $id) { return $this->gen_all($chat); } } if ($recursive) { yield $this->resolve_username_async($id); return yield $this->get_info_async($id, false); } throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } public function gen_all($constructor) { $res = [$this->constructors->find_by_predicate($constructor['_'])['type'] => $constructor]; switch ($constructor['_']) { case 'user': if ($constructor['self']) { $res['InputPeer'] = ['_' => 'inputPeerSelf']; $res['InputUser'] = ['_' => 'inputUserSelf']; } elseif (isset($constructor['access_hash'])) { $res['InputPeer'] = ['_' => 'inputPeerUser', 'user_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']]; $res['InputUser'] = ['_' => 'inputUser', 'user_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']]; } else { throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } $res['Peer'] = ['_' => 'peerUser', 'user_id' => $constructor['id']]; $res['DialogPeer'] = ['_' => 'dialogPeer', 'peer' => $res['Peer']]; $res['NotifyPeer'] = ['_' => 'notifyPeer', 'peer' => $res['Peer']]; $res['InputDialogPeer'] = ['_' => 'inputDialogPeer', 'peer' => $res['InputPeer']]; $res['InputNotifyPeer'] = ['_' => 'inputNotifyPeer', 'peer' => $res['InputPeer']]; $res['user_id'] = $constructor['id']; $res['bot_api_id'] = $constructor['id']; $res['type'] = $constructor['bot'] ? 'bot' : 'user'; break; case 'chat': case 'chatForbidden': $res['InputPeer'] = ['_' => 'inputPeerChat', 'chat_id' => $constructor['id']]; $res['Peer'] = ['_' => 'peerChat', 'chat_id' => $constructor['id']]; $res['DialogPeer'] = ['_' => 'dialogPeer', 'peer' => $res['Peer']]; $res['NotifyPeer'] = ['_' => 'notifyPeer', 'peer' => $res['Peer']]; $res['InputDialogPeer'] = ['_' => 'inputDialogPeer', 'peer' => $res['InputPeer']]; $res['InputNotifyPeer'] = ['_' => 'inputNotifyPeer', 'peer' => $res['InputPeer']]; $res['chat_id'] = $constructor['id']; $res['bot_api_id'] = -$constructor['id']; $res['type'] = 'chat'; break; case 'channel': if (!isset($constructor['access_hash'])) { throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); } $res['InputPeer'] = ['_' => 'inputPeerChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']]; $res['Peer'] = ['_' => 'peerChannel', 'channel_id' => $constructor['id']]; $res['DialogPeer'] = ['_' => 'dialogPeer', 'peer' => $res['Peer']]; $res['NotifyPeer'] = ['_' => 'notifyPeer', 'peer' => $res['Peer']]; $res['InputDialogPeer'] = ['_' => 'inputDialogPeer', 'peer' => $res['InputPeer']]; $res['InputNotifyPeer'] = ['_' => 'inputNotifyPeer', 'peer' => $res['InputPeer']]; $res['InputChannel'] = ['_' => 'inputChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']]; $res['channel_id'] = $constructor['id']; $res['bot_api_id'] = $this->to_supergroup($constructor['id']); $res['type'] = $constructor['megagroup'] ? 'supergroup' : 'channel'; break; case 'channelForbidden': throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); default: throw new \danog\MadelineProto\Exception('Invalid constructor given '.var_export($constructor, true)); } return $res; } public function full_chat_last_updated($id) { return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0; } public function get_full_info_async($id) { $partial = yield $this->get_info_async($id); if (time() - $this->full_chat_last_updated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) { return array_merge($partial, $this->full_chats[$partial['bot_api_id']]); } switch ($partial['type']) { case 'user': case 'bot': $full = yield $this->method_call_async_read('users.getFullUser', ['id' => $partial['InputUser']], ['datacenter' => $this->datacenter->curdc]); break; case 'chat': $full = (yield $this->method_call_async_read('messages.getFullChat', $partial, ['datacenter' => $this->datacenter->curdc]))['full_chat']; break; case 'channel': case 'supergroup': $full = (yield $this->method_call_async_read('channels.getFullChannel', ['channel' => $partial['InputChannel']], ['datacenter' => $this->datacenter->curdc]))['full_chat']; break; } $res = []; $res['full'] = $full; $res['last_update'] = time(); $this->full_chats[$partial['bot_api_id']] = $res; $partial = yield $this->get_info_async($id); return array_merge($partial, $res); } public function get_pwr_chat_async($id, $fullfetch = true, $send = true) { $full = $fullfetch ? yield $this->get_full_info_async($id) : yield $this->get_info_async($id); $res = ['id' => $full['bot_api_id'], 'type' => $full['type']]; switch ($full['type']) { case 'user': case 'bot': foreach (['first_name', 'last_name', 'username', 'verified', 'restricted', 'restriction_reason', 'status', 'bot_inline_placeholder', 'access_hash', 'phone', 'lang_code', 'bot_nochats'] as $key) { if (isset($full['User'][$key])) { $res[$key] = $full['User'][$key]; } } foreach (['about', 'bot_info', 'phone_calls_available', 'phone_calls_private', 'common_chats_count', 'can_pin_message', 'pinned_msg_id', 'notify_settings'] as $key) { if (isset($full['full'][$key])) { $res[$key] = $full['full'][$key]; } } if (isset($full['full']['profile_photo']['sizes'])) { $res['photo'] = yield $this->photosize_to_botapi_async(end($full['full']['profile_photo']['sizes']), $full['full']['profile_photo']); } break; case 'chat': foreach (['title', 'participants_count', 'admin', 'admins_enabled'] as $key) { if (isset($full['Chat'][$key])) { $res[$key] = $full['Chat'][$key]; } } foreach (['bot_info', 'pinned_msg_id', 'notify_settings'] as $key) { if (isset($full['full'][$key])) { $res[$key] = $full['full'][$key]; } } if (isset($res['admins_enabled'])) { $res['all_members_are_administrators'] = !$res['admins_enabled']; } if (isset($full['full']['chat_photo']['sizes'])) { $res['photo'] = yield $this->photosize_to_botapi_async(end($full['full']['chat_photo']['sizes']), $full['full']['chat_photo']); } if (isset($full['full']['exported_invite']['link'])) { $res['invite'] = $full['full']['exported_invite']['link']; } if (isset($full['full']['participants']['participants'])) { $res['participants'] = $full['full']['participants']['participants']; } break; case 'channel': case 'supergroup': foreach (['title', 'democracy', 'restricted', 'restriction_reason', 'access_hash', 'username', 'signatures'] as $key) { if (isset($full['Chat'][$key])) { $res[$key] = $full['Chat'][$key]; } } foreach (['read_inbox_max_id', 'read_outbox_max_id', 'hidden_prehistory', 'bot_info', 'notify_settings', 'can_set_stickers', 'stickerset', 'can_view_participants', 'can_set_username', 'participants_count', 'admins_count', 'kicked_count', 'banned_count', 'migrated_from_chat_id', 'migrated_from_max_id', 'pinned_msg_id', 'about', 'hidden_prehistory', 'available_min_id', 'can_view_stats', 'online_count'] as $key) { if (isset($full['full'][$key])) { $res[$key] = $full['full'][$key]; } } if (isset($full['full']['chat_photo']['sizes'])) { $res['photo'] = yield $this->photosize_to_botapi_async(end($full['full']['chat_photo']['sizes']), $full['full']['chat_photo']); } if (isset($full['full']['exported_invite']['link'])) { $res['invite'] = $full['full']['exported_invite']['link']; } if (isset($full['full']['participants']['participants'])) { $res['participants'] = $full['full']['participants']['participants']; } break; } if (isset($res['participants']) && $fullfetch) { foreach ($res['participants'] as $key => $participant) { $newres = []; $newres['user'] = yield $this->get_pwr_chat_async($participant['user_id'], false, true); if (isset($participant['inviter_id'])) { $newres['inviter'] = yield $this->get_pwr_chat_async($participant['inviter_id'], false, true); } if (isset($participant['promoted_by'])) { $newres['promoted_by'] = yield $this->get_pwr_chat_async($participant['promoted_by'], false, true); } if (isset($participant['kicked_by'])) { $newres['kicked_by'] = yield $this->get_pwr_chat_async($participant['kicked_by'], false, true); } if (isset($participant['date'])) { $newres['date'] = $participant['date']; } if (isset($participant['admin_rights'])) { $newres['admin_rights'] = $participant['admin_rights']; } if (isset($participant['banned_rights'])) { $newres['banned_rights'] = $participant['banned_rights']; } if (isset($participant['can_edit'])) { $newres['can_edit'] = $participant['can_edit']; } if (isset($participant['left'])) { $newres['left'] = $participant['left']; } switch ($participant['_']) { case 'chatParticipant': $newres['role'] = 'user'; break; case 'chatParticipantAdmin': $newres['role'] = 'admin'; break; case 'chatParticipantCreator': $newres['role'] = 'creator'; break; } $res['participants'][$key] = $newres; } } if (!isset($res['participants']) && $fullfetch && in_array($res['type'], ['supergroup', 'channel'])) { $total_count = (isset($res['participants_count']) ? $res['participants_count'] : 0) + (isset($res['admins_count']) ? $res['admins_count'] : 0) + (isset($res['kicked_count']) ? $res['kicked_count'] : 0) + (isset($res['banned_count']) ? $res['banned_count'] : 0); $res['participants'] = []; $limit = 200; $filters = ['channelParticipantsAdmins', 'channelParticipantsBots']; foreach ($filters as $filter) { yield $this->fetch_participants_async($full['InputChannel'], $filter, '', $total_count, $res); } $q = ''; $filters = ['channelParticipantsSearch', 'channelParticipantsKicked', 'channelParticipantsBanned']; foreach ($filters as $filter) { yield $this->recurse_alphabet_search_participants_async($full['InputChannel'], $filter, $q, $total_count, $res); } $this->logger->logger('Fetched '.count($res['participants'])." out of $total_count"); $res['participants'] = array_values($res['participants']); } if (!$fullfetch) { unset($res['participants']); } if ($fullfetch || $send) { $this->store_db($res); } return $res; } public function recurse_alphabet_search_participants_async($channel, $filter, $q, $total_count, &$res) { if (!yield $this->fetch_participants_async($channel, $filter, $q, $total_count, $res)) { return false; } for ($x = 'a'; $x !== 'aa' && $total_count > count($res['participants']); $x++) { yield $this->recurse_alphabet_search_participants_async($channel, $filter, $q.$x, $total_count, $res); } } public function fetch_participants_async($channel, $filter, $q, $total_count, &$res) { $offset = 0; $limit = 200; $has_more = false; $cached = false; $last_count = -1; do { try { $gres = yield $this->method_call_async_read('channels.getParticipants', ['channel' => $channel, 'filter' => ['_' => $filter, 'q' => $q], 'offset' => $offset, 'limit' => $limit, 'hash' => $hash = $this->get_participants_hash($channel, $filter, $q, $offset, $limit)], ['datacenter' => $this->datacenter->curdc, 'heavy' => true]); } catch (\danog\MadelineProto\RPCErrorException $e) { if ($e->rpc === 'CHAT_ADMIN_REQUIRED') { $this->logger->logger($e->rpc); return $has_more; } else { throw $e; } } if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') { $gres = $this->fetch_participants_cache($channel, $filter, $q, $offset, $limit); } else { $this->store_participants_cache($gres, $channel, $filter, $q, $offset, $limit); } if ($last_count !== -1 && $last_count !== $gres['count']) { $has_more = true; } else { $last_count = $gres['count']; } foreach ($gres['participants'] as $participant) { $newres = []; $newres['user'] = yield $this->get_pwr_chat_async($participant['user_id'], false, true); if (isset($participant['inviter_id'])) { $newres['inviter'] = yield $this->get_pwr_chat_async($participant['inviter_id'], false, true); } if (isset($participant['kicked_by'])) { $newres['kicked_by'] = yield $this->get_pwr_chat_async($participant['kicked_by'], false, true); } if (isset($participant['promoted_by'])) { $newres['promoted_by'] = yield $this->get_pwr_chat_async($participant['promoted_by'], false, true); } if (isset($participant['date'])) { $newres['date'] = $participant['date']; } switch ($participant['_']) { case 'channelParticipantSelf': $newres['role'] = 'user'; if (isset($newres['admin_rights'])) { $newres['admin_rights'] = $full['Chat']['admin_rights']; } if (isset($newres['banned_rights'])) { $newres['banned_rights'] = $full['Chat']['banned_rights']; } break; case 'channelParticipant': $newres['role'] = 'user'; break; case 'channelParticipantCreator': $newres['role'] = 'creator'; break; case 'channelParticipantAdmin': $newres['role'] = 'admin'; break; case 'channelParticipantBanned': $newres['role'] = 'banned'; break; } $res['participants'][$participant['user_id']] = $newres; } $this->logger->logger('Fetched '.count($gres['participants'])." channel participants with filter $filter, query $q, offset $offset, limit $limit, hash $hash: ".($cached ? 'cached' : 'not cached').', '.($offset + count($gres['participants'])).' participants out of '.$gres['count'].', in total fetched '.count($res['participants']).' out of '.$total_count); $offset += count($gres['participants']); } while (count($gres['participants'])); if ($offset === $limit) { return true; } return $has_more; } public function fetch_participants_cache($channel, $filter, $q, $offset, $limit) { return $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]; } public function store_participants_cache($gres, $channel, $filter, $q, $offset, $limit) { //return; unset($gres['users']); $ids = []; foreach ($gres['participants'] as $participant) { $ids[] = $participant['user_id']; } sort($ids, SORT_NUMERIC); $gres['hash'] = $this->gen_vector_hash($ids); $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres; } public function get_participants_hash($channel, $filter, $q, $offset, $limit) { return isset($this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]) ? $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]['hash'] : 0; } public function store_db($res, $force = false) { $settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all']; if (!isset($this->settings['pwr']) || $this->settings['pwr']['pwr'] === false || $settings['test_mode']) { return; } if (!empty($res)) { if (isset($res['participants'])) { unset($res['participants']); } $this->qres[] = $res; } if ($this->last_stored > time() && !$force) { //$this->logger->logger("========== WILL SERIALIZE IN ".($this->last_stored - time())." ============="); return false; } if (empty($this->qres)) { return false; } try { $payload = json_encode($this->qres); //$path = '/tmp/ids'.hash('sha256', $payload); //file_put_contents($path, $payload); $id = isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id']; $request = (new Request('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id, 'POST'))->withHeader('content-type', 'application/json')->withBody($payload); $result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody(); $this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE); $this->qres = []; $this->last_stored = time() + 10; } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('======= COULD NOT STORE IN DB DUE TO '.$e->getMessage().' =============', \danog\MadelineProto\Logger::VERBOSE); } } public function resolve_username_async($username) { try { $this->caching_simple_username[$username] = true; $res = yield $this->method_call_async_read('contacts.resolveUsername', ['username' => str_replace('@', '', $username)], ['datacenter' => $this->datacenter->curdc]); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('Username resolution failed with error '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); if (strpos($e->rpc, 'FLOOD_WAIT_') === 0 || $e->rpc === 'AUTH_KEY_UNREGISTERED' || $e->rpc === 'USERNAME_INVALID') { throw $e; } return false; } finally { if (isset($this->caching_simple_username[$username])) { unset($this->caching_simple_username[$username]); } } if ($res['_'] === 'contacts.resolvedPeer') { return $res; } return false; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use danog\MadelineProto\Exception; use Amp\Artax\Request; /** * Manages the creation of the authorization key. * * https://core.telegram.org/mtproto/auth_key * https://core.telegram.org/mtproto/samples-auth_key */ trait AuthKeyHandler { private $init_auth_dcs = []; private $pending_auth = false; public function create_auth_key_async($expires_in, $datacenter): \Generator { $req_pq = strpos($datacenter, 'cdn') ? 'req_pq' : 'req_pq_multi'; for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) { try { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['req_pq'], \danog\MadelineProto\Logger::VERBOSE); /** * *********************************************************************** * Make pq request, DH exchange initiation. * * @method req_pq * * @param [ * int128 $nonce : The value of nonce is selected randomly by the client (random number) and identifies the client within this communication * ] * * @return ResPQ [ * int128 $nonce : The value of nonce is selected randomly by the server * int128 $server_nonce : The value of server_nonce is selected randomly by the server * string $pq : This is a representation of a natural number (in binary big endian format). This number is the product of two different odd prime numbers * Vector long $server_public_key_fingerprints : This is a list of public RSA key fingerprints * ] */ $nonce = $this->random(16); $ResPQ = yield $this->method_call_async_read($req_pq, ['nonce' => $nonce], ['datacenter' => $datacenter]); /* * *********************************************************************** * Check if the client's nonce and the server's nonce are the same */ if ($ResPQ['nonce'] !== $nonce) { throw new \danog\MadelineProto\SecurityException('wrong nonce'); } /* * *********************************************************************** * Find our key in the server_public_key_fingerprints vector */ foreach ($this->rsa_keys as $curkey) { if (in_array($curkey->fp, $ResPQ['server_public_key_fingerprints'])) { $key = $curkey; } } if (!isset($key)) { throw new \danog\MadelineProto\SecurityException("Couldn't find any of our keys in the server_public_key_fingerprints vector."); } $pq_bytes = $ResPQ['pq']; $server_nonce = $ResPQ['server_nonce']; /* * *********************************************************************** * Compute p and q */ $pq = new \phpseclib\Math\BigInteger($pq_bytes, 256); $q = new \phpseclib\Math\BigInteger(0); $p = new \phpseclib\Math\BigInteger(\danog\PrimeModule::auto_single($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying native CPP module', \danog\MadelineProto\Logger::ERROR); $p = new \phpseclib\Math\BigInteger(\danog\PrimeModule::native_single_cpp($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying alt py module', \danog\MadelineProto\Logger::ERROR); $p = new \phpseclib\Math\BigInteger(\danog\PrimeModule::python_single_alt($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying py module', \danog\MadelineProto\Logger::ERROR); $p = new \phpseclib\Math\BigInteger(\danog\PrimeModule::python_single($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying native module', \danog\MadelineProto\Logger::ERROR); $p = new \phpseclib\Math\BigInteger(\danog\PrimeModule::native_single($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } if (!$pq->equals($p->multiply($q))) { $this->logger->logger('Automatic factorization failed, trying wolfram module', \danog\MadelineProto\Logger::ERROR); $p = new \phpseclib\Math\BigInteger(yield $this->wolfram_single_async($pq->__toString())); if (!$p->equals(\danog\MadelineProto\Magic::$zero)) { $q = $pq->divide($p)[0]; if ($p->compare($q) > 0) { list($p, $q) = [$q, $p]; } } if (!$pq->equals($p->multiply($q))) { throw new \danog\MadelineProto\SecurityException("Couldn't compute p and q, install prime.madelineproto.xyz to fix. Original pq: {$pq}, computed p: {$p}, computed q: {$q}, computed pq: ".$p->multiply($q)); } } } } } } $this->logger->logger('Factorization '.$pq.' = '.$p.' * '.$q, \danog\MadelineProto\Logger::VERBOSE); /* * *********************************************************************** * Serialize object for req_DH_params */ $p_bytes = $p->toBytes(); $q_bytes = $q->toBytes(); $new_nonce = $this->random(32); $data_unserialized = ['pq' => $pq_bytes, 'p' => $p_bytes, 'q' => $q_bytes, 'nonce' => $nonce, 'server_nonce' => $server_nonce, 'new_nonce' => $new_nonce, 'expires_in' => $expires_in, 'dc' => preg_replace('|_.*|', '', $datacenter)]; $p_q_inner_data = yield $this->serialize_object_async(['type' => 'p_q_inner_data'.($expires_in < 0 ? '' : '_temp')], $data_unserialized, 'p_q_inner_data'); /* * *********************************************************************** * Encrypt serialized object */ $sha_digest = sha1($p_q_inner_data, true); $random_bytes = $this->random(255 - strlen($p_q_inner_data) - strlen($sha_digest)); $to_encrypt = $sha_digest.$p_q_inner_data.$random_bytes; $encrypted_data = $key->encrypt($to_encrypt); $this->logger->logger('Starting Diffie Hellman key exchange', \danog\MadelineProto\Logger::VERBOSE); /* * *********************************************************************** * Starting Diffie Hellman key exchange, Server authentication * @method req_DH_params * @param [ * int128 $nonce : The value of nonce is selected randomly by the client (random number) and identifies the client within this communication * int128 $server_nonce : The value of server_nonce is selected randomly by the server * string $p : The value of BigInteger * string $q : The value of BigInteger * long $public_key_fingerprint : This is our key in the server_public_key_fingerprints vector * string $encrypted_data * ] * @return Server_DH_Params [ * int128 $nonce : The value of nonce is selected randomly by the server * int128 $server_nonce : The value of server_nonce is selected randomly by the server * string $new_nonce_hash : Return this value if server responds with server_DH_params_fail * string $encrypted_answer : Return this value if server responds with server_DH_params_ok * ] */ // $server_dh_params = yield $this->method_call_async_read('req_DH_params', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'p' => $p_bytes, 'q' => $q_bytes, 'public_key_fingerprint' => $key->fp, 'encrypted_data' => $encrypted_data], ['datacenter' => $datacenter]); /* * *********************************************************************** * Check if the client's nonce and the server's nonce are the same */ if ($nonce != $server_dh_params['nonce']) { throw new \danog\MadelineProto\SecurityException('wrong nonce.'); } /* * *********************************************************************** * Check if server_nonce and new server_nonce are the same */ if ($server_nonce != $server_dh_params['server_nonce']) { throw new \danog\MadelineProto\SecurityException('wrong server nonce.'); } /* * *********************************************************************** * Check valid new nonce hash if return from server * new nonce hash return in server_DH_params_fail */ if (isset($server_dh_params['new_nonce_hash']) && substr(sha1($new_nonce), -32) != $server_dh_params['new_nonce_hash']) { throw new \danog\MadelineProto\SecurityException('wrong new nonce hash.'); } /* * *********************************************************************** * Get key, iv and decrypt answer */ $encrypted_answer = $server_dh_params['encrypted_answer']; $tmp_aes_key = sha1($new_nonce.$server_nonce, true).substr(sha1($server_nonce.$new_nonce, true), 0, 12); $tmp_aes_iv = substr(sha1($server_nonce.$new_nonce, true), 12, 8).sha1($new_nonce.$new_nonce, true).substr($new_nonce, 0, 4); $answer_with_hash = $this->ige_decrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv); /* * *********************************************************************** * Separate answer and hash */ $answer_hash = substr($answer_with_hash, 0, 20); $answer = substr($answer_with_hash, 20); /* * *********************************************************************** * Deserialize answer * @return Server_DH_inner_data [ * int128 $nonce : The value of nonce is selected randomly by the client (random number) and identifies the client within this communication * int128 $server_nonce : The value of server_nonce is selected randomly by the server * int $g * string $dh_prime * string $g_a * int $server_time * ] */ $server_DH_inner_data = $this->deserialize($answer, ['type' => '']); /* * *********************************************************************** * Do some checks */ $server_DH_inner_data_length = $this->get_length($answer); if (sha1(substr($answer, 0, $server_DH_inner_data_length), true) != $answer_hash) { throw new \danog\MadelineProto\SecurityException('answer_hash mismatch.'); } if ($nonce != $server_DH_inner_data['nonce']) { throw new \danog\MadelineProto\SecurityException('wrong nonce'); } if ($server_nonce != $server_DH_inner_data['server_nonce']) { throw new \danog\MadelineProto\SecurityException('wrong server nonce'); } $g = new \phpseclib\Math\BigInteger($server_DH_inner_data['g']); $g_a = new \phpseclib\Math\BigInteger($server_DH_inner_data['g_a'], 256); $dh_prime = new \phpseclib\Math\BigInteger($server_DH_inner_data['dh_prime'], 256); /* * *********************************************************************** * Time delta */ $server_time = $server_DH_inner_data['server_time']; $this->datacenter->sockets[$datacenter]->time_delta = $server_time - time(); $this->logger->logger(sprintf('Server-client time delta = %.1f s', $this->datacenter->sockets[$datacenter]->time_delta), \danog\MadelineProto\Logger::VERBOSE); $this->check_p_g($dh_prime, $g); $this->check_G($g_a, $dh_prime); for ($retry_id = 0; $retry_id <= $this->settings['max_tries']['authorization']; $retry_id++) { $this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE); $b = new \phpseclib\Math\BigInteger($this->random(256), 256); $this->logger->logger('Generating g_b...', \danog\MadelineProto\Logger::VERBOSE); $g_b = $g->powMod($b, $dh_prime); $this->check_G($g_b, $dh_prime); /* * *********************************************************************** * Check validity of g_b * 1 < g_b < dh_prime - 1 */ $this->logger->logger('Executing g_b check...', \danog\MadelineProto\Logger::VERBOSE); if ($g_b->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g_b->compare($dh_prime->subtract(\danog\MadelineProto\Magic::$one)) >= 0) { throw new \danog\MadelineProto\SecurityException('g_b is invalid (1 < g_b < dh_prime - 1 is false).'); } $this->logger->logger('Preparing client_DH_inner_data...', \danog\MadelineProto\Logger::VERBOSE); $g_b_str = $g_b->toBytes(); /* * *********************************************************************** * serialize client_DH_inner_data * @method client_DH_inner_data * @param Server_DH_inner_data [ * int128 $nonce : The value of nonce is selected randomly by the client (random number) and identifies the client within this communication * int128 $server_nonce : The value of server_nonce is selected randomly by the server * long $retry_id : First attempt * string $g_b : g^b mod dh_prime * ] */ $data = yield $this->serialize_object_async(['type' => 'client_DH_inner_data'], ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'retry_id' => $retry_id, 'g_b' => $g_b_str], 'client_DH_inner_data'); /* * *********************************************************************** * encrypt client_DH_inner_data */ $data_with_sha = sha1($data, true).$data; $data_with_sha_padded = $data_with_sha.$this->random($this->posmod(-strlen($data_with_sha), 16)); $encrypted_data = $this->ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); $this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE); /* * *********************************************************************** * Send set_client_DH_params query * @method set_client_DH_params * @param Server_DH_inner_data [ * int128 $nonce : The value of nonce is selected randomly by the client (random number) and identifies the client within this communication * int128 $server_nonce : The value of server_nonce is selected randomly by the server * string $encrypted_data * ] * @return Set_client_DH_params_answer [ * string $_ : This value is dh_gen_ok, dh_gen_retry OR dh_gen_fail * int128 $server_nonce : The value of server_nonce is selected randomly by the server * int128 $new_nonce_hash1 : Return this value if server responds with dh_gen_ok * int128 $new_nonce_hash2 : Return this value if server responds with dh_gen_retry * int128 $new_nonce_hash2 : Return this value if server responds with dh_gen_fail * ] */ $Set_client_DH_params_answer = yield $this->method_call_async_read('set_client_DH_params', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'encrypted_data' => $encrypted_data], ['datacenter' => $datacenter]); /* * *********************************************************************** * Generate auth_key */ $this->logger->logger('Generating authorization key...', \danog\MadelineProto\Logger::VERBOSE); $auth_key = $g_a->powMod($b, $dh_prime); $auth_key_str = $auth_key->toBytes(); $auth_key_sha = sha1($auth_key_str, true); $auth_key_aux_hash = substr($auth_key_sha, 0, 8); $new_nonce_hash1 = substr(sha1($new_nonce.chr(1).$auth_key_aux_hash, true), -16); $new_nonce_hash2 = substr(sha1($new_nonce.chr(2).$auth_key_aux_hash, true), -16); $new_nonce_hash3 = substr(sha1($new_nonce.chr(3).$auth_key_aux_hash, true), -16); /* * *********************************************************************** * Check if the client's nonce and the server's nonce are the same */ if ($Set_client_DH_params_answer['nonce'] != $nonce) { throw new \danog\MadelineProto\SecurityException('wrong nonce.'); } /* * *********************************************************************** * Check if server_nonce and new server_nonce are the same */ if ($Set_client_DH_params_answer['server_nonce'] != $server_nonce) { throw new \danog\MadelineProto\SecurityException('wrong server nonce'); } /* * *********************************************************************** * Check Set_client_DH_params_answer type */ switch ($Set_client_DH_params_answer['_']) { case 'dh_gen_ok': if ($Set_client_DH_params_answer['new_nonce_hash1'] != $new_nonce_hash1) { throw new \danog\MadelineProto\SecurityException('wrong new_nonce_hash1'); } $this->logger->logger('Diffie Hellman key exchange processed successfully!', \danog\MadelineProto\Logger::VERBOSE); $res_authorization['server_salt'] = substr($new_nonce, 0, 8 - 0) ^ substr($server_nonce, 0, 8 - 0); $res_authorization['auth_key'] = $auth_key_str; $res_authorization['id'] = substr($auth_key_sha, -8); $res_authorization['connection_inited'] = false; $this->logger->logger('Auth key generated', \danog\MadelineProto\Logger::NOTICE); return $res_authorization; case 'dh_gen_retry': if ($Set_client_DH_params_answer['new_nonce_hash2'] != $new_nonce_hash2) { throw new \danog\MadelineProto\SecurityException('wrong new_nonce_hash_2'); } //repeat foreach $this->logger->logger('Retrying Auth', \danog\MadelineProto\Logger::VERBOSE); break; case 'dh_gen_fail': if ($Set_client_DH_params_answer['new_nonce_hash3'] != $new_nonce_hash3) { throw new \danog\MadelineProto\SecurityException('wrong new_nonce_hash_3'); } $this->logger->logger('Auth Failed', \danog\MadelineProto\Logger::WARNING); break 2; default: throw new \danog\MadelineProto\SecurityException('Response Error'); break; } } } catch (\danog\MadelineProto\SecurityException $e) { $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...', \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...', \danog\MadelineProto\Logger::WARNING); $req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi'; } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); } } if (strpos($datacenter, 'cdn') === false) { throw new \danog\MadelineProto\SecurityException('Auth Failed'); } } public function check_G($g_a, $p) { /* * *********************************************************************** * Check validity of g_a * 1 < g_a < p - 1 */ $this->logger->logger('Executing g_a check (1/2)...', \danog\MadelineProto\Logger::VERBOSE); if ($g_a->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) { throw new \danog\MadelineProto\SecurityException('g_a is invalid (1 < g_a < p - 1 is false).'); } $this->logger->logger('Executing g_a check (2/2)...', \danog\MadelineProto\Logger::VERBOSE); if ($g_a->compare(\danog\MadelineProto\Magic::$twoe1984) < 0 || $g_a->compare($p->subtract(\danog\MadelineProto\Magic::$twoe1984)) >= 0) { throw new \danog\MadelineProto\SecurityException('g_a is invalid (2^1984 < g_a < p - 2^1984 is false).'); } return true; } public function check_p_g($p, $g) { /* * *********************************************************************** * Check validity of dh_prime * Is it a prime? */ $this->logger->logger('Executing p/g checks (1/2)...', \danog\MadelineProto\Logger::VERBOSE); if (!$p->isPrime()) { throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime (p isn't a prime)."); } /* * *********************************************************************** * Check validity of p * Is (p - 1) / 2 a prime? * * Almost always fails */ /* $this->logger->logger('Executing p/g checks (2/3)...', \danog\MadelineProto\Logger::VERBOSE); if (!$p->subtract(\danog\MadelineProto\Magic::$one)->divide(\danog\MadelineProto\Magic::$two)[0]->isPrime()) { throw new \danog\MadelineProto\SecurityException("p isn't a safe 2048-bit prime ((p - 1) / 2 isn't a prime)."); } */ /* * *********************************************************************** * Check validity of p * 2^2047 < p < 2^2048 */ $this->logger->logger('Executing p/g checks (2/2)...', \danog\MadelineProto\Logger::VERBOSE); if ($p->compare(\danog\MadelineProto\Magic::$twoe2047) <= 0 || $p->compare(\danog\MadelineProto\Magic::$twoe2048) >= 0) { throw new \danog\MadelineProto\SecurityException("g isn't a safe 2048-bit prime (2^2047 < p < 2^2048 is false)."); } /* * *********************************************************************** * Check validity of g * 1 < g < p - 1 */ $this->logger->logger('Executing g check...', \danog\MadelineProto\Logger::VERBOSE); if ($g->compare(\danog\MadelineProto\Magic::$one) <= 0 || $g->compare($p->subtract(\danog\MadelineProto\Magic::$one)) >= 0) { throw new \danog\MadelineProto\SecurityException('g is invalid (1 < g < p - 1 is false).'); } return true; } public function get_dh_config_async() { $dh_config = yield $this->method_call_async_read('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]); if ($dh_config['_'] === 'messages.dhConfigNotModified') { $this->logger->logger(\danog\MadelineProto\Logger::VERBOSE, ['DH configuration not modified']); return $this->dh_config; } $dh_config['p'] = new \phpseclib\Math\BigInteger($dh_config['p'], 256); $dh_config['g'] = new \phpseclib\Math\BigInteger($dh_config['g']); $this->check_p_g($dh_config['p'], $dh_config['g']); return $this->dh_config = $dh_config; } public function bind_temp_auth_key_async($expires_in, $datacenter) { for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) { try { $this->logger->logger('Binding authorization keys...', \danog\MadelineProto\Logger::VERBOSE); $nonce = $this->random(8); $expires_at = time() + $expires_in; $temp_auth_key_id = $this->datacenter->sockets[$datacenter]->temp_auth_key['id']; $perm_auth_key_id = $this->datacenter->sockets[$datacenter]->auth_key['id']; $temp_session_id = $this->datacenter->sockets[$datacenter]->session_id; $message_data = yield $this->serialize_object_async(['type' => 'bind_auth_key_inner'], ['nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bind_temp_auth_key_inner'); $message_id = $this->datacenter->sockets[$datacenter]->generate_message_id(); $seq_no = 0; $encrypted_data = $this->random(16).$message_id.pack('VV', $seq_no, strlen($message_data)).$message_data; $message_key = substr(sha1($encrypted_data, true), -16); $padding = $this->random($this->posmod(-strlen($encrypted_data), 16)); list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->auth_key['auth_key']); $encrypted_message = $this->datacenter->sockets[$datacenter]->auth_key['id'].$message_key.$this->ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv); $res = yield $this->method_call_async_read('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id, 'datacenter' => $datacenter]); if ($res === true) { $this->logger->logger('Successfully binded temporary and permanent authorization keys, DC '.$datacenter, \danog\MadelineProto\Logger::NOTICE); $this->datacenter->sockets[$datacenter]->temp_auth_key['bound'] = true; $this->datacenter->sockets[$datacenter]->writer->resume(); return true; } } catch (\danog\MadelineProto\SecurityException $e) { $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('An exception occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('An RPCErrorException occurred while generating the authorization key: '.$e->getMessage().' Retrying (try number '.$retry_id_total.')...', \danog\MadelineProto\Logger::WARNING); } } throw new \danog\MadelineProto\SecurityException('An error occurred while binding temporary and permanent authorization keys.'); } public function wolfram_single_async($what) { $code = yield $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code'); $query = 'Do prime factorization of '.$what; $params = [ 'async' => true, 'banners' => 'raw', 'debuggingdata' => false, 'format' => 'moutput', 'formattimeout' => 8, 'input' => $query, 'output' => 'JSON', 'proxycode' => json_decode($code, true)['code'], ]; $url = 'https://www.wolframalpha.com/input/json.jsp?'.http_build_query($params); $request = (new Request($url))->withHeader('referer', 'https://www.wolframalpha.com/input/?i='.urlencode($query)); $res = json_decode(yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody(), true); if (!isset($res['queryresult']['pods'])) { return false; } $fres = false; foreach ($res['queryresult']['pods'] as $cur) { if ($cur['id'] === 'Divisors') { $fres = explode(', ', preg_replace(["/{\d+, /", "/, \d+}$/"], '', $cur['subpods'][0]['moutput'])); break; } } if (is_array($fres)) { $fres = $fres[0]; $newval = intval($fres); if (is_int($newval)) { $fres = $newval; } return $fres; } return false; } public function init_authorization_async() { if ($this->pending_auth) { return; } $initing = $this->initing_authorization; $this->initing_authorization = true; try { $dcs = []; $postpone = []; foreach ($this->datacenter->sockets as $id => $socket) { if (strpos($id, 'media') !== false) { $oid = intval($id); if (isset($dcs[$oid])) { $postpone[$id] = $socket; } continue; } if (isset($this->init_auth_dcs[$id])) { $this->pending_auth = true; continue; } $dcs[$id] = function () use ($id, $socket) { return $this->init_authorization_socket_async($id, $socket); }; } if ($dcs) { $first = array_shift($dcs)(); yield $first; } foreach ($dcs as $id => &$dc) { $dc = $dc(); } yield $this->all($dcs); foreach ($postpone as $id => $socket) { yield $this->init_authorization_socket_async($id, $socket); } if ($this->pending_auth && empty($this->init_auth_dcs)) { $this->pending_auth = false; yield $this->init_authorization_async(); } } finally { $this->pending_auth = false; $this->initing_authorization = $initing; } } public function init_authorization_socket_async($id, $socket) { $this->init_auth_dcs[$id] = true; try { if ($socket->session_id === null) { $socket->session_id = $this->random(8); $socket->session_in_seq_no = 0; $socket->session_out_seq_no = 0; } $cdn = strpos($id, 'cdn'); $media = strpos($id, 'media'); if ($socket->temp_auth_key === null || $socket->auth_key === null) { $dc_config_number = isset($this->settings['connection_settings'][$id]) ? $id : 'all'; if ($socket->auth_key === null && !$cdn && !$media) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['gen_perm_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); $socket->auth_key = yield $this->create_auth_key_async(-1, $id); $socket->authorized = false; } elseif ($socket->auth_key === null && $media) { $socket->auth_key = $this->datacenter->sockets[intval($id)]->auth_key; $socket->authorized = &$this->datacenter->sockets[intval($id)]->authorized; } if ($media) { $socket->authorized = &$this->datacenter->sockets[intval($id)]->authorized; } if ($this->settings['connection_settings'][$dc_config_number]['pfs']) { if (!$cdn) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); //$authorized = $socket->authorized; //$socket->authorized = false; $socket->temp_auth_key = null; $socket->temp_auth_key = yield $this->create_auth_key_async($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); yield $this->bind_temp_auth_key_async($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); $config = yield $this->method_call_async_read('help.getConfig', [], ['datacenter' => $id]); yield $this->sync_authorization_async($id); yield $this->get_config_async($config); } elseif ($socket->temp_auth_key === null) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); $socket->temp_auth_key = yield $this->create_auth_key_async($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); } } else { if (!$cdn) { $socket->temp_auth_key = $socket->auth_key; $config = yield $this->method_call_async_read('help.getConfig', [], ['datacenter' => $id]); yield $this->sync_authorization_async($id); yield $this->get_config_async($config); } elseif ($socket->temp_auth_key === null) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE); $socket->temp_auth_key = yield $this->create_auth_key_async($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); } } } elseif (!$cdn) { yield $this->sync_authorization_async($id); } } finally { unset($this->init_auth_dcs[$id]); } } public function sync_authorization_async($id) { if (!isset($this->datacenter->sockets[$id])) { return false; } $socket = $this->datacenter->sockets[$id]; if ($this->authorized === self::LOGGED_IN && $socket->authorized === false) { foreach ($this->datacenter->sockets as $authorized_dc_id => $authorized_socket) { if ($this->authorized_dc !== -1 && $authorized_dc_id !== $this->authorized_dc) { continue; } if ($authorized_socket->temp_auth_key !== null && $authorized_socket->auth_key !== null && $authorized_socket->authorized === true && $this->authorized === self::LOGGED_IN && $socket->authorized === false && strpos($authorized_dc_id, 'cdn') === false) { try { $this->logger->logger('Trying to copy authorization from dc '.$authorized_dc_id.' to dc '.$id); $exported_authorization = yield $this->method_call_async_read('auth.exportAuthorization', ['dc_id' => preg_replace('|_.*|', '', $id)], ['datacenter' => $authorized_dc_id]); $authorization = yield $this->method_call_async_read('auth.importAuthorization', $exported_authorization, ['datacenter' => $id]); $socket->authorized = true; break; } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('Failure while syncing authorization from DC '.$authorized_dc_id.' to DC '.$id.': '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); if ($e->rpc === 'DC_ID_INVALID') { break; } } // Turns out this DC isn't authorized after all } } } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use Amp\Artax\Request; use Amp\Deferred; use Amp\Loop; /** * Manages updates. */ trait UpdateHandler { private $got_state = false; private $channels_state; public $updates = []; public $updates_key = 0; public function pwr_update_handler($update) { if (isset($this->settings['pwr']['update_handler'])) { if (is_array($this->settings['pwr']['update_handler']) && $this->settings['pwr']['update_handler'][0] === false) { $this->settings['pwr']['update_handler'] = $this->settings['pwr']['update_handler'][1]; } if (is_string($this->settings['pwr']['update_handler'])) { return $this->{$this->settings['pwr']['update_handler']}($update); } in_array($this->settings['pwr']['update_handler'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler']) ? $this->get_updates_update_handler($update) : $this->settings['pwr']['update_handler']($update); } } public function get_updates_update_handler($update) { if (!$this->settings['updates']['handle_updates']) { return; } $this->updates[$this->updates_key++] = $update; } public function get_updates_async($params = []) { if (!$this->settings['updates']['handle_updates']) { $this->settings['updates']['handle_updates'] = true; $this->startUpdateSystem(); } if (!$this->settings['updates']['run_callback']) { $this->settings['updates']['run_callback'] = true; } array_walk($this->calls, function ($controller, $id) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $controller->discard(); } }); $params = array_merge(self::DEFAULT_GETUPDATES_PARAMS, $params); if (empty($this->updates)) { $this->update_deferred = new Deferred(); if (!$params['timeout']) { $params['timeout'] = 0.001; } yield $this->first([$this->waitUpdate(), $this->sleep($params['timeout'])]); } if (empty($this->updates)) { return []; } if ($params['offset'] < 0) { $params['offset'] = array_reverse(array_keys((array) $this->updates))[abs($params['offset']) - 1]; } $updates = []; foreach ($this->updates as $key => $value) { if ($params['offset'] > $key) { unset($this->updates[$key]); } elseif ($params['limit'] === null || count($updates) < $params['limit']) { $updates[] = ['update_id' => $key, 'update' => $value]; } } return $updates; } public $update_resolved = false; public $update_deferred; public function waitUpdate() { if (!$this->update_deferred) { $this->update_deferred = new Deferred(); } yield $this->update_deferred->promise(); $this->update_resolved = false; $this->update_deferred = new Deferred(); } public function signalUpdate() { if (!$this->update_deferred) { $this->update_deferred = new Deferred(); } Loop::defer(function () { if (!$this->update_resolved) { $this->update_resolved = true; $this->update_deferred->resolve(); } }); } public function check_msg_id($message) { if (!isset($message['to_id'])) { return true; } try { $peer_id = $this->get_id($message['to_id']); } catch (\danog\MadelineProto\Exception $e) { return true; } catch (\danog\MadelineProto\RPCErrorException $e) { return true; } $message_id = $message['id']; if (!isset($this->msg_ids[$peer_id]) || $message_id > $this->msg_ids[$peer_id]) { $this->msg_ids[$peer_id] = $message_id; return true; } return false; } public function load_update_state_async() { if (!$this->got_state) { $this->got_state = true; $this->channels_state->get(false, yield $this->get_updates_state_async()); } return $this->channels_state->get(false); } public function loadChannelState($channelId = null, $init = []) { return $this->channels_state->get($channelId, $init); } public function getChannelStates() { return $this->channels_state; } public function get_updates_state_async() { $data = yield $this->method_call_async_read('updates.getState', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]); yield $this->get_cdn_config_async($this->settings['connection_settings']['default_dc']); return $data; } public function save_update_async($update) { if ($update['_'] === 'updateConfig') { $this->config['expires'] = 0; yield $this->get_config_async(); } if (in_array($update['_'], ['updateUserName', 'updateUserPhone', 'updateUserBlocked', 'updateUserPhoto', 'updateContactRegistered', 'updateContactLink'])) { $id = $this->get_id($update); $this->full_chats[$id]['last_update'] = 0; yield $this->get_full_info_async($id); } if ($update['_'] === 'updateDcOptions') { $this->logger->logger('Got new dc options', \danog\MadelineProto\Logger::VERBOSE); yield $this->parse_dc_options_async($update['dc_options']); return; } if ($update['_'] === 'updatePhoneCall') { if (!class_exists('\\danog\\MadelineProto\\VoIP')) { $this->logger->logger('The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', \danog\MadelineProto\Logger::WARNING); return; } switch ($update['phone_call']['_']) { case 'phoneCallRequested': if (isset($this->calls[$update['phone_call']['id']])) { return; } $controller = new \danog\MadelineProto\VoIP(false, $update['phone_call']['admin_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_INCOMING); $controller->setCall($update['phone_call']); $controller->storage = ['g_a_hash' => $update['phone_call']['g_a_hash']]; $update['phone_call'] = $this->calls[$update['phone_call']['id']] = $controller; break; case 'phoneCallAccepted': if (!yield $this->confirm_call_async($update['phone_call'])) { return; } $update['phone_call'] = $this->calls[$update['phone_call']['id']]; break; case 'phoneCall': if (!yield $this->complete_call_async($update['phone_call'])) { return; } $update['phone_call'] = $this->calls[$update['phone_call']['id']]; break; case 'phoneCallDiscarded': if (!isset($this->calls[$update['phone_call']['id']])) { return; } return $this->calls[$update['phone_call']['id']]->discard($update['phone_call']['reason'], [], $update['phone_call']['need_debug']); } } if ($update['_'] === 'updateNewEncryptedMessage' && !isset($update['message']['decrypted_message'])) { $cur_state = yield $this->load_update_state_async(); if ($cur_state->qts() === -1) { $cur_state->qts($update['qts']); } if ($update['qts'] < $cur_state->qts()) { $this->logger->logger('Duplicate update. update qts: '.$update['qts'].' <= current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); return false; } if ($update['qts'] > $cur_state->qts() + 1) { $this->logger->logger('Qts hole. Fetching updates manually: update qts: '.$update['qts'].' > current qts '.$cur_state->qts().'+1, chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); $this->updaters[false]->resumeDefer(); return false; } $this->logger->logger('Applying qts: '.$update['qts'].' over current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE); yield $this->method_call_async_read('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], ['datacenter' => $this->settings['connection_settings']['default_dc']]); yield $this->handle_encrypted_update_async($update); return; } /* if ($update['_'] === 'updateEncryptedChatTyping') { $update = ['_' => 'updateUserTyping', 'user_id' => $this->encrypted_chats[$update['chat_id']]['user_id'], 'action' => ['_' => 'sendMessageTypingAction']]; } */ if ($update['_'] === 'updateEncryption') { switch ($update['chat']['_']) { case 'encryptedChatRequested': if ($this->settings['secret_chats']['accept_chats'] === false || is_array($this->settings['secret_chats']['accept_chats']) && !in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) { return; } $this->logger->logger('Accepting secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); yield $this->accept_secret_chat_async($update['chat']); break; case 'encryptedChatDiscarded': $this->logger->logger('Deleting secret chat '.$update['chat']['id'].' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE); if (isset($this->secret_chats[$update['chat']['id']])) { unset($this->secret_chats[$update['chat']['id']]); } if (isset($this->temp_requested_secret_chats[$update['chat']['id']])) { unset($this->temp_requested_secret_chats[$update['chat']['id']]); } if (isset($this->temp_rekeyed_secret_chats[$update['chat']['id']])) { unset($this->temp_rekeyed_secret_chats[$update['chat']['id']]); } break; case 'encryptedChat': $this->logger->logger('Completing creation of secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); yield $this->complete_secret_chat_async($update['chat']); break; } //$this->logger->logger($update, \danog\MadelineProto\Logger::NOTICE); } //if ($update['_'] === 'updateServiceNotification' && strpos($update['type'], 'AUTH_KEY_DROP_') === 0) { //} if (!$this->settings['updates']['handle_updates']) { return; } if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') { return; } if (isset($update['message']['from_id']) && $update['message']['from_id'] === $this->authorization['user']['id']) { $update['message']['out'] = true; } //$this->logger->logger('Saving an update of type '.$update['_'].'...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); if (isset($this->settings['pwr']['strict']) && $this->settings['pwr']['strict'] && isset($this->settings['pwr']['update_handler'])) { $this->pwr_update_handler($update); } elseif ($this->settings['updates']['run_callback']) { $this->get_updates_update_handler($update); } } public function pwr_webhook($update) { $payload = json_encode($update); //$this->logger->logger($update, $payload, json_last_error()); if ($payload === '') { $this->logger->logger('EMPTY UPDATE'); return false; } $this->callFork((function () use ($payload) { $request = (new Request($this->hook_url, 'POST'))->withHeader('content-type', 'application/json')->withBody($payload); $result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody(); $this->logger->logger('Result of webhook query is '.$result, \danog\MadelineProto\Logger::NOTICE); $result = json_decode($result, true); if (is_array($result) && isset($result['method']) && $result['method'] != '' && is_string($result['method'])) { try { $this->logger->logger('Reverse webhook command returned', yield $this->method_call_async_read($result['method'], $result, ['datacenter' => $this->datacenter->curdc])); } catch (\Throwable $e) { $this->logger->logger("Reverse webhook command returned: $e"); } } })()); } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use Amp\Loop; /** * Manages responses. */ trait ResponseHandler { public function send_msgs_state_info_async($req_msg_id, $msg_ids, $datacenter) { $this->logger->logger('Sending state info for '.count($msg_ids).' message IDs'); $info = ''; foreach ($msg_ids as $msg_id) { $cur_info = 0; if (!isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id])) { $msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256); if ((new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta + 30))->bitwise_leftShift(32)->compare($msg_id) < 0) { $this->logger->logger("Do not know anything about $msg_id and it is too small"); $cur_info |= 3; } elseif ((new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta - 300))->bitwise_leftShift(32)->compare($msg_id) > 0) { $this->logger->logger("Do not know anything about $msg_id and it is too big"); $cur_info |= 1; } else { $this->logger->logger("Do not know anything about $msg_id"); $cur_info |= 2; } } else { $this->logger->logger("Know about $msg_id"); $cur_info |= 4; } $info .= chr($cur_info); } $this->datacenter->sockets[$datacenter]->outgoing_messages[yield $this->object_call_async('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['datacenter' => $datacenter, 'postpone' => true])]['response'] = $req_msg_id; } public $n = 0; public function handle_messages($datacenter, $actual_datacenter = null) { if ($actual_datacenter) { $datacenter = $actual_datacenter; } $only_updates = true; while ($this->datacenter->sockets[$datacenter]->new_incoming) { reset($this->datacenter->sockets[$datacenter]->new_incoming); $current_msg_id = key($this->datacenter->sockets[$datacenter]->new_incoming); if (!isset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id])) { unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); continue; } $this->logger->logger((isset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ').$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].' from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); switch ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_']) { case 'msgs_ack': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { $this->ack_outgoing_message_id($msg_id, $datacenter); // Acknowledge that the server received my message } unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'rpc_result': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->ack_incoming_message_id($current_msg_id, $datacenter); $only_updates = false; // Acknowledge that the server received my request $req_msg_id = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id']; $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'] = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['result']; $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $this->handle_response($req_msg_id, $current_msg_id, $datacenter); break; case 'future_salts': case 'msgs_state_info': $msg_id_type = 'req_msg_id'; case 'bad_server_salt': case 'bad_msg_notification': $msg_id_type = isset($msg_id_type) ? $msg_id_type : 'bad_msg_id'; case 'pong': $msg_id_type = isset($msg_id_type) ? $msg_id_type : 'msg_id'; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'][$msg_id_type], $current_msg_id, $datacenter); unset($msg_id_type); break; case 'new_session_created': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; $this->datacenter->sockets[$datacenter]->temp_auth_key['server_salt'] = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['server_salt']; $this->ack_incoming_message_id($current_msg_id, $datacenter); // Acknowledge that I received the server's response if ($this->authorized === self::LOGGED_IN && !$this->initing_authorization && $this->datacenter->sockets[$this->datacenter->curdc]->temp_auth_key !== null && isset($this->updaters[false])) { $this->updaters[false]->resumeDefer(); } unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msg_container': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $only_updates = false; foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['messages'] as $message) { $this->datacenter->sockets[$datacenter]->check_message_id($message['msg_id'], ['outgoing' => false, 'container' => true]); $this->datacenter->sockets[$datacenter]->incoming_messages[$message['msg_id']] = ['seq_no' => $message['seqno'], 'content' => $message['body'], 'from_container' => true]; $this->datacenter->sockets[$datacenter]->new_incoming[$message['msg_id']] = $message['msg_id']; } ksort($this->datacenter->sockets[$datacenter]->new_incoming); //$this->handle_messages($datacenter); //$this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msg_copy': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; $this->ack_incoming_message_id($current_msg_id, $datacenter); // Acknowledge that I received the server's response if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) { $this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id'], $datacenter); // Acknowledge that I received the server's response } else { $message = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']; $this->datacenter->sockets[$datacenter]->check_message_id($message['orig_message']['msg_id'], ['outgoing' => false, 'container' => true]); $this->datacenter->sockets[$datacenter]->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']]; $this->datacenter->sockets[$datacenter]->new_incoming[$message['orig_message']['msg_id']] = $message['orig_message']['msg_id']; } unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'http_wait': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; $this->logger->logger($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::NOTICE); unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msgs_state_req': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->callFork($this->send_msgs_state_info_async($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter)); unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); break; case 'msgs_all_info': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) { $info = ord($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key]); $msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256); $status = 'Status for message id '.$msg_id.': '; /*if ($info & 4) { *$this->got_response_for_outgoing_message_id($msg_id, $datacenter); *} */ foreach (self::MSGS_INFO_FLAGS as $flag => $description) { if (($info & $flag) !== 0) { $status .= $description; } } $this->logger->logger($status, \danog\MadelineProto\Logger::NOTICE); } break; case 'msg_detailed_info': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $only_updates = false; if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id']])) { if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) { $this->handle_response($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_id'], $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id'], $datacenter); } else { $this->callFork($this->object_call_async('msg_resend_req', ['msg_ids' => [$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']]], ['datacenter' => $datacenter, 'postpone' => true])); } } break; case 'msg_new_detailed_info': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']])) { $this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id'], $datacenter); } else { $this->callFork($this->object_call_async('msg_resend_req', ['msg_ids' => [$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['answer_msg_id']]], ['datacenter' => $datacenter, 'postpone' => true])); } break; case 'msg_resend_req': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $ok = true; foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { if (!isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$msg_id]) || isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id])) { $ok = false; } } if ($ok) { foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { $this->method_recall('', ['message_id' => $msg_id, 'datacenter' => $datacenter, 'postpone' => true]); } } else { $this->callFork($this->send_msgs_state_info_async($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter)); } break; case 'msg_resend_ans_req': $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $only_updates = false; unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->callFork($this->send_msgs_state_info_async($current_msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'], $datacenter)); foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $msg_id) { if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']) && isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']])) { $this->callFork($this->object_call_async($this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']]['_'], $this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id]['response']]['body'], ['datacenter' => $datacenter, 'postpone' => true])); } } break; default: $this->datacenter->sockets[$datacenter]->check_in_seq_no($current_msg_id); $this->ack_incoming_message_id($current_msg_id, $datacenter); // Acknowledge that I received the server's response $response_type = $this->constructors->find_by_predicate($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'])['type']; switch ($response_type) { case 'Updates': unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); if (strpos($datacenter, 'cdn') === false) { $this->callForkDefer($this->handle_updates_async($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'])); } unset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']); $only_updates = true && $only_updates; break; default: $only_updates = false; $this->logger->logger('Trying to assign a response of type '.$response_type.' to its request...', \danog\MadelineProto\Logger::VERBOSE); foreach ($this->datacenter->sockets[$datacenter]->new_outgoing as $key => $expecting_msg_id) { $expecting = $this->datacenter->sockets[$datacenter]->outgoing_messages[$expecting_msg_id]; if (!isset($expecting['type'])) { continue; } $this->logger->logger('Does the request of return type '.$expecting['type'].' match?', \danog\MadelineProto\Logger::VERBOSE); if ($response_type === $expecting['type']) { $this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE); unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]); $this->handle_response($expecting_msg_id, $current_msg_id, $datacenter); break 2; } $this->logger->logger('No', \danog\MadelineProto\Logger::VERBOSE); } throw new \danog\MadelineProto\ResponseException('Dunno how to handle '.PHP_EOL.var_export($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], true)); break; } break; } } if ($this->datacenter->sockets[$datacenter]->pending_outgoing) $this->datacenter->sockets[$datacenter]->writer->resume(); //$this->n--; return $only_updates; } public function handle_reject($datacenter, &$request, $data) { if (isset($request['promise']) && is_object($request['promise'])) { Loop::defer(function () use (&$request, $data) { if (isset($request['promise'])) { $promise = $request['promise']; unset($request['promise']); $promise->fail($data); } else { $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-')); $this->logger->logger("Rejecting: $data"); } }); } elseif (isset($request['container'])) { foreach ($request['container'] as $message_id) { $this->handle_reject($datacenter, $this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id], $data); } } else { $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-')); $this->logger->logger("Rejecting: $data"); } } public function handle_response($request_id, $response_id, $datacenter) { $response = &$this->datacenter->sockets[$datacenter]->incoming_messages[$response_id]['content']; unset($this->datacenter->sockets[$datacenter]->incoming_messages[$response_id]['content']); $request = &$this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]; if (isset($response['_'])) { switch ($response['_']) { case 'rpc_error': if (isset($request['method']) && $request['method'] && $request['_'] !== 'auth.bindTempAuthKey' && $this->datacenter->sockets[$datacenter]->temp_auth_key !== null && (!isset($this->datacenter->sockets[$datacenter]->temp_auth_key['connection_inited']) || $this->datacenter->sockets[$datacenter]->temp_auth_key['connection_inited'] === false)) { $this->datacenter->sockets[$datacenter]->temp_auth_key['connection_inited'] = true; } if (in_array($response['error_message'], ['PERSISTENT_TIMESTAMP_EMPTY', 'PERSISTENT_TIMESTAMP_OUTDATED', 'PERSISTENT_TIMESTAMP_INVALID'])) { $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\PTSException($response['error_message'])); return; } if (strpos($response['error_message'], 'FILE_REFERENCE_') === 0) { $this->logger->logger("Got {$response['error_message']}, refreshing file reference and repeating method call..."); $request['refresh_references'] = true; if (isset($request['serialized_body'])) { unset($request['serialized_body']); } $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]); return; } switch ($response['error_code']) { case 500: case -500: if ($response['error_message'] === 'MSG_WAIT_FAILED') { $this->datacenter->sockets[$datacenter]->call_queue[$request['queue']] = []; $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]); return; } $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], isset($request['_']) ? $request['_'] : '')); return; case 303: $old_datacenter = $datacenter; $this->datacenter->curdc = $datacenter = (int) preg_replace('/[^0-9]+/', '', $response['error_message']); if (isset($request['file']) && $request['file'] && isset($this->datacenter->sockets[$datacenter.'_media'])) { \danog\MadelineProto\Logger::log('Using media DC'); $datacenter .= '_media'; } if (isset($request['user_related']) && $request['user_related']) { $this->settings['connection_settings']['default_dc'] = $this->authorized_dc = $this->datacenter->curdc; } Loop::defer([$this, 'method_recall'], ['message_id' => $request_id, 'datacenter' => $datacenter, 'old_datacenter' => $old_datacenter]); //$this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'old_datacenter' => $old_datacenter, 'postpone' => true]); return; case 401: switch ($response['error_message']) { case 'USER_DEACTIVATED': case 'SESSION_REVOKED': case 'SESSION_EXPIRED': $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->logger->logger($response['error_message'], \danog\MadelineProto\Logger::FATAL_ERROR); foreach ($this->datacenter->sockets as $socket) { $socket->temp_auth_key = null; $socket->session_id = null; $socket->auth_key = null; $socket->authorized = false; } if ($response['error_message'] === 'USER_DEACTIVATED') { $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR); $this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR); $phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using'; $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR); } $this->resetSession(); $this->callFork((function () use ($datacenter, &$request, &$response) { yield $this->init_authorization_async(); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], isset($request['_']) ? $request['_'] : '')); })()); return; case 'AUTH_KEY_UNREGISTERED': case 'AUTH_KEY_INVALID': if ($this->authorized !== self::LOGGED_IN) { $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->callFork((function () use ($datacenter, &$request, &$response) { yield $this->init_authorization_async(); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], isset($request['_']) ? $request['_'] : '')); })()); return; } $this->datacenter->sockets[$datacenter]->session_id = null; $this->datacenter->sockets[$datacenter]->temp_auth_key = null; $this->datacenter->sockets[$datacenter]->auth_key = null; $this->datacenter->sockets[$datacenter]->authorized = false; $this->logger->logger('Auth key not registered, resetting temporary and permanent auth keys...', \danog\MadelineProto\Logger::ERROR); if ($this->authorized_dc === $datacenter && $this->authorized === self::LOGGED_IN) { $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->logger->logger('Permanent auth key was main authorized key, logging out...', \danog\MadelineProto\Logger::FATAL_ERROR); foreach ($this->datacenter->sockets as $socket) { $socket->temp_auth_key = null; $socket->auth_key = null; $socket->authorized = false; } $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR); $this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR); $phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using'; $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->resetSession(); $this->callFork((function () use ($datacenter, &$request, &$response) { yield $this->init_authorization_async(); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], isset($request['_']) ? $request['_'] : '')); })()); return; } $this->callFork((function () use ($request_id, $datacenter) { yield $this->init_authorization_async(); $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter]); })()); return; case 'AUTH_KEY_PERM_EMPTY': $this->logger->logger('Temporary auth key not bound, resetting temporary auth key...', \danog\MadelineProto\Logger::ERROR); $this->datacenter->sockets[$datacenter]->temp_auth_key = null; $this->callFork((function () use ($request_id, $datacenter) { yield $this->init_authorization_async(); $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter]); })()); return; } $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], isset($request['_']) ? $request['_'] : '')); return; case 420: $seconds = preg_replace('/[^0-9]+/', '', $response['error_message']); $limit = isset($request['FloodWaitLimit']) ? $request['FloodWaitLimit'] : $this->settings['flood_timeout']['wait_if_lt']; if (is_numeric($seconds) && $seconds < $limit) { //$this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->logger->logger('Flood, waiting '.$seconds.' seconds before repeating async call...', \danog\MadelineProto\Logger::NOTICE); $request['sent'] += $seconds; Loop::delay($seconds * 1000, [$this, 'method_recall'], ['message_id' => $request_id, 'datacenter' => $datacenter]); return; } // no break default: $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code'], isset($request['_']) ? $request['_'] : '')); return; } return; case 'boolTrue': case 'boolFalse': $response = $response['_'] === 'boolTrue'; break; case 'bad_server_salt': case 'bad_msg_notification': $this->logger->logger('Received bad_msg_notification: '.self::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING); switch ($response['error_code']) { case 48: $this->datacenter->sockets[$datacenter]->temp_auth_key['server_salt'] = $response['new_server_salt']; $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]); return; case 16: case 17: $this->datacenter->sockets[$datacenter]->time_delta = (int) (new \phpseclib\Math\BigInteger(strrev($response_id), 256))->bitwise_rightShift(32)->subtract(new \phpseclib\Math\BigInteger(time()))->toString(); $this->logger->logger('Set time delta to '.$this->datacenter->sockets[$datacenter]->time_delta, \danog\MadelineProto\Logger::WARNING); $this->reset_session(); $this->datacenter->sockets[$datacenter]->temp_auth_key = null; $this->callFork((function () use ($datacenter, $request_id) { yield $this->init_authorization_async(); $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter]); })()); return; } $this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.self::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], isset($request['_']) ? $request['_'] : '')); return; } } if (isset($request['method']) && $request['method'] && $request['_'] !== 'auth.bindTempAuthKey' && $this->datacenter->sockets[$datacenter]->temp_auth_key !== null && (!isset($this->datacenter->sockets[$datacenter]->temp_auth_key['connection_inited']) || $this->datacenter->sockets[$datacenter]->temp_auth_key['connection_inited'] === false)) { $this->datacenter->sockets[$datacenter]->temp_auth_key['connection_inited'] = true; } if (!isset($request['promise'])) { $this->logger->logger('Response: already got response for '.(isset($request['_']) ? $request['_'] : '-').' with message ID '.$this->unpack_signed_long($request_id)); return; } $botAPI = isset($request['botAPI']) && $request['botAPI']; if (isset($response['_']) && strpos($datacenter, 'cdn') === false && $this->constructors->find_by_predicate($response['_'])['type'] === 'Updates') { $response['request'] = $request; $this->callForkDefer($this->handle_updates_async($response)); } unset($request); $this->got_response_for_outgoing_message_id($request_id, $datacenter); $r = isset($response['_']) ? $response['_'] : json_encode($response); $this->logger->logger("Defer sending $r to deferred"); $this->callFork(( function () use ($request_id, $response, $datacenter, $botAPI) { $r = isset($response['_']) ? $response['_'] : json_encode($response); $this->logger->logger("Deferred: sent $r to deferred"); if ($botAPI) { $response = yield $this->MTProto_to_botAPI_async($response); } if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise'])) { // This should not happen but happens, should debug $promise = $this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise']; unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$request_id]['promise']); $promise->resolve($response); } } )()); } public function handle_updates_async($updates, $actual_updates = null) { if (!$this->settings['updates']['handle_updates']) { return; } if ($actual_updates) { $updates = $actual_updates; } $this->logger->logger('Parsing updates ('.$updates['_'].') received via the socket...', \danog\MadelineProto\Logger::VERBOSE); switch ($updates['_']) { case 'updates': case 'updatesCombined': $result = []; foreach ($updates['updates'] as $key => $update) { if ($update['_'] === 'updateNewMessage' || $update['_'] === 'updateReadMessagesContents' || $update['_'] === 'updateEditMessage' || $update['_'] === 'updateDeleteMessages' || $update['_'] === 'updateReadHistoryInbox' || $update['_'] === 'updateReadHistoryOutbox' || $update['_'] === 'updateWebPage' || $update['_'] === 'updateMessageID') { $result[yield $this->feeders[false]->feedSingle($update)] = true; unset($updates['updates'][$key]); } } $this->seqUpdater->addPendingWakeups($result); if ($updates['updates']) { if ($updates['_'] === 'updatesCombined') { $updates['options'] = ['seq_start' => $updates['seq_start'], 'seq_end' => $updates['seq'], 'date' => $updates['date']]; } else { $updates['options'] = ['seq_start' => $updates['seq'], 'seq_end' => $updates['seq'], 'date' => $updates['date']]; } $this->seqUpdater->feed($updates); } $this->seqUpdater->resume(); break; case 'updateShort': $this->feeders[yield $this->feeders[false]->feedSingle($updates['update'])]->resume(); break; case 'updateShortSentMessage': if (!isset($updates['request']['body'])) { break; } $updates['user_id'] = (yield $this->get_info_async($updates['request']['body']['peer']))['bot_api_id']; $updates['message'] = $updates['request']['body']['message']; unset($updates['request']); case 'updateShortMessage': case 'updateShortChatMessage': $from_id = isset($updates['from_id']) ? $updates['from_id'] : ($updates['out'] ? $this->authorization['user']['id'] : $updates['user_id']); $to_id = isset($updates['chat_id']) ? -$updates['chat_id'] : ($updates['out'] ? $updates['user_id'] : $this->authorization['user']['id']); if (!yield $this->peer_isset_async($from_id) || !yield $this->peer_isset_async($to_id) || isset($updates['via_bot_id']) && !yield $this->peer_isset_async($updates['via_bot_id']) || isset($updates['entities']) && !yield $this->entities_peer_isset_async($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwd_peer_isset_async($updates['fwd_from'])) { yield $this->updaters[false]->resume(); return; } $message = $updates; $message['_'] = 'message'; $message['from_id'] = $from_id; try { $message['to_id'] = (yield $this->get_info_async($to_id))['Peer']; } catch (\danog\MadelineProto\Exception $e) { $this->logger->logger('Still did not get user in database, postponing update', \danog\MadelineProto\Logger::ERROR); //$this->pending_updates[] = $updates; break; } catch (\danog\MadelineProto\RPCErrorException $e) { $this->logger->logger('Still did not get user in database, postponing update', \danog\MadelineProto\Logger::ERROR); //$this->pending_updates[] = $updates; break; } $update = ['_' => 'updateNewMessage', 'message' => $message, 'pts' => $updates['pts'], 'pts_count' => $updates['pts_count']]; $this->feeders[yield $this->feeders[false]->feedSingle($update)]->resume(); break; case 'updatesTooLong': $this->updaters[false]->resume(); break; default: throw new \danog\MadelineProto\ResponseException('Unrecognized update received: '.var_export($updates, true)); break; } } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; use danog\MadelineProto\Exception; use danog\MadelineProto\Magic; use danog\MadelineProto\SecurityException; use danog\MadelineProto\Tools; use phpseclib\Math\BigInteger; /** * Manages password calculation. */ class PasswordCalculator { use AuthKeyHandler; use Tools; private $new_algo; private $secure_random = ''; private $current_algo; private $srp_B; private $srp_BForHash; private $srp_id; public $logger; // This is needed do not remove this public function __construct($logger) { $this->logger = $logger; } public function addInfo(array $object) { if ($object['_'] !== 'account.password') { throw new Exception('Wrong constructor'); } if ($object['has_secure_values']) { throw new Exception('Cannot parse secure values'); } if ($object['has_password']) { switch ($object['current_algo']['_']) { case 'passwordKdfAlgoUnknown': throw new Exception('Update your client to continue'); case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow': $object['current_algo']['g'] = new BigInteger($object['current_algo']['g']); $object['current_algo']['p'] = new BigInteger((string) $object['current_algo']['p'], 256); $this->check_p_g($object['current_algo']['p'], $object['current_algo']['g']); $object['current_algo']['gForHash'] = str_pad($object['current_algo']['g']->toBytes(), 256, chr(0), \STR_PAD_LEFT); $object['current_algo']['pForHash'] = str_pad($object['current_algo']['p']->toBytes(), 256, chr(0), \STR_PAD_LEFT); break; default: throw new Exception("Unknown KDF algo {$object['current_algo']['_']}"); } $this->current_algo = $object['current_algo']; $object['srp_B'] = new BigInteger((string) $object['srp_B'], 256); if ($object['srp_B']->compare(\danog\MadelineProto\Magic::$zero) < 0) { throw new SecurityException('srp_B < 0'); } if ($object['srp_B']->compare($object['current_algo']['p']) > 0) { throw new SecurityException('srp_B > p'); } $this->srp_B = $object['srp_B']; $this->srp_BForHash = str_pad($object['srp_B']->toBytes(), 256, chr(0), \STR_PAD_LEFT); $this->srp_id = $object['srp_id']; } else { $this->current_algo = null; $this->srp_B = null; $this->srp_BForHash = null; $this->srp_id = null; } switch ($object['new_algo']['_']) { case 'passwordKdfAlgoUnknown': throw new Exception('Update your client to continue'); case 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow': $object['new_algo']['g'] = new BigInteger($object['new_algo']['g']); $object['new_algo']['p'] = new BigInteger((string) $object['new_algo']['p'], 256); $this->check_p_g($object['new_algo']['p'], $object['new_algo']['g']); $object['new_algo']['gForHash'] = str_pad($object['new_algo']['g']->toBytes(), 256, chr(0), \STR_PAD_LEFT); $object['new_algo']['pForHash'] = str_pad($object['new_algo']['p']->toBytes(), 256, chr(0), \STR_PAD_LEFT); break; default: throw new Exception("Unknown KDF algo {$object['new_algo']['_']}"); } $this->new_algo = $object['new_algo']; $this->secure_random = $object['secure_random']; } public function createSalt(string $prefix = ''): string { return $prefix.$this->random(32); } public function hashSha256(string $data, string $salt): string { return hash('sha256', $salt.$data.$salt, true); } public function hashPassword(string $password, string $client_salt, string $server_salt): string { $buf = $this->hashSha256($password, $client_salt); $buf = $this->hashSha256($buf, $server_salt); $hash = hash_pbkdf2('sha512', $buf, $client_salt, 100000, 0, true); return $this->hashSha256($hash, $server_salt); } public function getCheckPassword(string $password): array { if ($password === '') { return ['_' => 'inputCheckPasswordEmpty']; } $client_salt = $this->current_algo['salt1']; $server_salt = $this->current_algo['salt2']; $g = $this->current_algo['g']; $gForHash = $this->current_algo['gForHash']; $p = $this->current_algo['p']; $pForHash = $this->current_algo['pForHash']; $B = $this->srp_B; $BForHash = $this->srp_BForHash; $id = $this->srp_id; $x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256); $g_x = $g->powMod($x, $p); $k = new BigInteger(hash('sha256', $pForHash.$gForHash, true), 256); $kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p); $a = new BigInteger($this->random(2048 / 8), 256); $A = $g->powMod($a, $p); $this->check_G($A, $p); $AForHash = str_pad($A->toBytes(), 256, chr(0), \STR_PAD_LEFT); $b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x); $u = new BigInteger(hash('sha256', $AForHash.$BForHash, true), 256); $ux = $u->multiply($x); $a_ux = $a->add($ux); $S = $b_kg_x->powMod($a_ux, $p); $SForHash = str_pad($S->toBytes(), 256, chr(0), \STR_PAD_LEFT); $K = hash('sha256', $SForHash, true); $h1 = hash('sha256', $pForHash, true); $h2 = hash('sha256', $gForHash, true); $h1 ^= $h2; $M1 = hash('sha256', $h1.hash('sha256', $client_salt, true).hash('sha256', $server_salt, true).$AForHash.$BForHash.$K, true); return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1]; } public function getPassword(array $params): array { $return = ['password' => $this->getCheckPassword(isset($params['password']) ? $params['password'] : ''), 'new_settings' => ['_' => 'account.passwordInputSettings', 'new_algo' => ['_' => 'passwordKdfAlgoUnknown'], 'new_password_hash' => '', 'hint' => '']]; $new_settings = &$return['new_settings']; if (isset($params['new_password']) && $params['new_password'] !== '') { $client_salt = $this->createSalt($this->new_algo['salt1']); $server_salt = $this->new_algo['salt2']; $g = $this->new_algo['g']; $p = $this->new_algo['p']; $pForHash = $this->new_algo['pForHash']; $x = new BigInteger($this->hashPassword($params['new_password'], $client_salt, $server_salt), 256); $v = $g->powMod($x, $p); $vForHash = str_pad($v->toBytes(), 256, chr(0), \STR_PAD_LEFT); $new_settings['new_algo'] = [ '_' => 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow', 'salt1' => $client_salt, 'salt2' => $server_salt, 'g' => (int) $g->toString(), 'p' => $pForHash, ]; $new_settings['new_password_hash'] = $vForHash; $new_settings['hint'] = $params['hint']; if (isset($params['email'])) { $new_settings['email'] = $params['email']; } } return $return; } } . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\MTProtoTools; /** * Manages acknowledgement of messages. */ trait AckHandler { public function ack_outgoing_message_id($message_id, $datacenter) { // The server acknowledges that it received my message if (!isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id])) { $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); return false; } //$this->logger->logger("Ack-ed ".$this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['_']." with message ID $message_id on DC $datacenter"); /* if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['body'])) { unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['body']); } if (isset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id])) { unset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id]); }*/ return true; } public function got_response_for_outgoing_message_id($message_id, $datacenter) { // The server acknowledges that it received my message if (!isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id])) { $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); return false; } if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['body'])) { unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['body']); } if (isset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['serialized_body'])) { unset($this->datacenter->sockets[$datacenter]->outgoing_messages[$message_id]['serialized_body']); } if (isset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id])) { unset($this->datacenter->sockets[$datacenter]->new_outgoing[$message_id]); } return true; } public function ack_incoming_message_id($message_id, $datacenter) { // I let the server know that I received its message if (!isset($this->datacenter->sockets[$datacenter]->incoming_messages[$message_id])) { $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); } /*if ($this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === null || $this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") { // || (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack']) && $this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack'])) { return; }*/ $this->datacenter->sockets[$datacenter]->ack_queue[$message_id] = $message_id; return true; } } { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "270785512", "predicate": "inputPeerContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1690012891", "predicate": "inputPeerForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-2031530139", "predicate": "inputUserContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputUser" }, { "id": "1700689151", "predicate": "inputUserForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "767900285", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" } ], "type": "InputMedia" }, { "id": "-1893027092", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "322623222", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1726817601", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "2130852582", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1879553105", "predicate": "userSelf", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" }, { "name": "inactive", "type": "Bool" } ], "type": "User" }, { "id": "-894214632", "predicate": "userContact", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-640891665", "predicate": "userRequest", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "123533224", "predicate": "userForeign", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-704549510", "predicate": "userDeleted", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1855757255", "predicate": "chat", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "left", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-83047359", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "date", "type": "int" } ], "type": "Chat" }, { "id": "1661886910", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "265468810", "predicate": "chatParticipantsForbidden", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "1450613171", "predicate": "message", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "Message" }, { "id": "-1553471722", "predicate": "messageForwarded", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "fwd_from_id", "type": "int" }, { "name": "fwd_date", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "Message" }, { "id": "495384334", "predicate": "messageService", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "-926655958", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageMedia" }, { "id": "-1563278704", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "694364726", "predicate": "messageMediaUnsupported", "params": [ { "name": "bytes", "type": "bytes" } ], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1422222932", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "582313809", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "sizes", "type": "Vector" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "948937617", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-486486981", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_invited", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-155815004", "predicate": "auth.authorization", "params": [ { "name": "expires", "type": "int" }, { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1490799288", "predicate": "inputReportReasonSpam", "params": [], "type": "ReportReason" }, { "id": "505595789", "predicate": "inputReportReasonViolence", "params": [], "type": "ReportReason" }, { "id": "777640226", "predicate": "inputReportReasonPornography", "params": [], "type": "ReportReason" }, { "id": "-512463606", "predicate": "inputReportReasonOther", "params": [ { "name": "text", "type": "string" } ], "type": "ReportReason" }, { "id": "1997575642", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "real_first_name", "type": "string" }, { "name": "real_last_name", "type": "string" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "322183672", "predicate": "contacts.foreignLinkUnknown", "params": [], "type": "contacts.ForeignLink" }, { "id": "-1484775609", "predicate": "contacts.foreignLinkRequested", "params": [ { "name": "has_phone", "type": "Bool" } ], "type": "contacts.ForeignLink" }, { "id": "468356321", "predicate": "contacts.foreignLinkMutual", "params": [], "type": "contacts.ForeignLink" }, { "id": "-768992160", "predicate": "contacts.myLinkEmpty", "params": [], "type": "contacts.MyLink" }, { "id": "1818882030", "predicate": "contacts.myLinkRequested", "params": [ { "name": "contact", "type": "Bool" } ], "type": "contacts.MyLink" }, { "id": "-1035932711", "predicate": "contacts.myLinkContact", "params": [], "type": "contacts.MyLink" }, { "id": "-322001931", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "contacts.MyLink" }, { "name": "foreign_link", "type": "contacts.ForeignLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector" }, { "name": "retry_contacts", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-1768654661", "predicate": "messages.statedMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessages" }, { "id": "-797251802", "predicate": "messages.statedMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-772484260", "predicate": "messages.sentMessage", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "-2125411368", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "messages.ChatFull" }, { "id": "-1210173710", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "-3644025", "predicate": "inputMessagesFilterGif", "params": [], "type": "MessagesFilter" }, { "id": "20626867", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-966484431", "predicate": "updateReadMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" } ], "type": "Update" }, { "id": "-1456734682", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector" }, { "name": "pts", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "1369737882", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "contacts.MyLink" }, { "name": "foreign_link", "type": "contacts.ForeignLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector" }, { "name": "new_encrypted_messages", "type": "Vector" }, { "name": "other_updates", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-738961532", "predicate": "updateShortMessage", "params": [ { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "724548942", "predicate": "updateShortChatMessage", "params": [ { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "784507964", "predicate": "dcOption", "params": [ { "name": "id", "type": "int" }, { "name": "hostname", "type": "string" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "2108568544", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector" }, { "name": "chat_big_size", "type": "int" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" }, { "name": "disabled_features", "type": "Vector" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1047852486", "predicate": "messages.statedMessagesLinks", "params": [ { "name": "messages", "type": "Vector" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "links", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessages" }, { "id": "-1448138623", "predicate": "messages.statedMessageLink", "params": [ { "name": "message", "type": "Message" }, { "name": "chats", "type": "Vector" }, { "name": "users", "type": "Vector" }, { "name": "links", "type": "Vector" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-371504577", "predicate": "messages.sentMessageLink", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "links", "type": "Vector" } ], "type": "messages.SentMessage" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "974056226", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-945003370", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1845219337", "predicate": "sendMessageUploadVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-424899985", "predicate": "sendMessageUploadAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-1727382502", "predicate": "sendMessageUploadPhotoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1884362354", "predicate": "sendMessageUploadDocumentAction", "params": [], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "-360210539", "predicate": "contactFound", "params": [ { "name": "user_id", "type": "int" } ], "type": "ContactFound" }, { "id": "90570766", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector" }, { "name": "users", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "-83208409", "predicate": "documentAttributeSticker", "params": [], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "85215461", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-588304126", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "packs", "type": "Vector" }, { "name": "documents", "type": "Vector" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector" }, { "id": "-1374118561", "method": "account.reportPeer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reason", "type": "ReportReason" } ], "type": "Bool" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Messages" }, { "id": "-321970698", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1834885329", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "132772523", "method": "messages.search", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-287800122", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "read_contents", "type": "Bool" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "351460618", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "682347368", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "1289620139", "method": "messages.sendMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "messages.SentMessage" }, { "id": "-1547149962", "method": "messages.sendMedia", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "messages.StatedMessage" }, { "id": "1363988751", "method": "messages.forwardMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector" } ], "type": "messages.StatedMessages" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-1262720843", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "messages.StatedMessage" }, { "id": "-662601187", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "messages.StatedMessage" }, { "id": "787082910", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-1010447069", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.StatedMessage" }, { "id": "1100847854", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector" }, { "name": "title", "type": "string" } ], "type": "messages.StatedMessage" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1209117380", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "66319602", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "messages.StatedMessage" }, { "id": "1102776690", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "messages.StatedMessages" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "894131138", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector" } ], "type": "Vector" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "200282908", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" } ] }. * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\Artax\Client; use Amp\Artax\Cookie\ArrayCookieJar; use Amp\Artax\DefaultClient; use Amp\Artax\HttpSocketPool; use Amp\CancellationToken; use Amp\Dns\Resolver; use Amp\DoH\DoHConfig; use Amp\DoH\Rfc8484StubResolver; use Amp\Socket\ClientConnectContext; use danog\MadelineProto\Stream\Common\BufferedRawStream; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream; use danog\MadelineProto\Stream\MTProtoTransport\FullStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpStream; use danog\MadelineProto\Stream\MTProtoTransport\IntermediatePaddedStream; use danog\MadelineProto\Stream\MTProtoTransport\IntermediateStream; use danog\MadelineProto\Stream\MTProtoTransport\ObfuscatedStream; use danog\MadelineProto\Stream\Proxy\HttpProxy; use danog\MadelineProto\Stream\Proxy\SocksProxy; use danog\MadelineProto\Stream\Transport\DefaultStream; use danog\MadelineProto\Stream\Transport\WssStream; use danog\MadelineProto\Stream\Transport\WsStream; use danog\MadelineProto\TL\Conversion\Exception; use Amp\DoH\Nameserver; use function Amp\call; use Amp\Promise; use Amp\Socket\ClientTlsContext; use Amp\Deferred; use Amp\NullCancellationToken; use function Amp\Socket\Internal\parseUri; use Amp\Dns\Record; use Amp\Socket\ConnectException; use Amp\Loop; use Amp\TimeoutException; use Amp\Socket\ClientSocket; use Amp\Dns\Rfc1035StubResolver; /** * Manages datacenters. */ class DataCenter { use \danog\MadelineProto\Tools; use \danog\Serializable; public $sockets = []; public $curdc = 0; private $API; private $dclist = []; private $settings = []; private $HTTPClient; private $DoHClient; public function __sleep() { return ['sockets', 'curdc', 'dclist', 'settings']; } public function __magic_construct($API, $dclist, $settings) { $this->API = $API; $this->dclist = $dclist; $this->settings = $settings; foreach ($this->sockets as $key => $socket) { if ($socket instanceof Connection && !strpos($key, '_bk')) { $this->API->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['dc_con_stop'], $key), \danog\MadelineProto\Logger::VERBOSE); $socket->old = true; $socket->setExtra($this->API); $socket->disconnect(); } else { unset($this->sockets[$key]); } } $this->HTTPClient = new DefaultClient(new ArrayCookieJar(), new HttpSocketPool(new ProxySocketPool($this))); $DoHConfig = new DoHConfig( [ new Nameserver('https://mozilla.cloudflare-dns.com/dns-query'), new Nameserver('https://google.com/resolve', Nameserver::GOOGLE_JSON, ["Host" => "dns.google.com"]), ], $this->HTTPClient ); $this->DoHClient = Magic::$altervista ? new Rfc1035StubResolver() : new Rfc8484StubResolver($DoHConfig); } /** * Asynchronously establish an encrypted TCP connection (non-blocking). * * Note: Once resolved the socket stream will already be set to non-blocking mode. * * @param string $uricall * @param ClientConnectContext $socketContext * @param ClientTlsContext $tlsContext * @param CancellationToken $token * * @return Promise */ public function cryptoConnect( string $uri, ClientConnectContext $socketContext = null, ClientTlsContext $tlsContext = null, CancellationToken $token = null ): Promise { return call(function () use ($uri, $socketContext, $tlsContext, $token) { $tlsContext = $tlsContext ?? new ClientTlsContext; if ($tlsContext->getPeerName() === null) { $tlsContext = $tlsContext->withPeerName(\parse_url($uri, PHP_URL_HOST)); } /** @var ClientSocket $socket */ $socket = yield $this->socketConnect($uri, $socketContext, $token); $promise = $socket->enableCrypto($tlsContext); if ($token) { $deferred = new Deferred; $id = $token->subscribe([$deferred, "fail"]); $promise->onResolve(function ($exception) use ($id, $token, $deferred) { if ($token->isRequested()) { return; } $token->unsubscribe($id); if ($exception) { $deferred->fail($exception); return; } $deferred->resolve(); }); $promise = $deferred->promise(); } try { yield $promise; } catch (\Throwable $exception) { $socket->close(); throw $exception; } return $socket; }); } /** * Asynchronously establish a socket connection to the specified URI. * * @param string $uri URI in scheme://host:port format. TCP is assumed if no scheme is present. * @param ClientConnectContext $socketContext Socket connect context to use when connecting. * @param CancellationToken|null $token * * @return Promise<\Amp\Socket\ClientSocket> */ public function socketConnect(string $uri, ClientConnectContext $socketContext = null, CancellationToken $token = null): Promise { return call(function () use ($uri, $socketContext, $token) { $socketContext = $socketContext ?? new ClientConnectContext; $token = $token ?? new NullCancellationToken; $attempt = 0; $uris = []; $failures = []; list($scheme, $host, $port) = parseUri($uri); if ($host[0] === '[') { $host = substr($host, 1, -1); } if ($port === 0 || @\inet_pton($host)) { // Host is already an IP address or file path. $uris = [$uri]; } else { // Host is not an IP address, so resolve the domain name. $records = yield $this->DoHClient->resolve($host, $socketContext->getDnsTypeRestriction()); // Usually the faster response should be preferred, but we don't have a reliable way of determining IPv6 // support, so we always prefer IPv4 here. \usort($records, function (Record $a, Record $b) { return $a->getType() - $b->getType(); }); foreach ($records as $record) { /** @var Record $record */ if ($record->getType() === Record::AAAA) { $uris[] = \sprintf("%s://[%s]:%d", $scheme, $record->getValue(), $port); } else { $uris[] = \sprintf("%s://%s:%d", $scheme, $record->getValue(), $port); } } } $flags = \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT; $timeout = $socketContext->getConnectTimeout(); foreach ($uris as $builtUri) { try { $context = \stream_context_create($socketContext->toStreamContextArray()); if (!$socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $context)) { throw new ConnectException(\sprintf( "Connection to %s failed: [Error #%d] %s%s", $uri, $errno, $errstr, $failures ? "; previous attempts: ".\implode($failures) : "" ), $errno); } \stream_set_blocking($socket, false); $deferred = new Deferred; $watcher = Loop::onWritable($socket, [$deferred, 'resolve']); $id = $token->subscribe([$deferred, 'fail']); try { yield Promise\timeout($deferred->promise(), $timeout); } catch (TimeoutException $e) { throw new ConnectException(\sprintf( "Connecting to %s failed: timeout exceeded (%d ms)%s", $uri, $timeout, $failures ? "; previous attempts: ".\implode($failures) : "" ), 110); // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno } finally { Loop::cancel($watcher); $token->unsubscribe($id); } // The following hack looks like the only way to detect connection refused errors with PHP's stream sockets. if (\stream_socket_get_name($socket, true) === false) { \fclose($socket); throw new ConnectException(\sprintf( "Connection to %s refused%s", $uri, $failures ? "; previous attempts: ".\implode($failures) : "" ), 111); // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno } } catch (ConnectException $e) { // Includes only error codes used in this file, as error codes on other OS families might be different. // In fact, this might show a confusing error message on OS families that return 110 or 111 by itself. $knownReasons = [ 110 => "connection timeout", 111 => "connection refused", ]; $code = $e->getCode(); $reason = $knownReasons[$code] ?? ("Error #".$code); if (++$attempt === $socketContext->getMaxAttempts()) { break; } $failures[] = "{$uri} ({$reason})"; continue; // Could not connect to host, try next host in the list. } return new ClientSocket($socket); } // This is reached if either all URIs failed or the maximum number of attempts is reached. throw $e; }); } public function rawConnectAsync(string $uri, CancellationToken $token = null, ClientConnectContext $ctx = null): \Generator { $ctxs = $this->generateContexts(0, $uri, $ctx); if (empty($ctxs)) { throw new Exception("No contexts for raw connection to URI $uri"); } foreach ($ctxs as $ctx) { /* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ try { $ctx->setCancellationToken($token); $result = yield $ctx->getStream(); $this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING); return $result->getSocket(); } catch (\Throwable $e) { if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { throw $e; } $this->API->logger->logger('Connection failed: '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); } catch (\Exception $e) { $this->API->logger->logger('Connection failed: '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); } } throw new \danog\MadelineProto\Exception("Could not connect to URI $uri"); } public function dcConnectAsync($dc_number): \Generator { if (isset($this->sockets[$dc_number]) && !isset($this->sockets[$dc_number]->old)) { return false; } $ctxs = $this->generateContexts($dc_number); if (empty($ctxs)) { return false; } foreach ($ctxs as $ctx) { try { if (isset($this->sockets[$dc_number]->old)) { $this->sockets[$dc_number]->setExtra($this->API); yield $this->sockets[$dc_number]->connect($ctx); } else { $this->sockets[$dc_number] = new Connection(); $this->sockets[$dc_number]->setExtra($this->API); yield $this->sockets[$dc_number]->connect($ctx); } $this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING); return true; } catch (\Throwable $e) { if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { throw $e; } $this->API->logger->logger('Connection failed: '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); } catch (\Exception $e) { $this->API->logger->logger('Connection failed: '.$e->getMessage(), \danog\MadelineProto\Logger::ERROR); } } throw new \danog\MadelineProto\Exception("Could not connect to DC $dc_number"); } public function generateContexts($dc_number = 0, string $uri = '', ClientConnectContext $context = null) { $ctxs = []; $combos = []; $dc_config_number = isset($this->settings[$dc_number]) ? $dc_number : 'all'; $test = $this->settings[$dc_config_number]['test_mode'] ? 'test' : 'main'; $ipv6 = $this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4'; switch ($this->settings[$dc_config_number]['protocol']) { case 'tcp_abridged': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [AbridgedStream::getName(), []]]; break; case 'tcp_intermediate': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [IntermediateStream::getName(), []]]; break; case 'obfuscated2': $this->settings[$dc_config_number]['protocol'] = 'tcp_intermediate_padded'; $this->settings[$dc_config_number]['obfuscated'] = true; case 'tcp_intermediate_padded': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [IntermediatePaddedStream::getName(), []]]; break; case 'tcp_full': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [FullStream::getName(), []]]; break; case 'http': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpStream::getName(), []]]; break; case 'https': $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]]; break; default: throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_invalid']); } if ($this->settings[$dc_config_number]['obfuscated'] && !in_array($default[2][0], [HttpsStream::getName(), HttpStream::getName()])) { $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; } if ($this->settings[$dc_config_number]['transport'] && !in_array($default[2][0], [HttpsStream::getName(), HttpStream::getName()])) { switch ($this->settings[$dc_config_number]['transport']) { case 'tcp': if ($this->settings[$dc_config_number]['obfuscated']) { $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; } break; case 'wss': if ($this->settings[$dc_config_number]['obfuscated']) { $default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; } else { $default = [[DefaultStream::getName(), []], [WssStream::getName(), []], [BufferedRawStream::getName(), []], end($default)]; } break; case 'ws': if ($this->settings[$dc_config_number]['obfuscated']) { $default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)]; } else { $default = [[DefaultStream::getName(), []], [WsStream::getName(), []], [BufferedRawStream::getName(), []], end($default)]; } break; } } if (!$dc_number) { $default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []]]; } $combos[] = $default; if (!isset($this->settings[$dc_config_number]['do_not_retry'])) { if ((isset($this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) && $this->dclist[$test][$ipv6][$dc_number]['tcpo_only']) || isset($this->dclist[$test][$ipv6][$dc_number]['secret'])) { $extra = isset($this->dclist[$test][$ipv6][$dc_number]['secret']) ? ['secret' => $this->dclist[$test][$ipv6][$dc_number]['secret']] : []; $combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), $extra], [IntermediatePaddedStream::getName(), []]]; } if (is_iterable($this->settings[$dc_config_number]['proxy'])) { $proxies = $this->settings[$dc_config_number]['proxy']; $proxy_extras = $this->settings[$dc_config_number]['proxy_extra']; } else { $proxies = [$this->settings[$dc_config_number]['proxy']]; $proxy_extras = [$this->settings[$dc_config_number]['proxy_extra']]; } foreach ($proxies as $key => $proxy) { // Convert old settings if ($proxy === '\\Socket') { $proxy = DefaultStream::getName(); } if ($proxy === '\\SocksProxy') { $proxy = SocksProxy::getName(); } if ($proxy === '\\HttpProxy') { $proxy = HttpProxy::getName(); } if ($proxy === '\\MTProxySocket') { $proxy = ObfuscatedStream::getName(); } if ($proxy === DefaultStream::getName()) { continue; } if (!$dc_number && $proxy === ObfuscatedStream::getName()) { continue; } $extra = $proxy_extras[$key]; if (!isset(class_implements($proxy)['danog\\MadelineProto\\Stream\\StreamInterface'])) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['proxy_class_invalid']); } if ($proxy === ObfuscatedStream::getName() && in_array(strlen($extra['secret']), [17, 34])) { $combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [$proxy, $extra], [IntermediatePaddedStream::getName(), []]]; } foreach ($combos as $k => $orig) { $combo = []; if ($proxy === ObfuscatedStream::getName()) { $combo = $orig; if ($combo[count($combo) - 2][0] === ObfuscatedStream::getName()) { $combo[count($combo) - 2][1] = $extra; } else { $mtproto = end($combo); $combo[count($combo) - 1] = [$proxy, $extra]; $combo[] = $mtproto; } } else { if ($orig[1][0] === BufferedRawStream::getName()) { list($first, $second) = [array_slice($orig, 0, 2), array_slice($orig, 2)]; $first[] = [$proxy, $extra]; $combo = array_merge($first, $second); } elseif (in_array($orig[1][0], [WsStream::getName(), WssStream::getName()])) { list($first, $second) = [array_slice($orig, 0, 1), array_slice($orig, 1)]; $first[] = [BufferedRawStream::getName(), []]; $first[] = [$proxy, $extra]; $combo = array_merge($first, $second); } } array_unshift($combos, $combo); //unset($combos[$k]); } } if ($dc_number) { $combos[] = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]]; } $combos = array_unique($combos, SORT_REGULAR); } /* @var $context \Amp\ClientConnectContext */ $context = $context ?? (new ClientConnectContext())->withMaxAttempts(1)->withConnectTimeout(1000 * $this->settings[$dc_config_number]['timeout']); foreach ($combos as $combo) { $ipv6 = [$this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4', $this->settings[$dc_config_number]['ipv6'] ? 'ipv4' : 'ipv6']; foreach ($ipv6 as $ipv6) { if (!$dc_number) { /** @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ $ctx = (new ConnectionContext()) ->setSocketContext($context) ->setUri($uri) ->setIpv6($ipv6 === 'ipv6'); foreach ($combo as $stream) { if ($stream[0] === DefaultStream::getName() && $stream[1] === []) { $stream[1] = [[$this, 'socketConnect'], [$this, 'cryptoConnect']]; } $ctx->addStream(...$stream); } $ctxs[] = $ctx; continue; } if (!isset($this->dclist[$test][$ipv6][$dc_number]['ip_address'])) { continue; } $address = $this->dclist[$test][$ipv6][$dc_number]['ip_address']; $port = $this->dclist[$test][$ipv6][$dc_number]['port']; foreach (array_unique([$port, 443, 80, 88, 5222]) as $port) { $stream = end($combo)[0]; if ($stream === HttpsStream::getName()) { $subdomain = $this->dclist['ssl_subdomains'][preg_replace('/\D+/', '', $dc_number)]; if (strpos($dc_number, '_media') !== false) { $subdomain .= '-1'; } $path = $this->settings[$dc_config_number]['test_mode'] ? 'apiw_test1' : 'apiw1'; $uri = 'tcp://'.$subdomain.'.web.telegram.org:'.$port.'/'.$path; } elseif ($stream === HttpStream::getName()) { $uri = 'tcp://'.$address.':'.$port.'/api'; } else { $uri = 'tcp://'.$address.':'.$port; } if ($combo[1][0] === WssStream::getName()) { $subdomain = $this->dclist['ssl_subdomains'][preg_replace('/\D+/', '', $dc_number)]; if (strpos($dc_number, '_media') !== false) { $subdomain .= '-1'; } $path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws'; $uri = 'tcp://'.$subdomain.'.'.'web.telegram.org'.':'.$port.'/'.$path; } elseif ($combo[1][0] === WsStream::getName()) { $subdomain = $this->dclist['ssl_subdomains'][preg_replace('/\D+/', '', $dc_number)]; if (strpos($dc_number, '_media') !== false) { $subdomain .= '-1'; } $path = $this->settings[$dc_config_number]['test_mode'] ? 'apiws_test' : 'apiws'; //$uri = 'tcp://' . $subdomain . '.web.telegram.org:' . $port . '/' . $path; $uri = 'tcp://'.$address.':'.$port.'/'.$path; } /** @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ $ctx = (new ConnectionContext()) ->setDc($dc_number) ->setTest($this->settings[$dc_config_number]['test_mode']) ->setSocketContext($context) ->setUri($uri) ->setIpv6($ipv6 === 'ipv6'); foreach ($combo as $stream) { if ($stream[0] === DefaultStream::getName() && $stream[1] === []) { $stream[1] = [[$this, 'socketConnect'], [$this, 'cryptoConnect']]; } $ctx->addStream(...$stream); } $ctxs[] = $ctx; } } } if (isset($this->dclist[$test][$ipv6][$dc_number.'_bk']['ip_address'])) { $ctxs = array_merge($ctxs, $this->generateContexts($dc_number.'_bk')); } if (empty($ctxs)) { unset($this->sockets[$dc_number]); $this->API->logger->logger("No info for DC $dc_number", \danog\MadelineProto\Logger::ERROR); } elseif (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') { return [$ctxs[0]]; } return $ctxs; } /** * Get Artax async HTTP client. * * @return \Amp\Artax\Client */ public function getHTTPClient(): Client { return $this->HTTPClient; } /** * Get DNS over HTTPS async DNS client. * * @return \Amp\Dns\Resolver */ public function getDNSClient(): Resolver { return $this->DoHClient; } public function fileGetContents($url): \Generator { return yield (yield $this->getHTTPClient()->request($url))->getBody(); } public function get_dcs($all = true) { $test = $this->settings['all']['test_mode'] ? 'test' : 'main'; $ipv6 = $this->settings['all']['ipv6'] ? 'ipv6' : 'ipv4'; return $all ? array_keys((array) $this->dclist[$test][$ipv6]) : array_keys((array) $this->sockets); } } bot_thumbnail#0 dc_id:int id:long access_hash:long volume_id:long secret:long local_id:int = File; bot_photo#2 dc_id:int id:long access_hash:long volume_id:long secret:long local_id:int = File; bot_voice#3 dc_id:int id:long access_hash:long = File; bot_video#4 dc_id:int id:long access_hash:long = File; bot_document#5 dc_id:int id:long access_hash:long = File; bot_sticker#8 dc_id:int id:long access_hash:long = File; bot_audio#9 dc_id:int id:long access_hash:long = File; bot_gif#A dc_id:int id:long access_hash:long = File; bot_video_note#D dc_id:int id:long access_hash:long = File; . * * @author Daniil Gentili * @copyright 2016-2019 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\Artax\Request; /** * Wrapper for my.telegram.org. */ class MyTelegramOrgWrapper { use Tools; private $logged = false; private $hash = ''; private $token; private $number; private $creation_hash; private $settings; private $async = true; const MY_TELEGRAM_URL = 'https://my.telegram.org'; public function __sleep() { return ['logged', 'hash', 'token', 'number', 'creation_hash', 'settings', 'async']; } public function __construct($settings = []) { if (!isset($settings['all'])) { $settings['connection_settings'] = ['all' => [ // These settings will be applied on every datacenter that hasn't a custom settings subarray... 'protocol' => Magic::$altervista ? 'http' : 'tcp_abridged', // can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported) 'test_mode' => false, // decides whether to connect to the main telegram servers or to the testing servers (deep telegram) 'ipv6' => \danog\MadelineProto\Magic::$ipv6, // decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean 'timeout' => 2, // timeout for sockets 'proxy' => Magic::$altervista ? '\\HttpProxy' : '\\Socket', // The proxy class to use 'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [], // Extra parameters to pass to the proxy class using setExtra 'obfuscated' => false, 'transport' => 'tcp', 'pfs' => extension_loaded('gmp'), ], ]; } $this->settings = $settings; $this->__wakeup(); } public function __wakeup() { $this->datacenter = new DataCenter( new class($this->settings) { public function __construct($settings) { $this->logger = new Logger( isset($settings['logger']['logger']) ? $settings['logger']['logger'] : php_sapi_name() === 'cli' ? 3 : 2, isset($settings['logger']['logger_param']) ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log', isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE, isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024); } }, [], $this->settings['connection_settings'] ); } public function login_async($number) { $this->number = $number; $request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST'); $request = $request->withBody(http_build_query(['phone' => $number])); $request = $request->withHeaders($this->getHeaders('origin')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody(); $resulta = json_decode($result, true); if (!isset($resulta['random_hash'])) { throw new Exception($result); } $this->hash = $resulta['random_hash']; } public function complete_login_async($password) { if ($this->logged) { throw new Exception('Already logged in!'); } $request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST'); $request = $request->withBody(http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password])); $request = $request->withHeaders($this->getHeaders('origin')); $request = $request->withHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody(); switch ($result) { case 'true': //Logger::log(['Login OK'], Logger::VERBOSE); break; default: throw new Exception($result); } $this->token = explode(';', explode('stel_token=', $response->getHeader('Set-Cookie'))[1])[0]; return $this->logged = true; } public function logged_in_async() { return $this->logged; } public function has_app_async() { if (!$this->logged) { throw new Exception('Not logged in!'); } $request = new Request(self::MY_TELEGRAM_URL.'/apps'); $request = $request->withHeaders($this->getHeaders('refer')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody(); $title = explode('', explode('', $result)[1])[0]; switch ($title) { case 'App configuration':return true; case 'Create new application': $this->creation_hash = explode('"/>', explode('<input type="hidden" name="hash" value="', $result)[1])[0]; return false; } throw new Exception($title); } public function get_app_async() { if (!$this->logged) { throw new Exception('Not logged in!'); } $request = new Request(self::MY_TELEGRAM_URL.'/apps'); $request = $request->withHeaders($this->getHeaders('refer')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody(); $cose = explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label> <div class="col-md-7"> <span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result); $asd = explode('</strong></span>', $cose[1]); $api_id = $asd[0]; $cose = explode('<label for="app_hash" class="col-md-4 text-right control-label">App api_hash:</label> <div class="col-md-7"> <span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result); $asd = explode('</span>', $cose[1]); $api_hash = $asd[0]; return ['api_id' => (int) $api_id, 'api_hash' => $api_hash]; } public function create_app_async($settings) { if (!$this->logged) { throw new Exception('Not logged in!'); } if (yield $this->has_app_async()) { throw new Exception('The app was already created!'); } $request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST'); $request = $request->withHeaders($this->getHeaders('app')); $request = $request->withBody(http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']])); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody(); if ($result) { throw new Exception($result); } $request = new Request(self::MY_TELEGRAM_URL.'/apps'); $request = $request->withHeaders($this->getHeaders('refer')); $response = yield $this->datacenter->getHTTPClient()->request($request); $result = yield $response->getBody(); $title = explode('', explode('', $result)[1])[0]; if ($title === 'Create new application') { $this->creation_hash = explode('"/>', explode('<input type="hidden" name="hash" value="', $result)[1])[0]; throw new \danog\MadelineProto\Exception('App creation failed'); } $cose = explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label> <div class="col-md-7"> <span class="form-control input-xlarge uneditable-input" onclick="this.select();"><strong>', $result); $asd = explode('</strong></span>', $cose['1']); $api_id = $asd['0']; $cose = explode('<label for="app_hash" class="col-md-4 text-right control-label">App api_hash:</label> <div class="col-md-7"> <span class="form-control input-xlarge uneditable-input" onclick="this.select();">', $result); $asd = explode('</span>', $cose['1']); $api_hash = $asd['0']; return ['api_id' => (int) $api_id, 'api_hash' => $api_hash]; } /** * Function for generating curl request headers. */ private function getHeaders($httpType) { // Common header flags. $headers = []; $headers[] = 'Dnt: 1'; $headers[] = 'Connection: keep-alive'; $headers[] = 'Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4'; $headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'; // Add additional headers based on the type of request. switch ($httpType) { case 'origin': $headers[] = 'Origin: '.self::MY_TELEGRAM_URL; //$headers[] = 'Accept-Encoding: gzip, deflate, br'; $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'; $headers[] = 'Accept: application/json, text/javascript, */*; q=0.01'; $headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/auth'; $headers[] = 'X-Requested-With: XMLHttpRequest'; break; case 'refer': //$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br'; $headers[] = 'Upgrade-Insecure-Requests: 1'; $headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; $headers[] = 'Referer: '.self::MY_TELEGRAM_URL; $headers[] = 'Cache-Control: max-age=0'; break; case 'app': $headers[] = 'Origin: '.self::MY_TELEGRAM_URL; //$headers[] = 'Accept-Encoding: gzip, deflate, br'; $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'; $headers[] = 'Accept: */*'; $headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/apps'; $headers[] = 'X-Requested-With: XMLHttpRequest'; break; } $final_headers = []; foreach ($headers as $header) { list($key, $value) = explode(':', $header, 2); $final_headers[trim($key)] = trim($value); } return $final_headers; } public function async($async) { $this->async = $async; } public function __call($name, $arguments) { $name .= '_async'; $async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async; return $async ? $this->{$name}(...$arguments) : $this->wait($this->{$name}(...$arguments)); } } <?php /** * FileCallback module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class FileCallback implements FileCallbackInterface { private $file; private $callback; public function __construct($file, $callback) { $this->file = $file; $this->callback = $callback; } public function getFile() { return $this->file; } public function __invoke($percent) { $callback = $this->callback; return $callback($percent); } } ---types--- ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector<User> = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector<DialogPeer> = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates; photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#3213dbba flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector<DocumentAttribute> = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule; account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector<Document> = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations; account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password; account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password; account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings; account.passwordInputSettings#21ffa60d flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_salt:flags.2?bytes new_secure_secret:flags.2?bytes new_secure_secret_id:flags.2?long = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector<User> = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector<RichText> = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector<RichText> = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector<PageBlock> caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector<PageBlock> caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page; pageFull#556ec7aa blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector<LabeledPrice> = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector<PhoneConnection> start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector<CdnPublicKey> = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vector<User> = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector<WebAuthorization> users:Vector<User> = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector<StickerSetCovered> = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector<Chat> users:Vector<User> = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#b4b4b699 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#67872e8 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#cb976d53 flags:# selfie_required:flags.1?true required_types:Vector<SecureValueType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector<WallPaper>; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector<SecureValue>; account.getSecureValue#73665bc2 types:Vector<SecureValueType> = Vector<SecureValue>; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool; contacts.getStatuses#c4a353ee = Vector<ContactStatus>; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector<int>; contacts.importCard#4fe196fe export_card:Vector<int> = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector<SavedContact>; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector<int> = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#c000e4c8 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#adc3e828 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector<MessageRange>; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector<FileHash>; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector<FileHash>; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<FileHash>; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector<InputStickerSetItem> = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangPackString>; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector<LangPackLanguage>; // Core types (no need to gen) //vector#1cb5c415 {t:Type} # [ t ] = Vector t; /////////////////////////////// /////////////////// Layer cons /////////////////////////////// //invokeAfterMsg#cb9f372d msg_id:long query:!X = X; //invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X; //invokeWithLayer1#53835315 query:!X = X; //invokeWithLayer2#289dd1f6 query:!X = X; //invokeWithLayer3#b7475268 query:!X = X; //invokeWithLayer4#dea0d430 query:!X = X; //invokeWithLayer5#417a57ae query:!X = X; //invokeWithLayer6#3a64d54d query:!X = X; //invokeWithLayer7#a5be56d3 query:!X = X; //invokeWithLayer8#e9abd9fd query:!X = X; //invokeWithLayer9#76715a63 query:!X = X; //invokeWithLayer10#39620c41 query:!X = X; //invokeWithLayer11#a6b88fdf query:!X = X; //invokeWithLayer12#dda60d3c query:!X = X; //invokeWithLayer13#427c8ea2 query:!X = X; //invokeWithLayer14#2b9b08fa query:!X = X; //invokeWithLayer15#b4418b64 query:!X = X; //invokeWithLayer16#cf5f0987 query:!X = X; //invokeWithLayer17#50858a19 query:!X = X; //invokeWithLayer18#1c900537 query:!X = X; //invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer /////////////////////////////// /// Authorization key creation /////////////////////////////// resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; destroy_auth_key#d1435160 = DestroyAuthKeyRes; /////////////////////////////// ////////////// System messages /////////////////////////////// ---types--- msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck; bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq; msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo; msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = MsgsAllInfo; msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq; //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually rpc_error#2144ca19 error_code:int error_message:string = RpcError; rpc_answer_unknown#5e2ad36e = RpcDropAnswer; rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts; pong#347773c5 msg_id:long ping_id:long = Pong; destroy_session_ok#e22045fc session_id:long = DestroySessionRes; destroy_session_none#62d350c9 session_id:long = DestroySessionRes; new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; //message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually //msg_container#73f1f8dc messages:vector<message> = MessageContainer; // parsed manually //msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container //gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; ---functions--- rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; get_future_salts#b921bd04 num:int = FutureSalts; ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; contest.saveDeveloperInfo#9a5f6e95 vk_id:int name:string phone_number:string age:int city:string = Bool; /////////////////////////////// ///////// Main application API /////////////////////////////// ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#630c9af1 flags:# file:InputFile caption:string stickers:flags.0?Vector<InputDocument> = InputMedia; inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#d070f1e9 flags:# file:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> = InputMedia; inputMediaUploadedThumbDocument#50d88cae flags:# file:InputFile thumb:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> = InputMedia; inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia; inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#92153685 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string start_param:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#a14dca52 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat; channelForbidden#8537784f flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull; channelFull#c3d5512f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#c09be45f flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; dialog#66ffba14 flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector<Contact> users:Vector<User> = contacts.Contacts; contacts.importedContacts#ad524315 imported:Vector<ImportedContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector<Peer> = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates; photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#1508485a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true id:int ip_address:string port:int = DcOption; config#cb601684 flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string disabled_features:Vector<DisabledFeature> = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector<DocumentAttribute> = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#1aa1f784 results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule; account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector<User> = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#410dee07 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole; channelRoleEditor#820bfe8c = ChannelParticipantRole; channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#c786ddcb flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector<Document> = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector<RichText> = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector<RichText> = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector<PageBlock> caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector<PageBlock> caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pagePart#8dee6c44 blocks:Vector<PageBlock> photos:Vector<Photo> videos:Vector<Document> = Page; pageFull#d7a19d69 blocks:Vector<PageBlock> photos:Vector<Photo> videos:Vector<Document> = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true currency:string prices:Vector<LabeledPrice> = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector<PhoneConnection> start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector<CdnPublicKey> = CdnConfig; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X; initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector<WallPaper>; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector<ContactStatus>; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector<InputContact> replace:Bool = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector<int>; contacts.importCard#4fe196fe export_card:Vector<int> = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; messages.getMessages#4222fa74 id:Vector<int> = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#d4569248 flags:# peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector<int> = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector<InputPeer> = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector<InputPeer> = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#2e7a2020 file_token:bytes request_token:bytes = Bool; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector<int> = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates; channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; // LAYER 66 <?php /** * PTSException module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class PTSException extends \Exception { use TL\PrettyException; public function __toString() { return get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL; } public function __construct($message, $file = '') { parent::__construct($message); $this->prettify_tl($file); } } <?php /** * FileCallbackInterface module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; interface FileCallbackInterface { public function getFile(); public function __invoke($percent); } ---types--- boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedDocument#e39621fd flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#450b7115 flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull; channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#b5223b0f flags:# photo:flags.0?Photo caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c long:double lat:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector<User> = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update; updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector<Peer> = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#10c2404b = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates; photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector<CdnFileHash> = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; config#9c840964 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector<DisabledFeature> = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; documentEmpty#36f8c871 id:long = Document; document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector<DocumentAttribute> = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#1aa1f784 results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule; account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector<User> = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant; channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs; inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults; exportedMessageLink#1f486803 link:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers; draftMessageEmpty#ba4baec5 = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#5ce20970 hash:int stickers:Vector<Document> = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector<RichText> = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#3a58c7f4 ordered:Bool items:Vector<RichText> = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock; pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock; pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:RichText = PageBlock; pageBlockCollage#8b31c4f items:Vector<PageBlock> caption:RichText = PageBlock; pageBlockSlideshow#130c8963 items:Vector<PageBlock> caption:RichText = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#31b81a7f audio_id:long caption:RichText = PageBlock; pagePart#8e3f9ebe blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page; pageFull#556ec7aa blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector<LabeledPrice> = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> dc_id:int = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#795667a6 payment_token:DataJSON = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector<PhoneConnection> start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector<CdnPublicKey> = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference; langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vector<User> = help.RecentMeUrls; inputSingleMedia#5eaa7809 media:InputMedia random_id:long = InputSingleMedia; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X; initConnection#c7481da6 {X:Type} api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool; account.registerDevice#637ea878 token_type:int token:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector<WallPaper>; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword; users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector<ContactStatus>; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector<int>; contacts.importCard#4fe196fe export_card:Vector<int> = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; messages.getMessages#4222fa74 id:Vector<int> = messages.Messages; messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#39e9ea0 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getChats#3c6aa187 id:Vector<int> = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#5d1b8dd flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Updates; messages.editInlineBotMessage#b0e08243 flags:# no_webpage:flags.1?true stop_geo_live:flags.12?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> geo_point:flags.13?InputGeoPoint = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector<InputPeer> = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool; messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector<InputPeer> = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#249431e2 peer:InputPeer limit:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector<CdnFileHash>; upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector<CdnFileHash>; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#ae2de196 = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.getTermsOfService#350170f3 = help.TermsOfService; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector<int> = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates; channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector<InputStickerSetItem> = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangPackString>; langpack.getDifference#b2e4d7d from_version:int = LangPackDifference; langpack.getLanguages#800fd57d = Vector<LangPackLanguage>; // LAYER 73 <?php /** * Bug74586Exception module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Bug74586Exception extends \Exception { } <?php /** * Serialization module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; /** * Manages serialization of the MadelineProto instance. */ class Serialization { public static function serialize_all($exception) { echo $exception.PHP_EOL; } public static function realpaths($file) { $file = Absolute::absolute($file); return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session']; } } {"constructors":[{"id":"481674261","predicate":"vector","params":[],"type":"Vector t"},{"id":"85337187","predicate":"resPQ","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"pq","type":"bytes"},{"name":"server_public_key_fingerprints","type":"Vector<long>"}],"type":"ResPQ"},{"id":"-2083955988","predicate":"p_q_inner_data","params":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"}],"type":"P_Q_inner_data"},{"id":"1013613780","predicate":"p_q_inner_data_temp","params":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"},{"name":"expires_in","type":"int"}],"type":"P_Q_inner_data"},{"id":"2043348061","predicate":"server_DH_params_fail","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash","type":"int128"}],"type":"Server_DH_Params"},{"id":"-790100132","predicate":"server_DH_params_ok","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_answer","type":"bytes"}],"type":"Server_DH_Params"},{"id":"-1249309254","predicate":"server_DH_inner_data","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"g","type":"int"},{"name":"dh_prime","type":"bytes"},{"name":"g_a","type":"bytes"},{"name":"server_time","type":"int"}],"type":"Server_DH_inner_data"},{"id":"1715713620","predicate":"client_DH_inner_data","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"retry_id","type":"long"},{"name":"g_b","type":"bytes"}],"type":"Client_DH_Inner_Data"},{"id":"1003222836","predicate":"dh_gen_ok","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash1","type":"int128"}],"type":"Set_client_DH_params_answer"},{"id":"1188831161","predicate":"dh_gen_retry","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash2","type":"int128"}],"type":"Set_client_DH_params_answer"},{"id":"-1499615742","predicate":"dh_gen_fail","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash3","type":"int128"}],"type":"Set_client_DH_params_answer"},{"id":"-212046591","predicate":"rpc_result","params":[{"name":"req_msg_id","type":"long"},{"name":"result","type":"Object"}],"type":"RpcResult"},{"id":"558156313","predicate":"rpc_error","params":[{"name":"error_code","type":"int"},{"name":"error_message","type":"string"}],"type":"RpcError"},{"id":"1579864942","predicate":"rpc_answer_unknown","params":[],"type":"RpcDropAnswer"},{"id":"-847714938","predicate":"rpc_answer_dropped_running","params":[],"type":"RpcDropAnswer"},{"id":"-1539647305","predicate":"rpc_answer_dropped","params":[{"name":"msg_id","type":"long"},{"name":"seq_no","type":"int"},{"name":"bytes","type":"int"}],"type":"RpcDropAnswer"},{"id":"155834844","predicate":"future_salt","params":[{"name":"valid_since","type":"int"},{"name":"valid_until","type":"int"},{"name":"salt","type":"long"}],"type":"FutureSalt"},{"id":"-1370486635","predicate":"future_salts","params":[{"name":"req_msg_id","type":"long"},{"name":"now","type":"int"},{"name":"salts","type":"vector<future_salt>"}],"type":"FutureSalts"},{"id":"880243653","predicate":"pong","params":[{"name":"msg_id","type":"long"},{"name":"ping_id","type":"long"}],"type":"Pong"},{"id":"-501201412","predicate":"destroy_session_ok","params":[{"name":"session_id","type":"long"}],"type":"DestroySessionRes"},{"id":"1658015945","predicate":"destroy_session_none","params":[{"name":"session_id","type":"long"}],"type":"DestroySessionRes"},{"id":"-1631450872","predicate":"new_session_created","params":[{"name":"first_msg_id","type":"long"},{"name":"unique_id","type":"long"},{"name":"server_salt","type":"long"}],"type":"NewSession"},{"id":"1945237724","predicate":"msg_container","params":[{"name":"messages","type":"vector<%Message>"}],"type":"MessageContainer"},{"id":"1538843921","predicate":"message","params":[{"name":"msg_id","type":"long"},{"name":"seqno","type":"int"},{"name":"bytes","type":"int"},{"name":"body","type":"Object"}],"type":"Message"},{"id":"-530561358","predicate":"msg_copy","params":[{"name":"orig_message","type":"Message"}],"type":"MessageCopy"},{"id":"812830625","predicate":"gzip_packed","params":[{"name":"packed_data","type":"bytes"}],"type":"Object"},{"id":"1658238041","predicate":"msgs_ack","params":[{"name":"msg_ids","type":"Vector<long>"}],"type":"MsgsAck"},{"id":"-1477445615","predicate":"bad_msg_notification","params":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"}],"type":"BadMsgNotification"},{"id":"-307542917","predicate":"bad_server_salt","params":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"},{"name":"new_server_salt","type":"long"}],"type":"BadMsgNotification"},{"id":"2105940488","predicate":"msg_resend_req","params":[{"name":"msg_ids","type":"Vector<long>"}],"type":"MsgResendReq"},{"id":"-630588590","predicate":"msgs_state_req","params":[{"name":"msg_ids","type":"Vector<long>"}],"type":"MsgsStateReq"},{"id":"81704317","predicate":"msgs_state_info","params":[{"name":"req_msg_id","type":"long"},{"name":"info","type":"bytes"}],"type":"MsgsStateInfo"},{"id":"-1933520591","predicate":"msgs_all_info","params":[{"name":"msg_ids","type":"Vector<long>"},{"name":"info","type":"bytes"}],"type":"MsgsAllInfo"},{"id":"661470918","predicate":"msg_detailed_info","params":[{"name":"msg_id","type":"long"},{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}],"type":"MsgDetailedInfo"},{"id":"-2137147681","predicate":"msg_new_detailed_info","params":[{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}],"type":"MsgDetailedInfo"},{"id":"1973679973","predicate":"bind_auth_key_inner","params":[{"name":"nonce","type":"long"},{"name":"temp_auth_key_id","type":"long"},{"name":"perm_auth_key_id","type":"long"},{"name":"temp_session_id","type":"long"},{"name":"expires_at","type":"int"}],"type":"BindAuthKeyInner"}],"methods":[{"id":"1615239032","method":"req_pq","params":[{"name":"nonce","type":"int128"}],"type":"ResPQ"},{"id":"-1099002127","method":"req_pq_multi","params":[{"name":"nonce","type":"int128"}],"type":"ResPQ"},{"id":"-686627650","method":"req_DH_params","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"public_key_fingerprint","type":"long"},{"name":"encrypted_data","type":"bytes"}],"type":"Server_DH_Params"},{"id":"-184262881","method":"set_client_DH_params","params":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_data","type":"bytes"}],"type":"Set_client_DH_params_answer"},{"id":"1491380032","method":"rpc_drop_answer","params":[{"name":"req_msg_id","type":"long"}],"type":"RpcDropAnswer"},{"id":"-1188971260","method":"get_future_salts","params":[{"name":"num","type":"int"}],"type":"FutureSalts"},{"id":"2059302892","method":"ping","params":[{"name":"ping_id","type":"long"}],"type":"Pong"},{"id":"-213746804","method":"ping_delay_disconnect","params":[{"name":"ping_id","type":"long"},{"name":"disconnect_delay","type":"int"}],"type":"Pong"},{"id":"-414113498","method":"destroy_session","params":[{"name":"session_id","type":"long"}],"type":"DestroySessionRes"},{"id":"-1835453025","method":"http_wait","params":[{"name":"max_delay","type":"int"},{"name":"wait_after","type":"int"},{"name":"max_wait","type":"int"}],"type":"HttpWait"}]} <?php /** * AnnotationsBuilder module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use phpDocumentor\Reflection\DocBlockFactory; class AnnotationsBuilder { use \danog\MadelineProto\TL\TL; use Tools; public function __construct($logger, $settings) { $this->logger = $logger; $this->construct_TL($settings['tl_schema']); $this->settings = $settings; } public function mk_annotations() { \danog\MadelineProto\Logger::log('Generating annotations...', \danog\MadelineProto\Logger::NOTICE); $this->setProperties(); $this->createInternalClasses(); } /** * Open file of class APIFactory * Insert properties * save the file with new content. */ private function setProperties() { \danog\MadelineProto\Logger::log('Generating properties...', \danog\MadelineProto\Logger::NOTICE); $fixture = DocBlockFactory::createInstance(); $class = new \ReflectionClass(APIFactory::class); $content = file_get_contents($filename = $class->getFileName()); foreach ($class->getProperties() as $property) { if ($raw_docblock = $property->getDocComment()) { $docblock = $fixture->create($raw_docblock); if ($docblock->hasTag('internal')) { $content = str_replace("\n ".$raw_docblock."\n public \$".$property->getName().';', '', $content); } } } foreach ($this->get_method_namespaces() as $namespace) { $content = preg_replace('/(class( \\w+[,]?){0,}\\n{\\n)/', '${1}'." /**\n"." * @internal this is a internal property generated by build_docs.php, don't change manually\n"." *\n"." * @var {$namespace}\n"." */\n"." public \${$namespace};\n", $content); } file_put_contents($filename, $content); } /** * Create file InternalDoc with all interfaces. */ private function createInternalClasses() { \danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE); $handle = fopen(dirname(__FILE__).'/InternalDoc.php', 'w'); foreach ($this->methods->by_id as $id => $data) { if (!strpos($data['method'], '.')) { continue; } list($namespace, $method) = explode('.', $data['method']); if (!in_array($namespace, $this->get_method_namespaces())) { continue; } $type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']); foreach ($data['params'] as $param) { if (in_array($param['name'], ['flags', 'random_id'])) { continue; } $stype = 'type'; if (isset($param['subtype'])) { $stype = 'subtype'; } $ptype = str_replace('.', '_', $param[$stype]); switch ($ptype) { case 'true': case 'false': $ptype = 'boolean'; } $internalDoc[$namespace][$method]['attr'][$param['name']] = $ptype; } if ($type === 'Bool') { $type = strtolower($type); } $internalDoc[$namespace][$method]['return'] = $type; } fwrite($handle, "<?php\n"); fwrite($handle, "/**\n"); fwrite($handle, " * This file is automatic generated by build_docs.php file\n"); fwrite($handle, " * and is used only for autocomplete in multiple IDE\n"); fwrite($handle, " * don't modify manually.\n"); fwrite($handle, " */\n\n"); fwrite($handle, "namespace danog\\MadelineProto;\n"); foreach ($internalDoc as $namespace => $methods) { fwrite($handle, "\ninterface {$namespace}\n{"); foreach ($methods as $method => $properties) { fwrite($handle, "\n /**\n"); if (isset($properties['attr'])) { fwrite($handle, " * @param array params [\n"); foreach ($properties['attr'] as $name => $type) { fwrite($handle, " * {$type} {$name},\n"); } fwrite($handle, " * ]\n"); fwrite($handle, " *\n"); } fwrite($handle, " * @return {$properties['return']}\n"); fwrite($handle, " */\n"); fwrite($handle, " public function {$method}("); if (isset($properties['attr'])) { fwrite($handle, 'array $params'); } fwrite($handle, ");\n"); } fwrite($handle, "}\n"); } fclose($handle); } } <?php /** * Exception module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Exception extends \Exception { use TL\PrettyException; public static $rollbar = true; public function __toString() { return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.$this->getTLTrace(); } public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null) { if (is_array($message) && $message[0] === 'extension') { if ($message[1] === 'libtgvoip') { $additional = 'Follow the instructions @ https://voip.madelineproto.xyz to install it.'; } elseif ($message[1] === 'prime') { $additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.'; } else { $additional = 'Try running sudo apt-get install php'.PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION.'-'.$message[1].'.'; } $message = 'MadelineProto requires the '.$message[1].' extension to run. '.$additional; if (php_sapi_name() !== 'cli') { echo $message.'<br>'; } $file = 'MadelineProto'; $line = 1; } $this->prettify_tl(); if ($file !== null) { if (basename($file) === 'Threaded.php') { $line = debug_backtrace(0)[2]['line']; $file = debug_backtrace(0)[2]['file']; } $this->file = $file; } if ($line !== null) { $this->line = $line; } parent::__construct($message, $code, $previous); if (strpos($message, 'socket_accept') === false) { \danog\MadelineProto\Logger::log($message.' in '.basename($this->file).':'.$this->line, \danog\MadelineProto\Logger::FATAL_ERROR); } if (in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) { return; } if (strpos($message, 'pg_query') !== false || strpos($message, 'Undefined variable: ') !== false || strpos($message, 'socket_write') !== false || strpos($message, 'socket_read') !== false || strpos($message, 'Received request to switch to DC ') !== false || strpos($message, "Couldn't get response") !== false || strpos($message, 'Re-executing query...') !== false || strpos($message, "Couldn't find peer by provided") !== false || strpos($message, 'id.pwrtelegram.xyz') !== false || strpos($message, 'Please update ') !== false || strpos($message, 'posix_isatty') !== false) { return; } if (self::$rollbar && class_exists('\\Rollbar\\Rollbar')) { \Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, debug_backtrace(0)); } } /** * ExceptionErrorHandler. * * Error handler */ public static function ExceptionErrorHandler($errno = 0, $errstr = null, $errfile = null, $errline = null) { // If error is suppressed with @, don't throw an exception if (error_reporting() === 0 || strpos($errstr, 'headers already sent') || ($errfile && strpos($errfile, 'vendor/amphp') !== false)) { return false; } throw new self($errstr, $errno, null, $errfile, $errline); } /** * ExceptionErrorHandler. * * Error handler */ public static function ExceptionHandler($exception) { Logger::log($exception, Logger::FATAL_ERROR); } } { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "-515910468", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1761896484", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1821749571", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1855757255", "predicate": "chat", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "left", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-83047359", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "date", "type": "int" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector<BotInfo>" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "265468810", "predicate": "chatParticipantsForbidden", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector<ChatParticipant>" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-1023016155", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" } ], "type": "Message" }, { "id": "495384334", "predicate": "messageService", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1540298357", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector<int>" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1042448310", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector<PhotoSize>" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "-148338733", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector<PhotoSize>" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1518971995", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "bot_info", "type": "BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "909233996", "predicate": "chatLocated", "params": [ { "name": "chat_id", "type": "int" }, { "name": "distance", "type": "int" } ], "type": "ChatLocated" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector<Contact>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector<ImportedContact>" }, { "name": "retry_contacts", "type": "Vector<long>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector<ContactBlocked>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector<ContactBlocked>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector<ContactSuggested>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "1062078024", "predicate": "messages.messageEmpty", "params": [], "type": "messages.Message" }, { "id": "1279084531", "predicate": "messages.sentMessage", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "MessageMedia" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector<Chat>" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector<Message>" }, { "name": "new_encrypted_messages", "type": "Vector<EncryptedMessage>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector<Message>" }, { "name": "new_encrypted_messages", "type": "Vector<EncryptedMessage>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-312729305", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" } ], "type": "Updates" }, { "id": "1378061116", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from_id", "type": "flags.2?int" }, { "name": "fwd_date", "type": "flags.2?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector<Update>" }, { "name": "users", "type": "Vector<User>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector<Update>" }, { "name": "users", "type": "Vector<User>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector<Photo>" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector<Photo>" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "1311946900", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector<DcOption>" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "disabled_features", "type": "Vector<DisabledFeature>" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "899786339", "predicate": "messages.sentMessageLink", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "MessageMedia" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "links", "type": "Vector<contacts.Link>" }, { "name": "seq", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "1960072954", "predicate": "inputGeoChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputGeoChat" }, { "id": "1301143240", "predicate": "inputNotifyGeoChatPeer", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "InputNotifyPeer" }, { "id": "1978329690", "predicate": "geoChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "venue", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "checked_in", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "1613830811", "predicate": "geoChatMessageEmpty", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" } ], "type": "GeoChatMessage" }, { "id": "1158019297", "predicate": "geoChatMessage", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "GeoChatMessage" }, { "id": "-749755826", "predicate": "geoChatMessageService", "params": [ { "name": "chat_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "GeoChatMessage" }, { "id": "397498251", "predicate": "geochats.statedMessage", "params": [ { "name": "message", "type": "GeoChatMessage" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "seq", "type": "int" } ], "type": "geochats.StatedMessage" }, { "id": "1224651367", "predicate": "geochats.located", "params": [ { "name": "results", "type": "Vector<ChatLocated>" }, { "name": "messages", "type": "Vector<GeoChatMessage>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "geochats.Located" }, { "id": "-783127119", "predicate": "geochats.messages", "params": [ { "name": "messages", "type": "Vector<GeoChatMessage>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "geochats.Messages" }, { "id": "-1135057944", "predicate": "geochats.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector<GeoChatMessage>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "geochats.Messages" }, { "id": "1862504124", "predicate": "messageActionGeoChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "address", "type": "string" } ], "type": "MessageAction" }, { "id": "209540062", "predicate": "messageActionGeoChatCheckin", "params": [], "type": "MessageAction" }, { "id": "1516823543", "predicate": "updateNewGeoChatMessage", "params": [ { "name": "message", "type": "GeoChatMessage" } ], "type": "Update" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "974056226", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector<DcOption>" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "-1610888", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector<DocumentAttribute>" } ], "type": "InputMedia" }, { "id": "1095242886", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector<DocumentAttribute>" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-102543275", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector<DocumentAttribute>" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "-360210539", "predicate": "contactFound", "params": [ { "name": "user_id", "type": "int" } ], "type": "ContactFound" }, { "id": "90570766", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector<ContactFound>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector<PrivacyRule>" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector<InputUser>" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector<InputUser>" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector<int>" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector<int>" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector<PrivacyRule>" }, { "name": "users", "type": "Vector<User>" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "-1527411636", "predicate": "account.sentChangePhoneCode", "params": [ { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" } ], "type": "account.SentChangePhoneCode" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-556656416", "predicate": "documentAttributeAudio", "params": [ { "name": "duration", "type": "int" }, { "name": "title", "type": "string" }, { "name": "performer", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector<Document>" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector<long>" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-719474725", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "string" }, { "name": "sets", "type": "Vector<StickerSet>" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "751004017", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-1558273867", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector<Authorization>" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-1124314324", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-829325875", "predicate": "chatInvite", "params": [ { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector<StickerPack>" }, { "name": "documents", "type": "Vector<Document>" } ], "type": "messages.StickerSet" }, { "id": "585404530", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1154598962", "predicate": "botInfoEmpty", "params": [], "type": "BotInfo" }, { "id": "164583517", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" }, { "name": "share_text", "type": "string" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector<BotCommand>" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector<KeyboardButton>" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "rows", "type": "Vector<KeyboardButtonRow>" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector<long>" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector<string>" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector<WallPaper>" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector<InputUser>" } ], "type": "Vector<User>" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector<ContactStatus>" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector<InputContact>" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector<InputUser>" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector<int>" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector<int>" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.Messages" }, { "id": "-321970698", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1834885329", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "132772523", "method": "messages.search", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-1336990448", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector<ReceivedNotifyMessage>" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-61479243", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "messages.SentMessage" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1440838285", "method": "messages.forwardMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector<int>" }, { "name": "random_id", "type": "Vector<long>" } ], "type": "Updates" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector<InputUser>" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector<InputPhoto>" } ], "type": "Vector<long>" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector<InputAppEvent>" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector<InputUser>" }, { "name": "random_id", "type": "Vector<long>" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "2132356495", "method": "geochats.getLocated", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "radius", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Located" }, { "id": "-515735953", "method": "geochats.getRecents", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "1437853947", "method": "geochats.checkin", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "geochats.StatedMessage" }, { "id": "1730338159", "method": "geochats.getFullChat", "params": [ { "name": "peer", "type": "InputGeoChat" } ], "type": "messages.ChatFull" }, { "id": "1284383347", "method": "geochats.editChatTitle", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" } ], "type": "geochats.StatedMessage" }, { "id": "903355029", "method": "geochats.editChatPhoto", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "geochats.StatedMessage" }, { "id": "-808598451", "method": "geochats.search", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "-1254131096", "method": "geochats.getHistory", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "geochats.Messages" }, { "id": "146319145", "method": "geochats.setTyping", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "102432836", "method": "geochats.sendMessage", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "geochats.StatedMessage" }, { "id": "-1192173825", "method": "geochats.sendMedia", "params": [ { "name": "peer", "type": "InputGeoChat" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "geochats.StatedMessage" }, { "id": "235482646", "method": "geochats.createGeoChat", "params": [ { "name": "title", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "address", "type": "string" }, { "name": "venue", "type": "string" } ], "type": "geochats.StatedMessage" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector<long>" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector<InputPrivacyRule>" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "200282908", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "-1543001868", "method": "account.sendChangePhoneCode", "params": [ { "name": "phone_number", "type": "string" } ], "type": "account.SentChangePhoneCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "-1438922648", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "string" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "457052156", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "chat_id", "type": "int" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "1537966002", "method": "help.getAppChangelog", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppChangelog" } ] }<?php /** * CombinedAPI module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; use Amp\Loop; use function Amp\Promise\all; class CombinedAPI { use \danog\Serializable; use Tools; public $session; public $instance_paths = []; public $instances = []; public $timeout = 5; public $serialization_interval = 30; public $serialized = 0; protected $async; public function __magic_construct($session, $paths = []) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); \danog\MadelineProto\Magic::class_exists(); $realpaths = Serialization::realpaths($session); $this->session = $realpaths['file']; foreach ($paths as $path => $settings) { $this->addInstance($path, $settings); } if (file_exists($realpaths['file'])) { if (!file_exists($realpaths['lockfile'])) { touch($realpaths['lockfile']); clearstatcache(); } $realpaths['lockfile'] = fopen($realpaths['lockfile'], 'r'); \danog\MadelineProto\Logger::log('Waiting for shared lock of serialization lockfile...'); flock($realpaths['lockfile'], LOCK_SH); \danog\MadelineProto\Logger::log('Shared lock acquired, deserializing...'); try { $tounserialize = file_get_contents($realpaths['file']); } finally { flock($realpaths['lockfile'], LOCK_UN); fclose($realpaths['lockfile']); } $deserialized = unserialize($tounserialize); /*foreach ($deserialized['instance_paths'] as $path) { $this->addInstance($path, isset($paths[$path]) ? $paths[$path] : []); }*/ $this->event_handler = $deserialized['event_handler']; $this->event_handler_instance = $deserialized['event_handler_instance']; if ($this->event_handler !== null) { $this->setEventHandler($this->event_handler); } } foreach ($paths as $path => $settings) { $this->addInstance($path, $settings); } } public function addInstance($path, $settings = []) { if (isset($this->instances[$path]) && isset($this->instance_paths[$path])) { if (isset($this->event_handler_instance)) { $this->event_handler_instance->referenceInstance($path); } return; } \danog\MadelineProto\Logger::constructor(3); \danog\MadelineProto\Logger::log("INSTANTIATING $path..."); $instance = new \danog\MadelineProto\API($path, $settings); $this->instance_paths[$path] = $path; $this->instances[$path] = $instance; if (isset($this->event_handler_instance)) { $this->event_handler_instance->referenceInstance($path); } } public function removeInstance($path) { if (isset($this->instance_paths[$path])) { unset($this->instance_paths[$path]); } if (isset($this->instances[$path])) { unset($this->instances[$path]); } if (isset($this->event_handler_instance)) { $this->event_handler_instance->removeInstance($path); } } public function __destruct() { if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()) || Magic::is_fork()) { return; } $this->serialize(); } public function serialize($filename = '') { /*foreach ($this->instances as $instance) { $instance->serialize(); }*/ if (is_null($this->session)) { return; } if ($filename === '') { $filename = $this->session; } Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']); $realpaths = Serialization::realpaths($filename); if (!file_exists($realpaths['lockfile'])) { touch($realpaths['lockfile']); clearstatcache(); } $realpaths['lockfile'] = fopen($realpaths['lockfile'], 'w'); \danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...'); flock($realpaths['lockfile'], LOCK_EX); \danog\MadelineProto\Logger::log('Lock acquired, serializing'); try { $wrote = file_put_contents($realpaths['tempfile'], serialize(['event_handler' => $this->event_handler, 'event_handler_instance' => $this->event_handler_instance, 'instance_paths' => $this->instance_paths])); rename($realpaths['tempfile'], $realpaths['file']); } finally { flock($realpaths['lockfile'], LOCK_UN); fclose($realpaths['lockfile']); } $this->serialized = time(); return $wrote; } public $event_handler; private $event_handler_instance; private $event_handler_methods = []; public function setEventHandler($event_handler) { if (!class_exists($event_handler) || !is_subclass_of($event_handler, '\danog\MadelineProto\CombinedEventHandler')) { throw new \danog\MadelineProto\Exception('Wrong event handler was defined'); } $this->event_handler = $event_handler; if (!($this->event_handler_instance instanceof $this->event_handler)) { $class_name = $this->event_handler; $this->event_handler_instance = new $class_name($this); } else { $this->event_handler_instance->__construct($this); } $this->event_handler_methods = []; foreach (\get_class_methods($this->event_handler) as $method) { if ($method === 'onLoop') { $this->loop_callback = [$this->event_handler_instance, 'onLoop']; } elseif ($method === 'onAny') { foreach (end($this->instances)->API->constructors->by_id as $constructor) { if ($constructor['type'] === 'Update' && !isset($this->event_handler_methods[$constructor['predicate']])) { $this->event_handler_methods[$constructor['predicate']] = [$this->event_handler_instance, 'onAny']; } } } else { $method_name = lcfirst(substr($method, 2)); $this->event_handler_methods[$method_name] = [$this->event_handler_instance, $method]; } } } public function event_update_handler($update, $instance) { if (isset($this->event_handler_methods[$update['_']])) { return $this->event_handler_methods[$update['_']]($update, $instance); } } private $loop_callback; public function async($async) { $this->async = $async; foreach ($this->instances as $instance) { $instance->async($async); } } public function setLoopCallback($callback) { $this->loop_callback = $callback; } public function get_updates($params = []) { } public function loop($max_forks = 0) { if (is_callable($max_forks)) { return $this->wait($max_forks()); } $loops = []; foreach ($this->instances as $path => $instance) { $this->wait($instance->initAsync()); if ($instance->API->authorized !== MTProto::LOGGED_IN) { continue; } if (!$instance->API->settings['updates']['handle_updates']) { $instance->API->settings['updates']['handle_updates'] = true; $instance->API->startUpdateSystem(); } $instance->setCallback(function ($update) use ($path) { return $this->event_update_handler($update, $path); }, ['async' => false]); if ($this->loop_callback !== null) { $instance->setLoopCallback($this->loop_callback, ['async' => false]); } $loops[] = $this->call($instance->loop(0, ['async' => true])); } Loop::repeat($this->serialization_interval * 1000, function () { \danog\MadelineProto\Logger::log('Serializing combined event handler'); $this->serialize(); }); \danog\MadelineProto\Logger::log('Started update loop', \danog\MadelineProto\Logger::NOTICE); $this->wait(all($loops)); } } ---types--- help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple; ipPort#d433ad73 ipv4:int port:int = IpPort; ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia; inputMediaPoll#6b3765b poll:Poll = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; userEmpty#200250ba id:int = User; user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#22a235da flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull; channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia; messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction; messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; photoEmpty#2331b22d id:long = Photo; photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> dc_id:int = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#38faab5f flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int terms_of_service:flags.3?help.TermsOfService = auth.SentCode; auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonChildAbuse#adf44ee3 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector<User> = contacts.Contacts; contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked; messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats; messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; inputMessagesFilterVoice#50f5c392 = MessagesFilter; inputMessagesFilterMusic#3751b49e = MessagesFilter; inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; inputMessagesFilterGeo#e7026d0d = MessagesFilter; inputMessagesFilterContacts#e062db83 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update; updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector<DialogPeer> = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update; updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference; updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates; photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File; dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#1da7158f flags:# popup:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; documentEmpty#36f8c871 id:long = Document; document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyBroadcasts#d612e8ef = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; sendMessageRecordRoundAction#88f27fbc = SendMessageAction; sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; privacyKeyForwards#69ec56a3 = PrivacyKey; privacyKeyProfilePhoto#96151fed = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule; account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#e4599bbd hash:int stickers:Vector<Document> = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage; webPageNotModified#85849473 = WebPage; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations; account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup; replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity; inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant; channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs; inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults; exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs; topPeer#edcdc05b peer:Peer rating:double = TopPeer; topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; topPeerCategoryBotsInline#148677e2 = TopPeerCategory; topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers; contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers; contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage; messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers; messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers; messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers; messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult; stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered; maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; inputGameID#32c3e77 id:long access_hash:long = InputGame; inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; highScore#58fffcd0 pos:int user_id:int score:int = HighScore; messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores; textEmpty#dc3d824f = RichText; textPlain#744694e0 text:string = RichText; textBold#6724abc4 text:RichText = RichText; textItalic#d912a59c text:RichText = RichText; textUnderline#c12622c4 text:RichText = RichText; textStrike#9bf8bb95 text:RichText = RichText; textFixed#6c3f19b9 text:RichText = RichText; textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; textEmail#de5a0dd6 text:RichText email:string = RichText; textConcat#7e6260d7 texts:Vector<RichText> = RichText; textSubscript#ed6a8504 text:RichText = RichText; textSuperscript#c7fb5e01 text:RichText = RichText; textMarked#34b8621 text:RichText = RichText; textPhone#1ccb966a text:RichText phone:string = RichText; textImage#81ccf4f document_id:long w:int h:int = RichText; textAnchor#35553762 text:RichText name:string = RichText; pageBlockUnsupported#13567e8a = PageBlock; pageBlockTitle#70abc3fd text:RichText = PageBlock; pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; pageBlockHeader#bfd064ec text:RichText = PageBlock; pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; pageBlockParagraph#467a0766 text:RichText = PageBlock; pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; pageBlockFooter#48870999 text:RichText = PageBlock; pageBlockDivider#db20b188 = PageBlock; pageBlockAnchor#ce0d37b0 name:string = PageBlock; pageBlockList#e4e88011 items:Vector<PageListItem> = PageBlock; pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; pageBlockCover#39f23300 cover:PageBlock = PageBlock; pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:PageCaption = PageBlock; pageBlockCollage#65a0fa4d items:Vector<PageBlock> caption:PageCaption = PageBlock; pageBlockSlideshow#31f9590 items:Vector<PageBlock> caption:PageCaption = PageBlock; pageBlockChannel#ef1751b5 channel:Chat = PageBlock; pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; pageBlockKicker#1e148390 text:RichText = PageBlock; pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector<PageTableRow> = PageBlock; pageBlockOrderedList#9a8ae1e1 items:Vector<PageListOrderedItem> = PageBlock; pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector<PageBlock> title:RichText = PageBlock; pageBlockRelatedArticles#16115a96 title:RichText articles:Vector<PageRelatedArticle> = PageBlock; pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector<LabeledPrice> = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument; webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument; inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = payments.PaymentForm; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo; payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; payments.paymentVerficationNeeded#6b56b921 url:string = payments.PaymentResult; payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt; payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials; account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption; inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem; inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall; phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol; phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall; upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; cdnConfig#5725e40a public_keys:Vector<CdnPublicKey> = CdnConfig; langPackString#cad181f6 key:string value:string = LangPackString; langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; langPackStringDeleted#2979eeb2 key:string = LangPackString; langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference; langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter; popularContact#5ce14175 client_id:long importers:int = PopularContact; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers; recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl; recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl; recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vector<User> = help.RecentMeUrls; inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia; webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; account.webAuthorizations#ed56c9fc authorizations:Vector<WebAuthorization> users:Vector<User> = account.WebAuthorizations; inputMessageID#a676a322 id:int = InputMessage; inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector<StickerSetCovered> = messages.FoundStickerSets; fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; inputClientProxy#75588b3f address:string port:int = InputClientProxy; help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData; help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector<Chat> users:Vector<User> = help.ProxyData; help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; secureFileEmpty#64199744 = SecureFile; secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; securePlainPhone#7d6099dd phone:string = SecurePlainData; securePlainEmail#21ec5a5f email:string = SecurePlainData; secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; secureValueTypePassportRegistration#99e3806a = SecureValueType; secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector<SecureFile> files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector<InputSecureFile> files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError; secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; account.authorizationForm#ad2e1cd8 flags:# required_types:Vector<SecureRequiredType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm; account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo; savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; account.takeout#4dba4501 id:long = account.Takeout; passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequiredType; help.passportConfigNotModified#bfb9f457 = help.PassportConfig; help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; jsonNull#3f6d7b68 = JSONValue; jsonBool#c7345e6a value:Bool = JSONValue; jsonNumber#2be0dfa4 value:double = JSONValue; jsonString#b71e767a value:string = JSONValue; jsonArray#f7444763 value:Vector<JSONValue> = JSONValue; jsonObject#99c1d49d value:Vector<JSONObjectValue> = JSONValue; pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; pageTableRow#e0c0c5e5 cells:Vector<PageTableCell> = PageTableRow; pageCaption#6f747657 text:RichText credit:RichText = PageCaption; pageListItemText#b92fb6cd text:RichText = PageListItem; pageListItemBlocks#25e073fc blocks:Vector<PageBlock> = PageListItem; pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = PageListOrderedItem; pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page; help.supportName#8c05f1c9 name:string = help.SupportName; help.userInfoEmpty#f3ae2eed = help.UserInfo; help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo; pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer; poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector<PollAnswer> = Poll; pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters; pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int = PollResults; chatOnlines#f041e250 onlines:int = ChatOnlines; statsURL#47a971e0 url:string = StatsURL; chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights; chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights; inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; inputWallPaperSlug#72091c80 slug:string = InputWallPaper; account.wallPapersNotModified#1c199183 = account.WallPapers; account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers; codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings; wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings; autoDownloadSettings#d246fd47 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int = AutoDownloadSettings; account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword; emojiKeywordDeleted#236df622 keyword:string emoticons:Vector<string> = EmojiKeyword; emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector<EmojiKeyword> = EmojiKeywordsDifference; emojiURL#a575739d url:string = EmojiURL; emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X; initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode; auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool; account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#aabb1763 hash:int = account.WallPapers; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; account.getAllSecureValues#b288bc7d = Vector<SecureValue>; account.getSecureValue#73665bc2 types:Vector<SecureValueType> = Vector<SecureValue>; account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool; account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout; account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; account.confirmPasswordEmail#8fdf1920 code:string = Bool; account.resendPasswordEmail#7a7f2a15 = Bool; account.cancelPasswordEmail#c1cbd5b6 = Bool; account.getContactSignUpNotification#9f07c728 = Bool; account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates; account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; account.resetWallPapers#bb3b9804 = Bool; account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>; users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool; contacts.getContactIDs#2caa4a42 hash:int = Vector<int>; contacts.getStatuses#c4a353ee = Vector<ContactStatus>; contacts.getContacts#c023849f hash:int = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool; contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector<SavedContact>; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages; messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector<int> = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages; messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia; messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#d116f31e flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool; messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool; messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats; messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool; messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates; messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers; messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages; messages.sendMultiMedia#2095512f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> = Updates; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector<MessageRange>; messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>; messages.clearAllDrafts#7e58ee9c = Bool; messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates; messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates; messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL; messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector<FileHash>; upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector<FileHash>; upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<FileHash>; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#522d5a7d source:string = help.AppUpdate; help.getInviteText#4d392343 = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#9010ef6f prev_app_version:string = Updates; help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; help.getCdnConfig#52029342 = CdnConfig; help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; help.getProxyData#3d7758e1 = help.ProxyData; help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; help.getAppConfig#98914110 = JSONValue; help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool; help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; help.getSupportName#d360e72c = help.SupportName; help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<MessageEntity> = help.UserInfo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool; channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm; payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult; payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector<InputStickerSetItem> = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; phone.getCallConfig#55451fa9 = DataJSON; phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>; langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; // LAYER 98 { "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "-139464256", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-373312269", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "-652419756", "predicate": "chat", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "admins_enabled", "type": "flags.3?true" }, { "name": "admin", "type": "flags.4?true" }, { "name": "deactivated", "type": "flags.5?true" }, { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "migrated_to", "type": "flags.6?InputChannel" } ], "type": "Chat" }, { "id": "120753115", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "771925524", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector<BotInfo>" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-57668565", "predicate": "chatParticipantsForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "chat_id", "type": "int" }, { "name": "self_participant", "type": "flags.0?ChatParticipant" } ], "type": "ChatParticipants" }, { "id": "1061556205", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "participants", "type": "Vector<ChatParticipant>" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "-1063525281", "predicate": "message", "params": [ { "name": "flags", "type": "#" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "post", "type": "flags.14?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "fwd_from", "type": "flags.2?MessageFwdHeader" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "reply_markup", "type": "flags.6?ReplyMarkup" }, { "name": "entities", "type": "flags.7?Vector<MessageEntity>" }, { "name": "views", "type": "flags.10?int" }, { "name": "edit_date", "type": "flags.15?int" } ], "type": "Message" }, { "id": "-1642487306", "predicate": "messageService", "params": [ { "name": "flags", "type": "#" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "post", "type": "flags.14?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "flags.8?int" }, { "name": "to_id", "type": "Peer" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "1032643901", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "-1618676578", "predicate": "messageMediaUnsupported", "params": [], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector<int>" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1217033015", "predicate": "messageActionChatAddUser", "params": [ { "name": "users", "type": "Vector<int>" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1728035348", "predicate": "dialog", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "read_outbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "pts", "type": "flags.0?int" }, { "name": "draft", "type": "flags.1?DraftMessage" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "-840088834", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "sizes", "type": "Vector<PhotoSize>" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-2128698738", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "1577067778", "predicate": "auth.sentCode", "params": [ { "name": "flags", "type": "#" }, { "name": "phone_registered", "type": "flags.0?true" }, { "name": "type", "type": "auth.SentCodeType" }, { "name": "phone_code_hash", "type": "string" }, { "name": "next_type", "type": "flags.1?auth.CodeType" }, { "name": "timeout", "type": "flags.2?int" } ], "type": "auth.SentCode" }, { "id": "-16553231", "predicate": "auth.authorization", "params": [ { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "949182130", "predicate": "inputPeerNotifySettings", "params": [ { "name": "flags", "type": "#" }, { "name": "show_previews", "type": "flags.0?true" }, { "name": "silent", "type": "flags.1?true" }, { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1697798976", "predicate": "peerNotifySettings", "params": [ { "name": "flags", "type": "#" }, { "name": "show_previews", "type": "flags.0?true" }, { "name": "silent", "type": "flags.1?true" }, { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" } ], "type": "PeerNotifySettings" }, { "id": "-2122045747", "predicate": "peerSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "report_spam", "type": "flags.0?true" } ], "type": "PeerSettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector<PhotoSize>" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1490799288", "predicate": "inputReportReasonSpam", "params": [], "type": "ReportReason" }, { "id": "505595789", "predicate": "inputReportReasonViolence", "params": [], "type": "ReportReason" }, { "id": "777640226", "predicate": "inputReportReasonPornography", "params": [], "type": "ReportReason" }, { "id": "-512463606", "predicate": "inputReportReasonOther", "params": [ { "name": "text", "type": "string" } ], "type": "ReportReason" }, { "id": "1496513539", "predicate": "userFull", "params": [ { "name": "flags", "type": "#" }, { "name": "blocked", "type": "flags.0?true" }, { "name": "user", "type": "User" }, { "name": "about", "type": "flags.1?string" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "flags.2?Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "bot_info", "type": "flags.3?BotInfo" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "-748155807", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "ContactStatus" }, { "id": "986597452", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector<Contact>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector<ImportedContact>" }, { "name": "retry_contacts", "type": "Vector<long>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector<ContactBlocked>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector<ContactBlocked>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Blocked" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "1694474197", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector<Chat>" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.ChatFull" }, { "id": "-1269012015", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "-3644025", "predicate": "inputMessagesFilterGif", "params": [], "type": "MessagesFilter" }, { "id": "522914557", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-1576161051", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1657903163", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "ContactLink" }, { "name": "foreign_link", "type": "ContactLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector<Message>" }, { "name": "new_encrypted_messages", "type": "Vector<EncryptedMessage>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector<Message>" }, { "name": "new_encrypted_messages", "type": "Vector<EncryptedMessage>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-1857044719", "predicate": "updateShortMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from", "type": "flags.2?MessageFwdHeader" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector<MessageEntity>" } ], "type": "Updates" }, { "id": "377562760", "predicate": "updateShortChatMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "out", "type": "flags.1?true" }, { "name": "mentioned", "type": "flags.4?true" }, { "name": "media_unread", "type": "flags.5?true" }, { "name": "silent", "type": "flags.13?true" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "fwd_from", "type": "flags.2?MessageFwdHeader" }, { "name": "via_bot_id", "type": "flags.11?int" }, { "name": "reply_to_msg_id", "type": "flags.3?int" }, { "name": "entities", "type": "flags.7?Vector<MessageEntity>" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector<Update>" }, { "name": "users", "type": "Vector<User>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector<Update>" }, { "name": "users", "type": "Vector<User>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector<Photo>" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector<Photo>" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "98092748", "predicate": "dcOption", "params": [ { "name": "flags", "type": "#" }, { "name": "ipv6", "type": "flags.0?true" }, { "name": "media_only", "type": "flags.1?true" }, { "name": "tcpo_only", "type": "flags.2?true" }, { "name": "id", "type": "int" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "-918482040", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "expires", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector<DcOption>" }, { "name": "chat_size_max", "type": "int" }, { "name": "megagroup_size_max", "type": "int" }, { "name": "forwarded_count_max", "type": "int" }, { "name": "online_update_period_ms", "type": "int" }, { "name": "offline_blur_timeout_ms", "type": "int" }, { "name": "offline_idle_timeout_ms", "type": "int" }, { "name": "online_cloud_timeout_ms", "type": "int" }, { "name": "notify_cloud_delay_ms", "type": "int" }, { "name": "notify_default_delay_ms", "type": "int" }, { "name": "chat_big_size", "type": "int" }, { "name": "push_chat_period_ms", "type": "int" }, { "name": "push_chat_limit", "type": "int" }, { "name": "saved_gifs_limit", "type": "int" }, { "name": "edit_time_limit", "type": "int" }, { "name": "rating_e_decay", "type": "int" }, { "name": "disabled_features", "type": "Vector<DisabledFeature>" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "-364179876", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector<DcOption>" } ], "type": "Update" }, { "id": "495530093", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector<DocumentAttribute>" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-1386138479", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "mime_type", "type": "string" }, { "name": "attributes", "type": "Vector<DocumentAttribute>" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "444068508", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" }, { "name": "caption", "type": "string" } ], "type": "InputMedia" }, { "id": "-203411800", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" }, { "name": "caption", "type": "string" } ], "type": "MessageMedia" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-106717361", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "attributes", "type": "Vector<DocumentAttribute>" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-378127636", "predicate": "sendMessageUploadVideoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-212740181", "predicate": "sendMessageUploadAudioAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-774682074", "predicate": "sendMessageUploadPhotoAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "-1441998364", "predicate": "sendMessageUploadDocumentAction", "params": [ { "name": "progress", "type": "int" } ], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "446822276", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector<Peer>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" }, { "id": "-496024847", "predicate": "userStatusRecently", "params": [], "type": "UserStatus" }, { "id": "129960444", "predicate": "userStatusLastWeek", "params": [], "type": "UserStatus" }, { "id": "2011940674", "predicate": "userStatusLastMonth", "params": [], "type": "UserStatus" }, { "id": "-298113238", "predicate": "updatePrivacy", "params": [ { "name": "key", "type": "PrivacyKey" }, { "name": "rules", "type": "Vector<PrivacyRule>" } ], "type": "Update" }, { "id": "1335282456", "predicate": "inputPrivacyKeyStatusTimestamp", "params": [], "type": "InputPrivacyKey" }, { "id": "-1137792208", "predicate": "privacyKeyStatusTimestamp", "params": [], "type": "PrivacyKey" }, { "id": "218751099", "predicate": "inputPrivacyValueAllowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "407582158", "predicate": "inputPrivacyValueAllowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "320652927", "predicate": "inputPrivacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector<InputUser>" } ], "type": "InputPrivacyRule" }, { "id": "195371015", "predicate": "inputPrivacyValueDisallowContacts", "params": [], "type": "InputPrivacyRule" }, { "id": "-697604407", "predicate": "inputPrivacyValueDisallowAll", "params": [], "type": "InputPrivacyRule" }, { "id": "-1877932953", "predicate": "inputPrivacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector<InputUser>" } ], "type": "InputPrivacyRule" }, { "id": "-123988", "predicate": "privacyValueAllowContacts", "params": [], "type": "PrivacyRule" }, { "id": "1698855810", "predicate": "privacyValueAllowAll", "params": [], "type": "PrivacyRule" }, { "id": "1297858060", "predicate": "privacyValueAllowUsers", "params": [ { "name": "users", "type": "Vector<int>" } ], "type": "PrivacyRule" }, { "id": "-125240806", "predicate": "privacyValueDisallowContacts", "params": [], "type": "PrivacyRule" }, { "id": "-1955338397", "predicate": "privacyValueDisallowAll", "params": [], "type": "PrivacyRule" }, { "id": "209668535", "predicate": "privacyValueDisallowUsers", "params": [ { "name": "users", "type": "Vector<int>" } ], "type": "PrivacyRule" }, { "id": "1430961007", "predicate": "account.privacyRules", "params": [ { "name": "rules", "type": "Vector<PrivacyRule>" }, { "name": "users", "type": "Vector<User>" } ], "type": "account.PrivacyRules" }, { "id": "-1194283041", "predicate": "accountDaysTTL", "params": [ { "name": "days", "type": "int" } ], "type": "AccountDaysTTL" }, { "id": "314130811", "predicate": "updateUserPhone", "params": [ { "name": "user_id", "type": "int" }, { "name": "phone", "type": "string" } ], "type": "Update" }, { "id": "1815593308", "predicate": "documentAttributeImageSize", "params": [ { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "297109817", "predicate": "documentAttributeAnimated", "params": [], "type": "DocumentAttribute" }, { "id": "978674434", "predicate": "documentAttributeSticker", "params": [ { "name": "alt", "type": "string" }, { "name": "stickerset", "type": "InputStickerSet" } ], "type": "DocumentAttribute" }, { "id": "1494273227", "predicate": "documentAttributeVideo", "params": [ { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "DocumentAttribute" }, { "id": "-1739392570", "predicate": "documentAttributeAudio", "params": [ { "name": "flags", "type": "#" }, { "name": "voice", "type": "flags.10?true" }, { "name": "duration", "type": "int" }, { "name": "title", "type": "flags.0?string" }, { "name": "performer", "type": "flags.1?string" }, { "name": "waveform", "type": "flags.2?bytes" } ], "type": "DocumentAttribute" }, { "id": "358154344", "predicate": "documentAttributeFilename", "params": [ { "name": "file_name", "type": "string" } ], "type": "DocumentAttribute" }, { "id": "-244016606", "predicate": "messages.stickersNotModified", "params": [], "type": "messages.Stickers" }, { "id": "-1970352846", "predicate": "messages.stickers", "params": [ { "name": "hash", "type": "string" }, { "name": "stickers", "type": "Vector<Document>" } ], "type": "messages.Stickers" }, { "id": "313694676", "predicate": "stickerPack", "params": [ { "name": "emoticon", "type": "string" }, { "name": "documents", "type": "Vector<long>" } ], "type": "StickerPack" }, { "id": "-395967805", "predicate": "messages.allStickersNotModified", "params": [], "type": "messages.AllStickers" }, { "id": "-302170017", "predicate": "messages.allStickers", "params": [ { "name": "hash", "type": "int" }, { "name": "sets", "type": "Vector<StickerSet>" } ], "type": "messages.AllStickers" }, { "id": "-1369215196", "predicate": "disabledFeature", "params": [ { "name": "feature", "type": "string" }, { "name": "description", "type": "string" } ], "type": "DisabledFeature" }, { "id": "-1721631396", "predicate": "updateReadHistoryInbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "791617983", "predicate": "updateReadHistoryOutbox", "params": [ { "name": "peer", "type": "Peer" }, { "name": "max_id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-2066640507", "predicate": "messages.affectedMessages", "params": [ { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "1599050311", "predicate": "contactLinkUnknown", "params": [], "type": "ContactLink" }, { "id": "-17968211", "predicate": "contactLinkNone", "params": [], "type": "ContactLink" }, { "id": "646922073", "predicate": "contactLinkHasPhone", "params": [], "type": "ContactLink" }, { "id": "-721239344", "predicate": "contactLinkContact", "params": [], "type": "ContactLink" }, { "id": "2139689491", "predicate": "updateWebPage", "params": [ { "name": "webpage", "type": "WebPage" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-350980120", "predicate": "webPageEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "WebPage" }, { "id": "-981018084", "predicate": "webPagePending", "params": [ { "name": "id", "type": "long" }, { "name": "date", "type": "int" } ], "type": "WebPage" }, { "id": "-897446185", "predicate": "webPage", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "long" }, { "name": "url", "type": "string" }, { "name": "display_url", "type": "string" }, { "name": "type", "type": "flags.0?string" }, { "name": "site_name", "type": "flags.1?string" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "photo", "type": "flags.4?Photo" }, { "name": "embed_url", "type": "flags.5?string" }, { "name": "embed_type", "type": "flags.5?string" }, { "name": "embed_width", "type": "flags.6?int" }, { "name": "embed_height", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "author", "type": "flags.8?string" }, { "name": "document", "type": "flags.9?Document" } ], "type": "WebPage" }, { "id": "-1557277184", "predicate": "messageMediaWebPage", "params": [ { "name": "webpage", "type": "WebPage" } ], "type": "MessageMedia" }, { "id": "2079516406", "predicate": "authorization", "params": [ { "name": "hash", "type": "long" }, { "name": "flags", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "platform", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "api_id", "type": "int" }, { "name": "app_name", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "date_created", "type": "int" }, { "name": "date_active", "type": "int" }, { "name": "ip", "type": "string" }, { "name": "country", "type": "string" }, { "name": "region", "type": "string" } ], "type": "Authorization" }, { "id": "307276766", "predicate": "account.authorizations", "params": [ { "name": "authorizations", "type": "Vector<Authorization>" } ], "type": "account.Authorizations" }, { "id": "-1764049896", "predicate": "account.noPassword", "params": [ { "name": "new_salt", "type": "bytes" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "2081952796", "predicate": "account.password", "params": [ { "name": "current_salt", "type": "bytes" }, { "name": "new_salt", "type": "bytes" }, { "name": "hint", "type": "string" }, { "name": "has_recovery", "type": "Bool" }, { "name": "email_unconfirmed_pattern", "type": "string" } ], "type": "account.Password" }, { "id": "-1212732749", "predicate": "account.passwordSettings", "params": [ { "name": "email", "type": "string" } ], "type": "account.PasswordSettings" }, { "id": "-2037289493", "predicate": "account.passwordInputSettings", "params": [ { "name": "flags", "type": "#" }, { "name": "new_salt", "type": "flags.0?bytes" }, { "name": "new_password_hash", "type": "flags.0?bytes" }, { "name": "hint", "type": "flags.0?string" }, { "name": "email", "type": "flags.1?string" } ], "type": "account.PasswordInputSettings" }, { "id": "326715557", "predicate": "auth.passwordRecovery", "params": [ { "name": "email_pattern", "type": "string" } ], "type": "auth.PasswordRecovery" }, { "id": "673687578", "predicate": "inputMediaVenue", "params": [ { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "InputMedia" }, { "id": "2031269663", "predicate": "messageMediaVenue", "params": [ { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" } ], "type": "MessageMedia" }, { "id": "-1551583367", "predicate": "receivedNotifyMessage", "params": [ { "name": "id", "type": "int" }, { "name": "flags", "type": "int" } ], "type": "ReceivedNotifyMessage" }, { "id": "1776236393", "predicate": "chatInviteEmpty", "params": [], "type": "ExportedChatInvite" }, { "id": "-64092740", "predicate": "chatInviteExported", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedChatInvite" }, { "id": "1516793212", "predicate": "chatInviteAlready", "params": [ { "name": "chat", "type": "Chat" } ], "type": "ChatInvite" }, { "id": "-1813406880", "predicate": "chatInvite", "params": [ { "name": "flags", "type": "#" }, { "name": "channel", "type": "flags.0?true" }, { "name": "broadcast", "type": "flags.1?true" }, { "name": "public", "type": "flags.2?true" }, { "name": "megagroup", "type": "flags.3?true" }, { "name": "title", "type": "string" } ], "type": "ChatInvite" }, { "id": "-123931160", "predicate": "messageActionChatJoinedByLink", "params": [ { "name": "inviter_id", "type": "int" } ], "type": "MessageAction" }, { "id": "1757493555", "predicate": "updateReadMessagesContents", "params": [ { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-4838507", "predicate": "inputStickerSetEmpty", "params": [], "type": "InputStickerSet" }, { "id": "-1645763991", "predicate": "inputStickerSetID", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputStickerSet" }, { "id": "-2044933984", "predicate": "inputStickerSetShortName", "params": [ { "name": "short_name", "type": "string" } ], "type": "InputStickerSet" }, { "id": "-852477119", "predicate": "stickerSet", "params": [ { "name": "flags", "type": "#" }, { "name": "installed", "type": "flags.0?true" }, { "name": "disabled", "type": "flags.1?true" }, { "name": "official", "type": "flags.2?true" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" }, { "name": "short_name", "type": "string" }, { "name": "count", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "StickerSet" }, { "id": "-1240849242", "predicate": "messages.stickerSet", "params": [ { "name": "set", "type": "StickerSet" }, { "name": "packs", "type": "Vector<StickerPack>" }, { "name": "documents", "type": "Vector<Document>" } ], "type": "messages.StickerSet" }, { "id": "-787638374", "predicate": "user", "params": [ { "name": "flags", "type": "#" }, { "name": "self", "type": "flags.10?true" }, { "name": "contact", "type": "flags.11?true" }, { "name": "mutual_contact", "type": "flags.12?true" }, { "name": "deleted", "type": "flags.13?true" }, { "name": "bot", "type": "flags.14?true" }, { "name": "bot_chat_history", "type": "flags.15?true" }, { "name": "bot_nochats", "type": "flags.16?true" }, { "name": "verified", "type": "flags.17?true" }, { "name": "restricted", "type": "flags.18?true" }, { "name": "min", "type": "flags.20?true" }, { "name": "bot_inline_geo", "type": "flags.21?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.0?long" }, { "name": "first_name", "type": "flags.1?string" }, { "name": "last_name", "type": "flags.2?string" }, { "name": "username", "type": "flags.3?string" }, { "name": "phone", "type": "flags.4?string" }, { "name": "photo", "type": "flags.5?UserProfilePhoto" }, { "name": "status", "type": "flags.6?UserStatus" }, { "name": "bot_info_version", "type": "flags.14?int" }, { "name": "restriction_reason", "type": "flags.18?string" }, { "name": "bot_inline_placeholder", "type": "flags.19?string" } ], "type": "User" }, { "id": "-1032140601", "predicate": "botCommand", "params": [ { "name": "command", "type": "string" }, { "name": "description", "type": "string" } ], "type": "BotCommand" }, { "id": "-1729618630", "predicate": "botInfo", "params": [ { "name": "user_id", "type": "int" }, { "name": "description", "type": "string" }, { "name": "commands", "type": "Vector<BotCommand>" } ], "type": "BotInfo" }, { "id": "-1560655744", "predicate": "keyboardButton", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "2002815875", "predicate": "keyboardButtonRow", "params": [ { "name": "buttons", "type": "Vector<KeyboardButton>" } ], "type": "KeyboardButtonRow" }, { "id": "-1606526075", "predicate": "replyKeyboardHide", "params": [ { "name": "flags", "type": "#" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "-200242528", "predicate": "replyKeyboardForceReply", "params": [ { "name": "flags", "type": "#" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" } ], "type": "ReplyMarkup" }, { "id": "889353612", "predicate": "replyKeyboardMarkup", "params": [ { "name": "flags", "type": "#" }, { "name": "resize", "type": "flags.0?true" }, { "name": "single_use", "type": "flags.1?true" }, { "name": "selective", "type": "flags.2?true" }, { "name": "rows", "type": "Vector<KeyboardButtonRow>" } ], "type": "ReplyMarkup" }, { "id": "2072935910", "predicate": "inputPeerUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-668391402", "predicate": "inputUser", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-1350696044", "predicate": "help.appChangelogEmpty", "params": [], "type": "help.AppChangelog" }, { "id": "1181279933", "predicate": "help.appChangelog", "params": [ { "name": "text", "type": "string" } ], "type": "help.AppChangelog" }, { "id": "-1148011883", "predicate": "messageEntityUnknown", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-100378723", "predicate": "messageEntityMention", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1868782349", "predicate": "messageEntityHashtag", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1827637959", "predicate": "messageEntityBotCommand", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1859134776", "predicate": "messageEntityUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1692693954", "predicate": "messageEntityEmail", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-1117713463", "predicate": "messageEntityBold", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "-2106619040", "predicate": "messageEntityItalic", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "681706865", "predicate": "messageEntityCode", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" } ], "type": "MessageEntity" }, { "id": "1938967520", "predicate": "messageEntityPre", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "language", "type": "string" } ], "type": "MessageEntity" }, { "id": "1990644519", "predicate": "messageEntityTextUrl", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "url", "type": "string" } ], "type": "MessageEntity" }, { "id": "301019932", "predicate": "updateShortSentMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "out", "type": "flags.1?true" }, { "name": "id", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "media", "type": "flags.9?MessageMedia" }, { "name": "entities", "type": "flags.7?Vector<MessageEntity>" } ], "type": "Updates" }, { "id": "-292807034", "predicate": "inputChannelEmpty", "params": [], "type": "InputChannel" }, { "id": "-1343524562", "predicate": "inputChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputChannel" }, { "id": "-1109531342", "predicate": "peerChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Peer" }, { "id": "548253432", "predicate": "inputPeerChannel", "params": [ { "name": "channel_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "-1588737454", "predicate": "channel", "params": [ { "name": "flags", "type": "#" }, { "name": "creator", "type": "flags.0?true" }, { "name": "kicked", "type": "flags.1?true" }, { "name": "left", "type": "flags.2?true" }, { "name": "editor", "type": "flags.3?true" }, { "name": "moderator", "type": "flags.4?true" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "verified", "type": "flags.7?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "restricted", "type": "flags.9?true" }, { "name": "democracy", "type": "flags.10?true" }, { "name": "signatures", "type": "flags.11?true" }, { "name": "min", "type": "flags.12?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "flags.13?long" }, { "name": "title", "type": "string" }, { "name": "username", "type": "flags.6?string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "date", "type": "int" }, { "name": "version", "type": "int" }, { "name": "restriction_reason", "type": "flags.9?string" } ], "type": "Chat" }, { "id": "-2059962289", "predicate": "channelForbidden", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.5?true" }, { "name": "megagroup", "type": "flags.8?true" }, { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "title", "type": "string" } ], "type": "Chat" }, { "id": "2131196633", "predicate": "contacts.resolvedPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.ResolvedPeer" }, { "id": "-1009430225", "predicate": "channelFull", "params": [ { "name": "flags", "type": "#" }, { "name": "can_view_participants", "type": "flags.3?true" }, { "name": "can_set_username", "type": "flags.6?true" }, { "name": "id", "type": "int" }, { "name": "about", "type": "string" }, { "name": "participants_count", "type": "flags.0?int" }, { "name": "admins_count", "type": "flags.1?int" }, { "name": "kicked_count", "type": "flags.2?int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "read_outbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "exported_invite", "type": "ExportedChatInvite" }, { "name": "bot_info", "type": "Vector<BotInfo>" }, { "name": "migrated_from_chat_id", "type": "flags.4?int" }, { "name": "migrated_from_max_id", "type": "flags.4?int" }, { "name": "pinned_msg_id", "type": "flags.5?int" } ], "type": "ChatFull" }, { "id": "182649427", "predicate": "messageRange", "params": [ { "name": "min_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "MessageRange" }, { "id": "-1725551049", "predicate": "messages.channelMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "pts", "type": "int" }, { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "-1781355374", "predicate": "messageActionChannelCreate", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "-352032773", "predicate": "updateChannelTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "channel_id", "type": "int" }, { "name": "pts", "type": "flags.0?int" } ], "type": "Update" }, { "id": "-1227598250", "predicate": "updateChannel", "params": [ { "name": "channel_id", "type": "int" } ], "type": "Update" }, { "id": "1656358105", "predicate": "updateNewChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "1108669311", "predicate": "updateReadChannelInbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-1015733815", "predicate": "updateDeleteChannelMessages", "params": [ { "name": "channel_id", "type": "int" }, { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1734268085", "predicate": "updateChannelMessageViews", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" }, { "name": "views", "type": "int" } ], "type": "Update" }, { "id": "1041346555", "predicate": "updates.channelDifferenceEmpty", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" } ], "type": "updates.ChannelDifference" }, { "id": "1091431943", "predicate": "updates.channelDifferenceTooLong", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "top_message", "type": "int" }, { "name": "read_inbox_max_id", "type": "int" }, { "name": "read_outbox_max_id", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "updates.ChannelDifference" }, { "id": "543450958", "predicate": "updates.channelDifference", "params": [ { "name": "flags", "type": "#" }, { "name": "final", "type": "flags.0?true" }, { "name": "pts", "type": "int" }, { "name": "timeout", "type": "flags.1?int" }, { "name": "new_messages", "type": "Vector<Message>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "updates.ChannelDifference" }, { "id": "-1798033689", "predicate": "channelMessagesFilterEmpty", "params": [], "type": "ChannelMessagesFilter" }, { "id": "-847783593", "predicate": "channelMessagesFilter", "params": [ { "name": "flags", "type": "#" }, { "name": "exclude_new_messages", "type": "flags.1?true" }, { "name": "ranges", "type": "Vector<MessageRange>" } ], "type": "ChannelMessagesFilter" }, { "id": "367766557", "predicate": "channelParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1557620115", "predicate": "channelParticipantSelf", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1861910545", "predicate": "channelParticipantModerator", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1743180447", "predicate": "channelParticipantEditor", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-1933187430", "predicate": "channelParticipantKicked", "params": [ { "name": "user_id", "type": "int" }, { "name": "kicked_by", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-471670279", "predicate": "channelParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChannelParticipant" }, { "id": "-566281095", "predicate": "channelParticipantsRecent", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1268741783", "predicate": "channelParticipantsAdmins", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "1010285434", "predicate": "channelParticipantsKicked", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-1299865402", "predicate": "channelRoleEmpty", "params": [], "type": "ChannelParticipantRole" }, { "id": "-1776756363", "predicate": "channelRoleModerator", "params": [], "type": "ChannelParticipantRole" }, { "id": "-2113143156", "predicate": "channelRoleEditor", "params": [], "type": "ChannelParticipantRole" }, { "id": "-177282392", "predicate": "channels.channelParticipants", "params": [ { "name": "count", "type": "int" }, { "name": "participants", "type": "Vector<ChannelParticipant>" }, { "name": "users", "type": "Vector<User>" } ], "type": "channels.ChannelParticipants" }, { "id": "-791039645", "predicate": "channels.channelParticipant", "params": [ { "name": "participant", "type": "ChannelParticipant" }, { "name": "users", "type": "Vector<User>" } ], "type": "channels.ChannelParticipant" }, { "id": "-636267638", "predicate": "chatParticipantCreator", "params": [ { "name": "user_id", "type": "int" } ], "type": "ChatParticipant" }, { "id": "-489233354", "predicate": "chatParticipantAdmin", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "1855224129", "predicate": "updateChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1232070311", "predicate": "updateChatParticipantAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "is_admin", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1371385889", "predicate": "messageActionChatMigrateTo", "params": [ { "name": "channel_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1336546578", "predicate": "messageActionChannelMigrateFrom", "params": [ { "name": "title", "type": "string" }, { "name": "chat_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1328445861", "predicate": "channelParticipantsBots", "params": [], "type": "ChannelParticipantsFilter" }, { "id": "-236044656", "predicate": "help.termsOfService", "params": [ { "name": "text", "type": "string" } ], "type": "help.TermsOfService" }, { "id": "1753886890", "predicate": "updateNewStickerSet", "params": [ { "name": "stickerset", "type": "messages.StickerSet" } ], "type": "Update" }, { "id": "-253774767", "predicate": "updateStickerSetsOrder", "params": [ { "name": "order", "type": "Vector<long>" } ], "type": "Update" }, { "id": "1135492588", "predicate": "updateStickerSets", "params": [], "type": "Update" }, { "id": "372165663", "predicate": "foundGif", "params": [ { "name": "url", "type": "string" }, { "name": "thumb_url", "type": "string" }, { "name": "content_url", "type": "string" }, { "name": "content_type", "type": "string" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "FoundGif" }, { "id": "-1670052855", "predicate": "foundGifCached", "params": [ { "name": "url", "type": "string" }, { "name": "photo", "type": "Photo" }, { "name": "document", "type": "Document" } ], "type": "FoundGif" }, { "id": "1212395773", "predicate": "inputMediaGifExternal", "params": [ { "name": "url", "type": "string" }, { "name": "q", "type": "string" } ], "type": "InputMedia" }, { "id": "1158290442", "predicate": "messages.foundGifs", "params": [ { "name": "next_offset", "type": "int" }, { "name": "results", "type": "Vector<FoundGif>" } ], "type": "messages.FoundGifs" }, { "id": "-402498398", "predicate": "messages.savedGifsNotModified", "params": [], "type": "messages.SavedGifs" }, { "id": "772213157", "predicate": "messages.savedGifs", "params": [ { "name": "hash", "type": "int" }, { "name": "gifs", "type": "Vector<Document>" } ], "type": "messages.SavedGifs" }, { "id": "-1821035490", "predicate": "updateSavedGifs", "params": [], "type": "Update" }, { "id": "691006739", "predicate": "inputBotInlineMessageMediaAuto", "params": [ { "name": "flags", "type": "#" }, { "name": "caption", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "1036876423", "predicate": "inputBotInlineMessageText", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.0?true" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.1?Vector<MessageEntity>" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "750510426", "predicate": "inputBotInlineResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "url", "type": "flags.3?string" }, { "name": "thumb_url", "type": "flags.4?string" }, { "name": "content_url", "type": "flags.5?string" }, { "name": "content_type", "type": "flags.5?string" }, { "name": "w", "type": "flags.6?int" }, { "name": "h", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "175419739", "predicate": "botInlineMessageMediaAuto", "params": [ { "name": "flags", "type": "#" }, { "name": "caption", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "-1937807902", "predicate": "botInlineMessageText", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.0?true" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.1?Vector<MessageEntity>" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "-1679053127", "predicate": "botInlineResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "url", "type": "flags.3?string" }, { "name": "thumb_url", "type": "flags.4?string" }, { "name": "content_url", "type": "flags.5?string" }, { "name": "content_type", "type": "flags.5?string" }, { "name": "w", "type": "flags.6?int" }, { "name": "h", "type": "flags.6?int" }, { "name": "duration", "type": "flags.7?int" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "627509670", "predicate": "messages.botResults", "params": [ { "name": "flags", "type": "#" }, { "name": "gallery", "type": "flags.0?true" }, { "name": "query_id", "type": "long" }, { "name": "next_offset", "type": "flags.1?string" }, { "name": "switch_pm", "type": "flags.2?InlineBotSwitchPM" }, { "name": "results", "type": "Vector<BotInlineResult>" } ], "type": "messages.BotResults" }, { "id": "1417832080", "predicate": "updateBotInlineQuery", "params": [ { "name": "flags", "type": "#" }, { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "query", "type": "string" }, { "name": "geo", "type": "flags.0?GeoPoint" }, { "name": "offset", "type": "string" } ], "type": "Update" }, { "id": "239663460", "predicate": "updateBotInlineSend", "params": [ { "name": "flags", "type": "#" }, { "name": "user_id", "type": "int" }, { "name": "query", "type": "string" }, { "name": "geo", "type": "flags.0?GeoPoint" }, { "name": "id", "type": "string" }, { "name": "msg_id", "type": "flags.1?InputBotInlineMessageID" } ], "type": "Update" }, { "id": "1358283666", "predicate": "inputMessagesFilterVoice", "params": [], "type": "MessagesFilter" }, { "id": "928101534", "predicate": "inputMessagesFilterMusic", "params": [], "type": "MessagesFilter" }, { "id": "-1107622874", "predicate": "inputPrivacyKeyChatInvite", "params": [], "type": "InputPrivacyKey" }, { "id": "1343122938", "predicate": "privacyKeyChatInvite", "params": [], "type": "PrivacyKey" }, { "id": "524838915", "predicate": "exportedMessageLink", "params": [ { "name": "link", "type": "string" } ], "type": "ExportedMessageLink" }, { "id": "-947462709", "predicate": "messageFwdHeader", "params": [ { "name": "flags", "type": "#" }, { "name": "from_id", "type": "flags.0?int" }, { "name": "date", "type": "int" }, { "name": "channel_id", "type": "flags.1?int" }, { "name": "channel_post", "type": "flags.2?int" } ], "type": "MessageFwdHeader" }, { "id": "457133559", "predicate": "updateEditChannelMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-1738988427", "predicate": "updateChannelPinnedMessage", "params": [ { "name": "channel_id", "type": "int" }, { "name": "id", "type": "int" } ], "type": "Update" }, { "id": "-1799538451", "predicate": "messageActionPinMessage", "params": [], "type": "MessageAction" }, { "id": "1923290508", "predicate": "auth.codeTypeSms", "params": [], "type": "auth.CodeType" }, { "id": "1948046307", "predicate": "auth.codeTypeCall", "params": [], "type": "auth.CodeType" }, { "id": "577556219", "predicate": "auth.codeTypeFlashCall", "params": [], "type": "auth.CodeType" }, { "id": "1035688326", "predicate": "auth.sentCodeTypeApp", "params": [ { "name": "length", "type": "int" } ], "type": "auth.SentCodeType" }, { "id": "-1073693790", "predicate": "auth.sentCodeTypeSms", "params": [ { "name": "length", "type": "int" } ], "type": "auth.SentCodeType" }, { "id": "1398007207", "predicate": "auth.sentCodeTypeCall", "params": [ { "name": "length", "type": "int" } ], "type": "auth.SentCodeType" }, { "id": "-1425815847", "predicate": "auth.sentCodeTypeFlashCall", "params": [ { "name": "pattern", "type": "string" } ], "type": "auth.SentCodeType" }, { "id": "629866245", "predicate": "keyboardButtonUrl", "params": [ { "name": "text", "type": "string" }, { "name": "url", "type": "string" } ], "type": "KeyboardButton" }, { "id": "1748655686", "predicate": "keyboardButtonCallback", "params": [ { "name": "text", "type": "string" }, { "name": "data", "type": "bytes" } ], "type": "KeyboardButton" }, { "id": "-1318425559", "predicate": "keyboardButtonRequestPhone", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "-59151553", "predicate": "keyboardButtonRequestGeoLocation", "params": [ { "name": "text", "type": "string" } ], "type": "KeyboardButton" }, { "id": "-367298028", "predicate": "keyboardButtonSwitchInline", "params": [ { "name": "text", "type": "string" }, { "name": "query", "type": "string" } ], "type": "KeyboardButton" }, { "id": "1218642516", "predicate": "replyInlineMarkup", "params": [ { "name": "rows", "type": "Vector<KeyboardButtonRow>" } ], "type": "ReplyMarkup" }, { "id": "308605382", "predicate": "messages.botCallbackAnswer", "params": [ { "name": "flags", "type": "#" }, { "name": "alert", "type": "flags.1?true" }, { "name": "message", "type": "flags.0?string" } ], "type": "messages.BotCallbackAnswer" }, { "id": "-1500747636", "predicate": "updateBotCallbackQuery", "params": [ { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "peer", "type": "Peer" }, { "name": "msg_id", "type": "int" }, { "name": "data", "type": "bytes" } ], "type": "Update" }, { "id": "649453030", "predicate": "messages.messageEditData", "params": [ { "name": "flags", "type": "#" }, { "name": "caption", "type": "flags.0?true" } ], "type": "messages.MessageEditData" }, { "id": "-469536605", "predicate": "updateEditMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" }, { "name": "pts_count", "type": "int" } ], "type": "Update" }, { "id": "-190472735", "predicate": "inputBotInlineMessageMediaGeo", "params": [ { "name": "flags", "type": "#" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "-1431327288", "predicate": "inputBotInlineMessageMediaVenue", "params": [ { "name": "flags", "type": "#" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "766443943", "predicate": "inputBotInlineMessageMediaContact", "params": [ { "name": "flags", "type": "#" }, { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "InputBotInlineMessage" }, { "id": "982505656", "predicate": "botInlineMessageMediaGeo", "params": [ { "name": "flags", "type": "#" }, { "name": "geo", "type": "GeoPoint" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "1130767150", "predicate": "botInlineMessageMediaVenue", "params": [ { "name": "flags", "type": "#" }, { "name": "geo", "type": "GeoPoint" }, { "name": "title", "type": "string" }, { "name": "address", "type": "string" }, { "name": "provider", "type": "string" }, { "name": "venue_id", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "904770772", "predicate": "botInlineMessageMediaContact", "params": [ { "name": "flags", "type": "#" }, { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "BotInlineMessage" }, { "id": "-1462213465", "predicate": "inputBotInlineResultPhoto", "params": [ { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "photo", "type": "InputPhoto" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "-459324", "predicate": "inputBotInlineResultDocument", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "title", "type": "flags.1?string" }, { "name": "description", "type": "flags.2?string" }, { "name": "document", "type": "InputDocument" }, { "name": "send_message", "type": "InputBotInlineMessage" } ], "type": "InputBotInlineResult" }, { "id": "400266251", "predicate": "botInlineMediaResult", "params": [ { "name": "flags", "type": "#" }, { "name": "id", "type": "string" }, { "name": "type", "type": "string" }, { "name": "photo", "type": "flags.0?Photo" }, { "name": "document", "type": "flags.1?Document" }, { "name": "title", "type": "flags.2?string" }, { "name": "description", "type": "flags.3?string" }, { "name": "send_message", "type": "BotInlineMessage" } ], "type": "BotInlineResult" }, { "id": "-1995686519", "predicate": "inputBotInlineMessageID", "params": [ { "name": "dc_id", "type": "int" }, { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputBotInlineMessageID" }, { "id": "750622127", "predicate": "updateInlineBotCallbackQuery", "params": [ { "name": "query_id", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "msg_id", "type": "InputBotInlineMessageID" }, { "name": "data", "type": "bytes" } ], "type": "Update" }, { "id": "1008755359", "predicate": "inlineBotSwitchPM", "params": [ { "name": "text", "type": "string" }, { "name": "start_param", "type": "string" } ], "type": "InlineBotSwitchPM" }, { "id": "863093588", "predicate": "messages.peerDialogs", "params": [ { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "state", "type": "updates.State" } ], "type": "messages.PeerDialogs" }, { "id": "-305282981", "predicate": "topPeer", "params": [ { "name": "peer", "type": "Peer" }, { "name": "rating", "type": "double" } ], "type": "TopPeer" }, { "id": "-1419371685", "predicate": "topPeerCategoryBotsPM", "params": [], "type": "TopPeerCategory" }, { "id": "344356834", "predicate": "topPeerCategoryBotsInline", "params": [], "type": "TopPeerCategory" }, { "id": "104314861", "predicate": "topPeerCategoryCorrespondents", "params": [], "type": "TopPeerCategory" }, { "id": "-1122524854", "predicate": "topPeerCategoryGroups", "params": [], "type": "TopPeerCategory" }, { "id": "371037736", "predicate": "topPeerCategoryChannels", "params": [], "type": "TopPeerCategory" }, { "id": "-75283823", "predicate": "topPeerCategoryPeers", "params": [ { "name": "category", "type": "TopPeerCategory" }, { "name": "count", "type": "int" }, { "name": "peers", "type": "Vector<TopPeer>" } ], "type": "TopPeerCategoryPeers" }, { "id": "-567906571", "predicate": "contacts.topPeersNotModified", "params": [], "type": "contacts.TopPeers" }, { "id": "1891070632", "predicate": "contacts.topPeers", "params": [ { "name": "categories", "type": "Vector<TopPeerCategoryPeers>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.TopPeers" }, { "id": "892193368", "predicate": "messageEntityMentionName", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "user_id", "type": "int" } ], "type": "MessageEntity" }, { "id": "546203849", "predicate": "inputMessageEntityMentionName", "params": [ { "name": "offset", "type": "int" }, { "name": "length", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "MessageEntity" }, { "id": "975236280", "predicate": "inputMessagesFilterChatPhotos", "params": [], "type": "MessagesFilter" }, { "id": "634833351", "predicate": "updateReadChannelOutbox", "params": [ { "name": "channel_id", "type": "int" }, { "name": "max_id", "type": "int" } ], "type": "Update" }, { "id": "-299124375", "predicate": "updateDraftMessage", "params": [ { "name": "peer", "type": "Peer" }, { "name": "draft", "type": "DraftMessage" } ], "type": "Update" }, { "id": "-1169445179", "predicate": "draftMessageEmpty", "params": [], "type": "DraftMessage" }, { "id": "-40996577", "predicate": "draftMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.3?Vector<MessageEntity>" }, { "name": "date", "type": "int" } ], "type": "DraftMessage" }, { "id": "-1615153660", "predicate": "messageActionHistoryClear", "params": [], "type": "MessageAction" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector<long>" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "-2035355412", "method": "auth.sendCode", "params": [ { "name": "flags", "type": "#" }, { "name": "allow_flashcall", "type": "flags.0?true" }, { "name": "phone_number", "type": "string" }, { "name": "current_number", "type": "flags.0?Bool" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" } ], "type": "auth.SentCode" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector<string>" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1669245048", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "2018596725", "method": "account.updateProfile", "params": [ { "name": "flags", "type": "#" }, { "name": "first_name", "type": "flags.0?string" }, { "name": "last_name", "type": "flags.1?string" }, { "name": "about", "type": "flags.2?string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector<WallPaper>" }, { "id": "-1374118561", "method": "account.reportPeer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "reason", "type": "ReportReason" } ], "type": "Bool" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector<InputUser>" } ], "type": "Vector<User>" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector<ContactStatus>" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector<InputContact>" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector<InputUser>" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector<int>" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector<int>" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.Messages" }, { "id": "1799878989", "method": "messages.getDialogs", "params": [ { "name": "offset_date", "type": "int" }, { "name": "offset_id", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1347868602", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "offset_date", "type": "int" }, { "name": "add_offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "min_id", "type": "int" } ], "type": "messages.Messages" }, { "id": "-732523960", "method": "messages.search", "params": [ { "name": "flags", "type": "#" }, { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "238054714", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedMessages" }, { "id": "469850889", "method": "messages.deleteHistory", "params": [ { "name": "flags", "type": "#" }, { "name": "just_clear", "type": "flags.0?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "-1510897371", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.AffectedMessages" }, { "id": "94983360", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector<ReceivedNotifyMessage>" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "-91733382", "method": "messages.sendMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "clear_draft", "type": "flags.7?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector<MessageEntity>" } ], "type": "Updates" }, { "id": "-923703407", "method": "messages.sendMedia", "params": [ { "name": "flags", "type": "#" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "clear_draft", "type": "flags.7?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" } ], "type": "Updates" }, { "id": "1888354709", "method": "messages.forwardMessages", "params": [ { "name": "flags", "type": "#" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "from_peer", "type": "InputPeer" }, { "name": "id", "type": "Vector<int>" }, { "name": "random_id", "type": "Vector<long>" }, { "name": "to_peer", "type": "InputPeer" } ], "type": "Updates" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "-1460572005", "method": "messages.hideReportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "913498268", "method": "messages.getPeerSettings", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "PeerSettings" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-599447467", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-900957736", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "-106911223", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "Updates" }, { "id": "-530505962", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "Updates" }, { "id": "164303470", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector<InputUser>" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector<InputPhoto>" } ], "type": "Vector<long>" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-1372724842", "method": "help.getAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector<InputAppEvent>" } ], "type": "Bool" }, { "id": "1295590211", "method": "help.getInviteText", "params": [], "type": "help.InviteText" }, { "id": "-1848823128", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "long" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "865483769", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Updates" }, { "id": "-1082919718", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector<InputUser>" }, { "name": "random_id", "type": "Vector<long>" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "Updates" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector<long>" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "916930423", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.AffectedMessages" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "-623130288", "method": "account.getPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" } ], "type": "account.PrivacyRules" }, { "id": "-906486552", "method": "account.setPrivacy", "params": [ { "name": "key", "type": "InputPrivacyKey" }, { "name": "rules", "type": "Vector<InputPrivacyRule>" } ], "type": "account.PrivacyRules" }, { "id": "1099779595", "method": "account.deleteAccount", "params": [ { "name": "reason", "type": "string" } ], "type": "Bool" }, { "id": "150761757", "method": "account.getAccountTTL", "params": [], "type": "AccountDaysTTL" }, { "id": "608323678", "method": "account.setAccountTTL", "params": [ { "name": "ttl", "type": "AccountDaysTTL" } ], "type": "Bool" }, { "id": "-627372787", "method": "invokeWithLayer", "params": [ { "name": "layer", "type": "int" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-113456221", "method": "contacts.resolveUsername", "params": [ { "name": "username", "type": "string" } ], "type": "contacts.ResolvedPeer" }, { "id": "149257707", "method": "account.sendChangePhoneCode", "params": [ { "name": "flags", "type": "#" }, { "name": "allow_flashcall", "type": "flags.0?true" }, { "name": "phone_number", "type": "string" }, { "name": "current_number", "type": "flags.0?Bool" } ], "type": "auth.SentCode" }, { "id": "1891839707", "method": "account.changePhone", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "User" }, { "id": "-1373446075", "method": "messages.getStickers", "params": [ { "name": "emoticon", "type": "string" }, { "name": "hash", "type": "string" } ], "type": "messages.Stickers" }, { "id": "479598769", "method": "messages.getAllStickers", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.AllStickers" }, { "id": "954152242", "method": "account.updateDeviceLocked", "params": [ { "name": "period", "type": "int" } ], "type": "Bool" }, { "id": "1738800940", "method": "auth.importBotAuthorization", "params": [ { "name": "flags", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "bot_auth_token", "type": "string" } ], "type": "auth.Authorization" }, { "id": "623001124", "method": "messages.getWebPagePreview", "params": [ { "name": "message", "type": "string" } ], "type": "MessageMedia" }, { "id": "-484392616", "method": "account.getAuthorizations", "params": [], "type": "account.Authorizations" }, { "id": "-545786948", "method": "account.resetAuthorization", "params": [ { "name": "hash", "type": "long" } ], "type": "Bool" }, { "id": "1418342645", "method": "account.getPassword", "params": [], "type": "account.Password" }, { "id": "-1131605573", "method": "account.getPasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" } ], "type": "account.PasswordSettings" }, { "id": "-92517498", "method": "account.updatePasswordSettings", "params": [ { "name": "current_password_hash", "type": "bytes" }, { "name": "new_settings", "type": "account.PasswordInputSettings" } ], "type": "Bool" }, { "id": "174260510", "method": "auth.checkPassword", "params": [ { "name": "password_hash", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-661144474", "method": "auth.requestPasswordRecovery", "params": [], "type": "auth.PasswordRecovery" }, { "id": "1319464594", "method": "auth.recoverPassword", "params": [ { "name": "code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1080796745", "method": "invokeWithoutUpdates", "params": [ { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "2106086025", "method": "messages.exportChatInvite", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ExportedChatInvite" }, { "id": "1051570619", "method": "messages.checkChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "ChatInvite" }, { "id": "1817183516", "method": "messages.importChatInvite", "params": [ { "name": "hash", "type": "string" } ], "type": "Updates" }, { "id": "639215886", "method": "messages.getStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "messages.StickerSet" }, { "id": "2066793382", "method": "messages.installStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" }, { "name": "disabled", "type": "Bool" } ], "type": "Bool" }, { "id": "-110209570", "method": "messages.uninstallStickerSet", "params": [ { "name": "stickerset", "type": "InputStickerSet" } ], "type": "Bool" }, { "id": "-421563528", "method": "messages.startBot", "params": [ { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "random_id", "type": "long" }, { "name": "start_param", "type": "string" } ], "type": "Updates" }, { "id": "-1189013126", "method": "help.getAppChangelog", "params": [], "type": "help.AppChangelog" }, { "id": "-993483427", "method": "messages.getMessagesViews", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector<int>" }, { "name": "increment", "type": "Bool" } ], "type": "Vector<int>" }, { "id": "-871347913", "method": "channels.readHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "max_id", "type": "int" } ], "type": "Bool" }, { "id": "-2067661490", "method": "channels.deleteMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector<int>" } ], "type": "messages.AffectedMessages" }, { "id": "-787622117", "method": "channels.deleteUserHistory", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.AffectedHistory" }, { "id": "-32999408", "method": "channels.reportSpam", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "id", "type": "Vector<int>" } ], "type": "Bool" }, { "id": "-1814580409", "method": "channels.getMessages", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "Vector<int>" } ], "type": "messages.Messages" }, { "id": "618237842", "method": "channels.getParticipants", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelParticipantsFilter" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "channels.ChannelParticipants" }, { "id": "1416484774", "method": "channels.getParticipant", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" } ], "type": "channels.ChannelParticipant" }, { "id": "176122811", "method": "channels.getChannels", "params": [ { "name": "id", "type": "Vector<InputChannel>" } ], "type": "messages.Chats" }, { "id": "141781513", "method": "channels.getFullChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "messages.ChatFull" }, { "id": "-192332417", "method": "channels.createChannel", "params": [ { "name": "flags", "type": "#" }, { "name": "broadcast", "type": "flags.0?true" }, { "name": "megagroup", "type": "flags.1?true" }, { "name": "title", "type": "string" }, { "name": "about", "type": "string" } ], "type": "Updates" }, { "id": "333610782", "method": "channels.editAbout", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "about", "type": "string" } ], "type": "Bool" }, { "id": "-344583728", "method": "channels.editAdmin", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "role", "type": "ChannelParticipantRole" } ], "type": "Updates" }, { "id": "1450044624", "method": "channels.editTitle", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "title", "type": "string" } ], "type": "Updates" }, { "id": "-248621111", "method": "channels.editPhoto", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "Updates" }, { "id": "283557164", "method": "channels.checkUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "890549214", "method": "channels.updateUsername", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "615851205", "method": "channels.joinChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-130635115", "method": "channels.leaveChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "429865580", "method": "channels.inviteToChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "users", "type": "Vector<InputUser>" } ], "type": "Updates" }, { "id": "-1502421484", "method": "channels.kickFromChannel", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "user_id", "type": "InputUser" }, { "name": "kicked", "type": "Bool" } ], "type": "Updates" }, { "id": "-950663035", "method": "channels.exportInvite", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "ExportedChatInvite" }, { "id": "-1072619549", "method": "channels.deleteChannel", "params": [ { "name": "channel", "type": "InputChannel" } ], "type": "Updates" }, { "id": "-1154295872", "method": "updates.getChannelDifference", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "filter", "type": "ChannelMessagesFilter" }, { "name": "pts", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "updates.ChannelDifference" }, { "id": "-326379039", "method": "messages.toggleChatAdmins", "params": [ { "name": "chat_id", "type": "int" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1444503762", "method": "messages.editChatAdmin", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "is_admin", "type": "Bool" } ], "type": "Bool" }, { "id": "363051235", "method": "messages.migrateChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Updates" }, { "id": "-1640190800", "method": "messages.searchGlobal", "params": [ { "name": "q", "type": "string" }, { "name": "offset_date", "type": "int" }, { "name": "offset_peer", "type": "InputPeer" }, { "name": "offset_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "889286899", "method": "help.getTermsOfService", "params": [], "type": "help.TermsOfService" }, { "id": "-1613775824", "method": "messages.reorderStickerSets", "params": [ { "name": "order", "type": "Vector<long>" } ], "type": "Bool" }, { "id": "864953444", "method": "messages.getDocumentByHash", "params": [ { "name": "sha256", "type": "bytes" }, { "name": "size", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "Document" }, { "id": "-1080395925", "method": "messages.searchGifs", "params": [ { "name": "q", "type": "string" }, { "name": "offset", "type": "int" } ], "type": "messages.FoundGifs" }, { "id": "-2084618926", "method": "messages.getSavedGifs", "params": [ { "name": "hash", "type": "int" } ], "type": "messages.SavedGifs" }, { "id": "846868683", "method": "messages.saveGif", "params": [ { "name": "id", "type": "InputDocument" }, { "name": "unsave", "type": "Bool" } ], "type": "Bool" }, { "id": "1364105629", "method": "messages.getInlineBotResults", "params": [ { "name": "flags", "type": "#" }, { "name": "bot", "type": "InputUser" }, { "name": "peer", "type": "InputPeer" }, { "name": "geo_point", "type": "flags.0?InputGeoPoint" }, { "name": "query", "type": "string" }, { "name": "offset", "type": "string" } ], "type": "messages.BotResults" }, { "id": "-346119674", "method": "messages.setInlineBotResults", "params": [ { "name": "flags", "type": "#" }, { "name": "gallery", "type": "flags.0?true" }, { "name": "private", "type": "flags.1?true" }, { "name": "query_id", "type": "long" }, { "name": "results", "type": "Vector<InputBotInlineResult>" }, { "name": "cache_time", "type": "int" }, { "name": "next_offset", "type": "flags.2?string" }, { "name": "switch_pm", "type": "flags.3?InlineBotSwitchPM" } ], "type": "Bool" }, { "id": "-1318189314", "method": "messages.sendInlineBotResult", "params": [ { "name": "flags", "type": "#" }, { "name": "silent", "type": "flags.5?true" }, { "name": "background", "type": "flags.6?true" }, { "name": "clear_draft", "type": "flags.7?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "random_id", "type": "long" }, { "name": "query_id", "type": "long" }, { "name": "id", "type": "string" } ], "type": "Updates" }, { "id": "1231065863", "method": "channels.toggleInvites", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-934882771", "method": "channels.exportMessageLink", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "int" } ], "type": "ExportedMessageLink" }, { "id": "527021574", "method": "channels.toggleSignatures", "params": [ { "name": "channel", "type": "InputChannel" }, { "name": "enabled", "type": "Bool" } ], "type": "Updates" }, { "id": "-1490162350", "method": "channels.updatePinnedMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "silent", "type": "flags.0?true" }, { "name": "channel", "type": "InputChannel" }, { "name": "id", "type": "int" } ], "type": "Updates" }, { "id": "1056025023", "method": "auth.resendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "auth.SentCode" }, { "id": "520357240", "method": "auth.cancelCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "-39416522", "method": "messages.getMessageEditData", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" } ], "type": "messages.MessageEditData" }, { "id": "-829299510", "method": "messages.editMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "message", "type": "flags.11?string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector<MessageEntity>" } ], "type": "Updates" }, { "id": "319564933", "method": "messages.editInlineBotMessage", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "id", "type": "InputBotInlineMessageID" }, { "name": "message", "type": "flags.11?string" }, { "name": "reply_markup", "type": "flags.2?ReplyMarkup" }, { "name": "entities", "type": "flags.3?Vector<MessageEntity>" } ], "type": "Bool" }, { "id": "-1494659324", "method": "messages.getBotCallbackAnswer", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "msg_id", "type": "int" }, { "name": "data", "type": "bytes" } ], "type": "messages.BotCallbackAnswer" }, { "id": "1209817370", "method": "messages.setBotCallbackAnswer", "params": [ { "name": "flags", "type": "#" }, { "name": "alert", "type": "flags.1?true" }, { "name": "query_id", "type": "long" }, { "name": "message", "type": "flags.0?string" } ], "type": "Bool" }, { "id": "-728224331", "method": "contacts.getTopPeers", "params": [ { "name": "flags", "type": "#" }, { "name": "correspondents", "type": "flags.0?true" }, { "name": "bots_pm", "type": "flags.1?true" }, { "name": "bots_inline", "type": "flags.2?true" }, { "name": "groups", "type": "flags.10?true" }, { "name": "channels", "type": "flags.15?true" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" }, { "name": "hash", "type": "int" } ], "type": "contacts.TopPeers" }, { "id": "451113900", "method": "contacts.resetTopPeerRating", "params": [ { "name": "category", "type": "TopPeerCategory" }, { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "764901049", "method": "messages.getPeerDialogs", "params": [ { "name": "peers", "type": "Vector<InputPeer>" } ], "type": "messages.PeerDialogs" }, { "id": "-1137057461", "method": "messages.saveDraft", "params": [ { "name": "flags", "type": "#" }, { "name": "no_webpage", "type": "flags.1?true" }, { "name": "reply_to_msg_id", "type": "flags.0?int" }, { "name": "peer", "type": "InputPeer" }, { "name": "message", "type": "string" }, { "name": "entities", "type": "flags.3?Vector<MessageEntity>" } ], "type": "Bool" }, { "id": "1782549861", "method": "messages.getAllDrafts", "params": [], "type": "Updates" } ] }{ "constructors": [ { "id": "-1132882121", "predicate": "boolFalse", "params": [], "type": "Bool" }, { "id": "-1720552011", "predicate": "boolTrue", "params": [], "type": "Bool" }, { "id": "1072550713", "predicate": "true", "params": [], "type": "True" }, { "id": "481674261", "predicate": "vector", "params": [], "type": "Vector t" }, { "id": "-994444869", "predicate": "error", "params": [ { "name": "code", "type": "int" }, { "name": "text", "type": "string" } ], "type": "Error" }, { "id": "1450380236", "predicate": "null", "params": [], "type": "Null" }, { "id": "2134579434", "predicate": "inputPeerEmpty", "params": [], "type": "InputPeer" }, { "id": "2107670217", "predicate": "inputPeerSelf", "params": [], "type": "InputPeer" }, { "id": "270785512", "predicate": "inputPeerContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1690012891", "predicate": "inputPeerForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputPeer" }, { "id": "396093539", "predicate": "inputPeerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "InputPeer" }, { "id": "-1182234929", "predicate": "inputUserEmpty", "params": [], "type": "InputUser" }, { "id": "-138301121", "predicate": "inputUserSelf", "params": [], "type": "InputUser" }, { "id": "-2031530139", "predicate": "inputUserContact", "params": [ { "name": "user_id", "type": "int" } ], "type": "InputUser" }, { "id": "1700689151", "predicate": "inputUserForeign", "params": [ { "name": "user_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputUser" }, { "id": "-208488460", "predicate": "inputPhoneContact", "params": [ { "name": "client_id", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputContact" }, { "id": "-181407105", "predicate": "inputFile", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" }, { "name": "md5_checksum", "type": "string" } ], "type": "InputFile" }, { "id": "-1771768449", "predicate": "inputMediaEmpty", "params": [], "type": "InputMedia" }, { "id": "767900285", "predicate": "inputMediaUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" } ], "type": "InputMedia" }, { "id": "-1893027092", "predicate": "inputMediaPhoto", "params": [ { "name": "id", "type": "InputPhoto" } ], "type": "InputMedia" }, { "id": "-104578748", "predicate": "inputMediaGeoPoint", "params": [ { "name": "geo_point", "type": "InputGeoPoint" } ], "type": "InputMedia" }, { "id": "-1494984313", "predicate": "inputMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "InputMedia" }, { "id": "322623222", "predicate": "inputMediaUploadedVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1726817601", "predicate": "inputMediaUploadedThumbVideo", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "2130852582", "predicate": "inputMediaVideo", "params": [ { "name": "id", "type": "InputVideo" } ], "type": "InputMedia" }, { "id": "480546647", "predicate": "inputChatPhotoEmpty", "params": [], "type": "InputChatPhoto" }, { "id": "-1809496270", "predicate": "inputChatUploadedPhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-1293828344", "predicate": "inputChatPhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "InputChatPhoto" }, { "id": "-457104426", "predicate": "inputGeoPointEmpty", "params": [], "type": "InputGeoPoint" }, { "id": "-206066487", "predicate": "inputGeoPoint", "params": [ { "name": "lat", "type": "double" }, { "name": "long", "type": "double" } ], "type": "InputGeoPoint" }, { "id": "483901197", "predicate": "inputPhotoEmpty", "params": [], "type": "InputPhoto" }, { "id": "-74070332", "predicate": "inputPhoto", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputPhoto" }, { "id": "1426648181", "predicate": "inputVideoEmpty", "params": [], "type": "InputVideo" }, { "id": "-296249774", "predicate": "inputVideo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputVideo" }, { "id": "342061462", "predicate": "inputFileLocation", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1023632620", "predicate": "inputVideoFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-1377390588", "predicate": "inputPhotoCropAuto", "params": [], "type": "InputPhotoCrop" }, { "id": "-644787419", "predicate": "inputPhotoCrop", "params": [ { "name": "crop_left", "type": "double" }, { "name": "crop_top", "type": "double" }, { "name": "crop_width", "type": "double" } ], "type": "InputPhotoCrop" }, { "id": "1996904104", "predicate": "inputAppEvent", "params": [ { "name": "time", "type": "double" }, { "name": "type", "type": "string" }, { "name": "peer", "type": "long" }, { "name": "data", "type": "string" } ], "type": "InputAppEvent" }, { "id": "-1649296275", "predicate": "peerUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "Peer" }, { "id": "-1160714821", "predicate": "peerChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Peer" }, { "id": "-1432995067", "predicate": "storage.fileUnknown", "params": [], "type": "storage.FileType" }, { "id": "8322574", "predicate": "storage.fileJpeg", "params": [], "type": "storage.FileType" }, { "id": "-891180321", "predicate": "storage.fileGif", "params": [], "type": "storage.FileType" }, { "id": "172975040", "predicate": "storage.filePng", "params": [], "type": "storage.FileType" }, { "id": "-1373745011", "predicate": "storage.filePdf", "params": [], "type": "storage.FileType" }, { "id": "1384777335", "predicate": "storage.fileMp3", "params": [], "type": "storage.FileType" }, { "id": "1258941372", "predicate": "storage.fileMov", "params": [], "type": "storage.FileType" }, { "id": "1086091090", "predicate": "storage.filePartial", "params": [], "type": "storage.FileType" }, { "id": "-1278304028", "predicate": "storage.fileMp4", "params": [], "type": "storage.FileType" }, { "id": "276907596", "predicate": "storage.fileWebp", "params": [], "type": "storage.FileType" }, { "id": "2086234950", "predicate": "fileLocationUnavailable", "params": [ { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "1406570614", "predicate": "fileLocation", "params": [ { "name": "dc_id", "type": "int" }, { "name": "volume_id", "type": "long" }, { "name": "local_id", "type": "int" }, { "name": "secret", "type": "long" } ], "type": "FileLocation" }, { "id": "537022650", "predicate": "userEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "User" }, { "id": "1879553105", "predicate": "userSelf", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" }, { "name": "inactive", "type": "Bool" } ], "type": "User" }, { "id": "-894214632", "predicate": "userContact", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-640891665", "predicate": "userRequest", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "phone", "type": "string" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "123533224", "predicate": "userForeign", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" }, { "name": "access_hash", "type": "long" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "status", "type": "UserStatus" } ], "type": "User" }, { "id": "-704549510", "predicate": "userDeleted", "params": [ { "name": "id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "User" }, { "id": "1326562017", "predicate": "userProfilePhotoEmpty", "params": [], "type": "UserProfilePhoto" }, { "id": "-715532088", "predicate": "userProfilePhoto", "params": [ { "name": "photo_id", "type": "long" }, { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "UserProfilePhoto" }, { "id": "164646985", "predicate": "userStatusEmpty", "params": [], "type": "UserStatus" }, { "id": "-306628279", "predicate": "userStatusOnline", "params": [ { "name": "expires", "type": "int" } ], "type": "UserStatus" }, { "id": "9203775", "predicate": "userStatusOffline", "params": [ { "name": "was_online", "type": "int" } ], "type": "UserStatus" }, { "id": "-1683826688", "predicate": "chatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Chat" }, { "id": "1855757255", "predicate": "chat", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "photo", "type": "ChatPhoto" }, { "name": "participants_count", "type": "int" }, { "name": "date", "type": "int" }, { "name": "left", "type": "Bool" }, { "name": "version", "type": "int" } ], "type": "Chat" }, { "id": "-83047359", "predicate": "chatForbidden", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "date", "type": "int" } ], "type": "Chat" }, { "id": "1661886910", "predicate": "chatFull", "params": [ { "name": "id", "type": "int" }, { "name": "participants", "type": "ChatParticipants" }, { "name": "chat_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "ChatFull" }, { "id": "-925415106", "predicate": "chatParticipant", "params": [ { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ChatParticipant" }, { "id": "265468810", "predicate": "chatParticipantsForbidden", "params": [ { "name": "chat_id", "type": "int" } ], "type": "ChatParticipants" }, { "id": "2017571861", "predicate": "chatParticipants", "params": [ { "name": "chat_id", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participants", "type": "Vector<ChatParticipant>" }, { "name": "version", "type": "int" } ], "type": "ChatParticipants" }, { "id": "935395612", "predicate": "chatPhotoEmpty", "params": [], "type": "ChatPhoto" }, { "id": "1632839530", "predicate": "chatPhoto", "params": [ { "name": "photo_small", "type": "FileLocation" }, { "name": "photo_big", "type": "FileLocation" } ], "type": "ChatPhoto" }, { "id": "-2082087340", "predicate": "messageEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "Message" }, { "id": "1450613171", "predicate": "message", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "Message" }, { "id": "-1553471722", "predicate": "messageForwarded", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "fwd_from_id", "type": "int" }, { "name": "fwd_date", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" } ], "type": "Message" }, { "id": "495384334", "predicate": "messageService", "params": [ { "name": "flags", "type": "int" }, { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "to_id", "type": "Peer" }, { "name": "date", "type": "int" }, { "name": "action", "type": "MessageAction" } ], "type": "Message" }, { "id": "1038967584", "predicate": "messageMediaEmpty", "params": [], "type": "MessageMedia" }, { "id": "-926655958", "predicate": "messageMediaPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageMedia" }, { "id": "-1563278704", "predicate": "messageMediaVideo", "params": [ { "name": "video", "type": "Video" } ], "type": "MessageMedia" }, { "id": "1457575028", "predicate": "messageMediaGeo", "params": [ { "name": "geo", "type": "GeoPoint" } ], "type": "MessageMedia" }, { "id": "1585262393", "predicate": "messageMediaContact", "params": [ { "name": "phone_number", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "user_id", "type": "int" } ], "type": "MessageMedia" }, { "id": "694364726", "predicate": "messageMediaUnsupported", "params": [ { "name": "bytes", "type": "bytes" } ], "type": "MessageMedia" }, { "id": "-1230047312", "predicate": "messageActionEmpty", "params": [], "type": "MessageAction" }, { "id": "-1503425638", "predicate": "messageActionChatCreate", "params": [ { "name": "title", "type": "string" }, { "name": "users", "type": "Vector<int>" } ], "type": "MessageAction" }, { "id": "-1247687078", "predicate": "messageActionChatEditTitle", "params": [ { "name": "title", "type": "string" } ], "type": "MessageAction" }, { "id": "2144015272", "predicate": "messageActionChatEditPhoto", "params": [ { "name": "photo", "type": "Photo" } ], "type": "MessageAction" }, { "id": "-1780220945", "predicate": "messageActionChatDeletePhoto", "params": [], "type": "MessageAction" }, { "id": "1581055051", "predicate": "messageActionChatAddUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1297179892", "predicate": "messageActionChatDeleteUser", "params": [ { "name": "user_id", "type": "int" } ], "type": "MessageAction" }, { "id": "-1422222932", "predicate": "dialog", "params": [ { "name": "peer", "type": "Peer" }, { "name": "top_message", "type": "int" }, { "name": "unread_count", "type": "int" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Dialog" }, { "id": "590459437", "predicate": "photoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Photo" }, { "id": "582313809", "predicate": "photo", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "geo", "type": "GeoPoint" }, { "name": "sizes", "type": "Vector<PhotoSize>" } ], "type": "Photo" }, { "id": "236446268", "predicate": "photoSizeEmpty", "params": [ { "name": "type", "type": "string" } ], "type": "PhotoSize" }, { "id": "2009052699", "predicate": "photoSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "size", "type": "int" } ], "type": "PhotoSize" }, { "id": "-374917894", "predicate": "photoCachedSize", "params": [ { "name": "type", "type": "string" }, { "name": "location", "type": "FileLocation" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "PhotoSize" }, { "id": "-1056548696", "predicate": "videoEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Video" }, { "id": "948937617", "predicate": "video", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "caption", "type": "string" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" }, { "name": "w", "type": "int" }, { "name": "h", "type": "int" } ], "type": "Video" }, { "id": "286776671", "predicate": "geoPointEmpty", "params": [], "type": "GeoPoint" }, { "id": "541710092", "predicate": "geoPoint", "params": [ { "name": "long", "type": "double" }, { "name": "lat", "type": "double" } ], "type": "GeoPoint" }, { "id": "-486486981", "predicate": "auth.checkedPhone", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_invited", "type": "Bool" } ], "type": "auth.CheckedPhone" }, { "id": "-269659687", "predicate": "auth.sentCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "-155815004", "predicate": "auth.authorization", "params": [ { "name": "expires", "type": "int" }, { "name": "user", "type": "User" } ], "type": "auth.Authorization" }, { "id": "-543777747", "predicate": "auth.exportedAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.ExportedAuthorization" }, { "id": "-1195615476", "predicate": "inputNotifyPeer", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "InputNotifyPeer" }, { "id": "423314455", "predicate": "inputNotifyUsers", "params": [], "type": "InputNotifyPeer" }, { "id": "1251338318", "predicate": "inputNotifyChats", "params": [], "type": "InputNotifyPeer" }, { "id": "-1540769658", "predicate": "inputNotifyAll", "params": [], "type": "InputNotifyPeer" }, { "id": "-265263912", "predicate": "inputPeerNotifyEventsEmpty", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "-395694988", "predicate": "inputPeerNotifyEventsAll", "params": [], "type": "InputPeerNotifyEvents" }, { "id": "1185074840", "predicate": "inputPeerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "InputPeerNotifySettings" }, { "id": "-1378534221", "predicate": "peerNotifyEventsEmpty", "params": [], "type": "PeerNotifyEvents" }, { "id": "1830677896", "predicate": "peerNotifyEventsAll", "params": [], "type": "PeerNotifyEvents" }, { "id": "1889961234", "predicate": "peerNotifySettingsEmpty", "params": [], "type": "PeerNotifySettings" }, { "id": "-1923214866", "predicate": "peerNotifySettings", "params": [ { "name": "mute_until", "type": "int" }, { "name": "sound", "type": "string" }, { "name": "show_previews", "type": "Bool" }, { "name": "events_mask", "type": "int" } ], "type": "PeerNotifySettings" }, { "id": "-860866985", "predicate": "wallPaper", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "sizes", "type": "Vector<PhotoSize>" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "1997575642", "predicate": "userFull", "params": [ { "name": "user", "type": "User" }, { "name": "link", "type": "contacts.Link" }, { "name": "profile_photo", "type": "Photo" }, { "name": "notify_settings", "type": "PeerNotifySettings" }, { "name": "blocked", "type": "Bool" }, { "name": "real_first_name", "type": "string" }, { "name": "real_last_name", "type": "string" } ], "type": "UserFull" }, { "id": "-116274796", "predicate": "contact", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual", "type": "Bool" } ], "type": "Contact" }, { "id": "-805141448", "predicate": "importedContact", "params": [ { "name": "user_id", "type": "int" }, { "name": "client_id", "type": "long" } ], "type": "ImportedContact" }, { "id": "1444661369", "predicate": "contactBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "ContactBlocked" }, { "id": "1038193057", "predicate": "contactSuggested", "params": [ { "name": "user_id", "type": "int" }, { "name": "mutual_contacts", "type": "int" } ], "type": "ContactSuggested" }, { "id": "-1434994573", "predicate": "contactStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "expires", "type": "int" } ], "type": "ContactStatus" }, { "id": "322183672", "predicate": "contacts.foreignLinkUnknown", "params": [], "type": "contacts.ForeignLink" }, { "id": "-1484775609", "predicate": "contacts.foreignLinkRequested", "params": [ { "name": "has_phone", "type": "Bool" } ], "type": "contacts.ForeignLink" }, { "id": "468356321", "predicate": "contacts.foreignLinkMutual", "params": [], "type": "contacts.ForeignLink" }, { "id": "-768992160", "predicate": "contacts.myLinkEmpty", "params": [], "type": "contacts.MyLink" }, { "id": "1818882030", "predicate": "contacts.myLinkRequested", "params": [ { "name": "contact", "type": "Bool" } ], "type": "contacts.MyLink" }, { "id": "-1035932711", "predicate": "contacts.myLinkContact", "params": [], "type": "contacts.MyLink" }, { "id": "-322001931", "predicate": "contacts.link", "params": [ { "name": "my_link", "type": "contacts.MyLink" }, { "name": "foreign_link", "type": "contacts.ForeignLink" }, { "name": "user", "type": "User" } ], "type": "contacts.Link" }, { "id": "-1219778094", "predicate": "contacts.contactsNotModified", "params": [], "type": "contacts.Contacts" }, { "id": "1871416498", "predicate": "contacts.contacts", "params": [ { "name": "contacts", "type": "Vector<Contact>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Contacts" }, { "id": "-1387117803", "predicate": "contacts.importedContacts", "params": [ { "name": "imported", "type": "Vector<ImportedContact>" }, { "name": "retry_contacts", "type": "Vector<long>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.ImportedContacts" }, { "id": "471043349", "predicate": "contacts.blocked", "params": [ { "name": "blocked", "type": "Vector<ContactBlocked>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Blocked" }, { "id": "-1878523231", "predicate": "contacts.blockedSlice", "params": [ { "name": "count", "type": "int" }, { "name": "blocked", "type": "Vector<ContactBlocked>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Blocked" }, { "id": "1447681221", "predicate": "contacts.suggested", "params": [ { "name": "results", "type": "Vector<ContactSuggested>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Suggested" }, { "id": "364538944", "predicate": "messages.dialogs", "params": [ { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Dialogs" }, { "id": "1910543603", "predicate": "messages.dialogsSlice", "params": [ { "name": "count", "type": "int" }, { "name": "dialogs", "type": "Vector<Dialog>" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Dialogs" }, { "id": "-1938715001", "predicate": "messages.messages", "params": [ { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "189033187", "predicate": "messages.messagesSlice", "params": [ { "name": "count", "type": "int" }, { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Messages" }, { "id": "-1768654661", "predicate": "messages.statedMessages", "params": [ { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessages" }, { "id": "-797251802", "predicate": "messages.statedMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-772484260", "predicate": "messages.sentMessage", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.SentMessage" }, { "id": "-2125411368", "predicate": "messages.chats", "params": [ { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.Chats" }, { "id": "-438840932", "predicate": "messages.chatFull", "params": [ { "name": "full_chat", "type": "ChatFull" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" } ], "type": "messages.ChatFull" }, { "id": "-1210173710", "predicate": "messages.affectedHistory", "params": [ { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "1474492012", "predicate": "inputMessagesFilterEmpty", "params": [], "type": "MessagesFilter" }, { "id": "-1777752804", "predicate": "inputMessagesFilterPhotos", "params": [], "type": "MessagesFilter" }, { "id": "-1614803355", "predicate": "inputMessagesFilterVideo", "params": [], "type": "MessagesFilter" }, { "id": "1458172132", "predicate": "inputMessagesFilterPhotoVideo", "params": [], "type": "MessagesFilter" }, { "id": "-648121413", "predicate": "inputMessagesFilterPhotoVideoDocuments", "params": [], "type": "MessagesFilter" }, { "id": "-1629621880", "predicate": "inputMessagesFilterDocument", "params": [], "type": "MessagesFilter" }, { "id": "-808946398", "predicate": "inputMessagesFilterAudio", "params": [], "type": "MessagesFilter" }, { "id": "1526462308", "predicate": "inputMessagesFilterAudioDocuments", "params": [], "type": "MessagesFilter" }, { "id": "2129714567", "predicate": "inputMessagesFilterUrl", "params": [], "type": "MessagesFilter" }, { "id": "20626867", "predicate": "updateNewMessage", "params": [ { "name": "message", "type": "Message" }, { "name": "pts", "type": "int" } ], "type": "Update" }, { "id": "1318109142", "predicate": "updateMessageID", "params": [ { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "Update" }, { "id": "-966484431", "predicate": "updateReadMessages", "params": [ { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" } ], "type": "Update" }, { "id": "-1456734682", "predicate": "updateDeleteMessages", "params": [ { "name": "messages", "type": "Vector<int>" }, { "name": "pts", "type": "int" } ], "type": "Update" }, { "id": "1548249383", "predicate": "updateUserTyping", "params": [ { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "-1704596961", "predicate": "updateChatUserTyping", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Update" }, { "id": "125178264", "predicate": "updateChatParticipants", "params": [ { "name": "participants", "type": "ChatParticipants" } ], "type": "Update" }, { "id": "469489699", "predicate": "updateUserStatus", "params": [ { "name": "user_id", "type": "int" }, { "name": "status", "type": "UserStatus" } ], "type": "Update" }, { "id": "-1489818765", "predicate": "updateUserName", "params": [ { "name": "user_id", "type": "int" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" }, { "name": "username", "type": "string" } ], "type": "Update" }, { "id": "-1791935732", "predicate": "updateUserPhoto", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "photo", "type": "UserProfilePhoto" }, { "name": "previous", "type": "Bool" } ], "type": "Update" }, { "id": "628472761", "predicate": "updateContactRegistered", "params": [ { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "1369737882", "predicate": "updateContactLink", "params": [ { "name": "user_id", "type": "int" }, { "name": "my_link", "type": "contacts.MyLink" }, { "name": "foreign_link", "type": "contacts.ForeignLink" } ], "type": "Update" }, { "id": "-1895411046", "predicate": "updateNewAuthorization", "params": [ { "name": "auth_key_id", "type": "long" }, { "name": "date", "type": "int" }, { "name": "device", "type": "string" }, { "name": "location", "type": "string" } ], "type": "Update" }, { "id": "-1519637954", "predicate": "updates.state", "params": [ { "name": "pts", "type": "int" }, { "name": "qts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "unread_count", "type": "int" } ], "type": "updates.State" }, { "id": "1567990072", "predicate": "updates.differenceEmpty", "params": [ { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "updates.Difference" }, { "id": "16030880", "predicate": "updates.difference", "params": [ { "name": "new_messages", "type": "Vector<Message>" }, { "name": "new_encrypted_messages", "type": "Vector<EncryptedMessage>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-1459938943", "predicate": "updates.differenceSlice", "params": [ { "name": "new_messages", "type": "Vector<Message>" }, { "name": "new_encrypted_messages", "type": "Vector<EncryptedMessage>" }, { "name": "other_updates", "type": "Vector<Update>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "intermediate_state", "type": "updates.State" } ], "type": "updates.Difference" }, { "id": "-484987010", "predicate": "updatesTooLong", "params": [], "type": "Updates" }, { "id": "-738961532", "predicate": "updateShortMessage", "params": [ { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "724548942", "predicate": "updateShortChatMessage", "params": [ { "name": "id", "type": "int" }, { "name": "from_id", "type": "int" }, { "name": "chat_id", "type": "int" }, { "name": "message", "type": "string" }, { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "2027216577", "predicate": "updateShort", "params": [ { "name": "update", "type": "Update" }, { "name": "date", "type": "int" } ], "type": "Updates" }, { "id": "1918567619", "predicate": "updatesCombined", "params": [ { "name": "updates", "type": "Vector<Update>" }, { "name": "users", "type": "Vector<User>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "date", "type": "int" }, { "name": "seq_start", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "1957577280", "predicate": "updates", "params": [ { "name": "updates", "type": "Vector<Update>" }, { "name": "users", "type": "Vector<User>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "date", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "Updates" }, { "id": "-1916114267", "predicate": "photos.photos", "params": [ { "name": "photos", "type": "Vector<Photo>" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photos" }, { "id": "352657236", "predicate": "photos.photosSlice", "params": [ { "name": "count", "type": "int" }, { "name": "photos", "type": "Vector<Photo>" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photos" }, { "id": "539045032", "predicate": "photos.photo", "params": [ { "name": "photo", "type": "Photo" }, { "name": "users", "type": "Vector<User>" } ], "type": "photos.Photo" }, { "id": "157948117", "predicate": "upload.file", "params": [ { "name": "type", "type": "storage.FileType" }, { "name": "mtime", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "upload.File" }, { "id": "784507964", "predicate": "dcOption", "params": [ { "name": "id", "type": "int" }, { "name": "hostname", "type": "string" }, { "name": "ip_address", "type": "string" }, { "name": "port", "type": "int" } ], "type": "DcOption" }, { "id": "777313652", "predicate": "config", "params": [ { "name": "date", "type": "int" }, { "name": "test_mode", "type": "Bool" }, { "name": "this_dc", "type": "int" }, { "name": "dc_options", "type": "Vector<DcOption>" }, { "name": "chat_size_max", "type": "int" }, { "name": "broadcast_size_max", "type": "int" } ], "type": "Config" }, { "id": "-1910892683", "predicate": "nearestDc", "params": [ { "name": "country", "type": "string" }, { "name": "this_dc", "type": "int" }, { "name": "nearest_dc", "type": "int" } ], "type": "NearestDc" }, { "id": "-1987579119", "predicate": "help.appUpdate", "params": [ { "name": "id", "type": "int" }, { "name": "critical", "type": "Bool" }, { "name": "url", "type": "string" }, { "name": "text", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "-1000708810", "predicate": "help.noAppUpdate", "params": [], "type": "help.AppUpdate" }, { "id": "415997816", "predicate": "help.inviteText", "params": [ { "name": "message", "type": "string" } ], "type": "help.InviteText" }, { "id": "1047852486", "predicate": "messages.statedMessagesLinks", "params": [ { "name": "messages", "type": "Vector<Message>" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "links", "type": "Vector<contacts.Link>" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessages" }, { "id": "-1448138623", "predicate": "messages.statedMessageLink", "params": [ { "name": "message", "type": "Message" }, { "name": "chats", "type": "Vector<Chat>" }, { "name": "users", "type": "Vector<User>" }, { "name": "links", "type": "Vector<contacts.Link>" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-371504577", "predicate": "messages.sentMessageLink", "params": [ { "name": "id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "pts", "type": "int" }, { "name": "seq", "type": "int" }, { "name": "links", "type": "Vector<contacts.Link>" } ], "type": "messages.SentMessage" }, { "id": "1662091044", "predicate": "wallPaperSolid", "params": [ { "name": "id", "type": "int" }, { "name": "title", "type": "string" }, { "name": "bg_color", "type": "int" }, { "name": "color", "type": "int" } ], "type": "WallPaper" }, { "id": "314359194", "predicate": "updateNewEncryptedMessage", "params": [ { "name": "message", "type": "EncryptedMessage" }, { "name": "qts", "type": "int" } ], "type": "Update" }, { "id": "386986326", "predicate": "updateEncryptedChatTyping", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Update" }, { "id": "-1264392051", "predicate": "updateEncryption", "params": [ { "name": "chat", "type": "EncryptedChat" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "956179895", "predicate": "updateEncryptedMessagesRead", "params": [ { "name": "chat_id", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "date", "type": "int" } ], "type": "Update" }, { "id": "-1417756512", "predicate": "encryptedChatEmpty", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "1006044124", "predicate": "encryptedChatWaiting", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-931638658", "predicate": "encryptedChatRequested", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "-94974410", "predicate": "encryptedChat", "params": [ { "name": "id", "type": "int" }, { "name": "access_hash", "type": "long" }, { "name": "date", "type": "int" }, { "name": "admin_id", "type": "int" }, { "name": "participant_id", "type": "int" }, { "name": "g_a_or_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "332848423", "predicate": "encryptedChatDiscarded", "params": [ { "name": "id", "type": "int" } ], "type": "EncryptedChat" }, { "id": "-247351839", "predicate": "inputEncryptedChat", "params": [ { "name": "chat_id", "type": "int" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedChat" }, { "id": "-1038136962", "predicate": "encryptedFileEmpty", "params": [], "type": "EncryptedFile" }, { "id": "1248893260", "predicate": "encryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "EncryptedFile" }, { "id": "406307684", "predicate": "inputEncryptedFileEmpty", "params": [], "type": "InputEncryptedFile" }, { "id": "1690108678", "predicate": "inputEncryptedFileUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "md5_checksum", "type": "string" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "1511503333", "predicate": "inputEncryptedFile", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputEncryptedFile" }, { "id": "-182231723", "predicate": "inputEncryptedFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "-317144808", "predicate": "encryptedMessage", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" }, { "name": "file", "type": "EncryptedFile" } ], "type": "EncryptedMessage" }, { "id": "594758406", "predicate": "encryptedMessageService", "params": [ { "name": "random_id", "type": "long" }, { "name": "chat_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "EncryptedMessage" }, { "id": "-1058912715", "predicate": "messages.dhConfigNotModified", "params": [ { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "740433629", "predicate": "messages.dhConfig", "params": [ { "name": "g", "type": "int" }, { "name": "p", "type": "bytes" }, { "name": "version", "type": "int" }, { "name": "random", "type": "bytes" } ], "type": "messages.DhConfig" }, { "id": "1443858741", "predicate": "messages.sentEncryptedMessage", "params": [ { "name": "date", "type": "int" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1802240206", "predicate": "messages.sentEncryptedFile", "params": [ { "name": "date", "type": "int" }, { "name": "file", "type": "EncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-95482955", "predicate": "inputFileBig", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "name", "type": "string" } ], "type": "InputFile" }, { "id": "767652808", "predicate": "inputEncryptedFileBigUploaded", "params": [ { "name": "id", "type": "long" }, { "name": "parts", "type": "int" }, { "name": "key_fingerprint", "type": "int" } ], "type": "InputEncryptedFile" }, { "id": "974056226", "predicate": "updateChatParticipantAdd", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "inviter_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "1851755554", "predicate": "updateChatParticipantDelete", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "int" }, { "name": "version", "type": "int" } ], "type": "Update" }, { "id": "-1906403213", "predicate": "updateDcOptions", "params": [ { "name": "dc_options", "type": "Vector<DcOption>" } ], "type": "Update" }, { "id": "1313442987", "predicate": "inputMediaUploadedAudio", "params": [ { "name": "file", "type": "InputFile" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-1986820223", "predicate": "inputMediaAudio", "params": [ { "name": "id", "type": "InputAudio" } ], "type": "InputMedia" }, { "id": "887592125", "predicate": "inputMediaUploadedDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "file_name", "type": "string" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "1044831837", "predicate": "inputMediaUploadedThumbDocument", "params": [ { "name": "file", "type": "InputFile" }, { "name": "thumb", "type": "InputFile" }, { "name": "file_name", "type": "string" }, { "name": "mime_type", "type": "string" } ], "type": "InputMedia" }, { "id": "-779818943", "predicate": "inputMediaDocument", "params": [ { "name": "id", "type": "InputDocument" } ], "type": "InputMedia" }, { "id": "802824708", "predicate": "messageMediaDocument", "params": [ { "name": "document", "type": "Document" } ], "type": "MessageMedia" }, { "id": "-961117440", "predicate": "messageMediaAudio", "params": [ { "name": "audio", "type": "Audio" } ], "type": "MessageMedia" }, { "id": "-648356732", "predicate": "inputAudioEmpty", "params": [], "type": "InputAudio" }, { "id": "2010398975", "predicate": "inputAudio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputAudio" }, { "id": "1928391342", "predicate": "inputDocumentEmpty", "params": [], "type": "InputDocument" }, { "id": "410618194", "predicate": "inputDocument", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputDocument" }, { "id": "1960591437", "predicate": "inputAudioFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1313188841", "predicate": "inputDocumentFileLocation", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" } ], "type": "InputFileLocation" }, { "id": "1483311320", "predicate": "audioEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Audio" }, { "id": "-945003370", "predicate": "audio", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "duration", "type": "int" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "dc_id", "type": "int" } ], "type": "Audio" }, { "id": "922273905", "predicate": "documentEmpty", "params": [ { "name": "id", "type": "long" } ], "type": "Document" }, { "id": "-1627626714", "predicate": "document", "params": [ { "name": "id", "type": "long" }, { "name": "access_hash", "type": "long" }, { "name": "user_id", "type": "int" }, { "name": "date", "type": "int" }, { "name": "file_name", "type": "string" }, { "name": "mime_type", "type": "string" }, { "name": "size", "type": "int" }, { "name": "thumb", "type": "PhotoSize" }, { "name": "dc_id", "type": "int" } ], "type": "Document" }, { "id": "398898678", "predicate": "help.support", "params": [ { "name": "phone_number", "type": "string" }, { "name": "user", "type": "User" } ], "type": "help.Support" }, { "id": "-1613493288", "predicate": "notifyPeer", "params": [ { "name": "peer", "type": "Peer" } ], "type": "NotifyPeer" }, { "id": "-1261946036", "predicate": "notifyUsers", "params": [], "type": "NotifyPeer" }, { "id": "-1073230141", "predicate": "notifyChats", "params": [], "type": "NotifyPeer" }, { "id": "1959820384", "predicate": "notifyAll", "params": [], "type": "NotifyPeer" }, { "id": "-2131957734", "predicate": "updateUserBlocked", "params": [ { "name": "user_id", "type": "int" }, { "name": "blocked", "type": "Bool" } ], "type": "Update" }, { "id": "-1094555409", "predicate": "updateNotifySettings", "params": [ { "name": "peer", "type": "NotifyPeer" }, { "name": "notify_settings", "type": "PeerNotifySettings" } ], "type": "Update" }, { "id": "-484053553", "predicate": "auth.sentAppCode", "params": [ { "name": "phone_registered", "type": "Bool" }, { "name": "phone_code_hash", "type": "string" }, { "name": "send_call_timeout", "type": "int" }, { "name": "is_password", "type": "Bool" } ], "type": "auth.SentCode" }, { "id": "381645902", "predicate": "sendMessageTypingAction", "params": [], "type": "SendMessageAction" }, { "id": "-44119819", "predicate": "sendMessageCancelAction", "params": [], "type": "SendMessageAction" }, { "id": "-1584933265", "predicate": "sendMessageRecordVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1845219337", "predicate": "sendMessageUploadVideoAction", "params": [], "type": "SendMessageAction" }, { "id": "-718310409", "predicate": "sendMessageRecordAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-424899985", "predicate": "sendMessageUploadAudioAction", "params": [], "type": "SendMessageAction" }, { "id": "-1727382502", "predicate": "sendMessageUploadPhotoAction", "params": [], "type": "SendMessageAction" }, { "id": "-1884362354", "predicate": "sendMessageUploadDocumentAction", "params": [], "type": "SendMessageAction" }, { "id": "393186209", "predicate": "sendMessageGeoLocationAction", "params": [], "type": "SendMessageAction" }, { "id": "1653390447", "predicate": "sendMessageChooseContactAction", "params": [], "type": "SendMessageAction" }, { "id": "-360210539", "predicate": "contactFound", "params": [ { "name": "user_id", "type": "int" } ], "type": "ContactFound" }, { "id": "90570766", "predicate": "contacts.found", "params": [ { "name": "results", "type": "Vector<ContactFound>" }, { "name": "users", "type": "Vector<User>" } ], "type": "contacts.Found" }, { "id": "942527460", "predicate": "updateServiceNotification", "params": [ { "name": "type", "type": "string" }, { "name": "message", "type": "string" }, { "name": "media", "type": "MessageMedia" }, { "name": "popup", "type": "Bool" } ], "type": "Update" } ], "methods": [ { "id": "-878758099", "method": "invokeAfterMsg", "params": [ { "name": "msg_id", "type": "long" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1036301552", "method": "invokeAfterMsgs", "params": [ { "name": "msg_ids", "type": "Vector<long>" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "1877286395", "method": "auth.checkPhone", "params": [ { "name": "phone_number", "type": "string" } ], "type": "auth.CheckedPhone" }, { "id": "1988976461", "method": "auth.sendCode", "params": [ { "name": "phone_number", "type": "string" }, { "name": "sms_type", "type": "int" }, { "name": "api_id", "type": "int" }, { "name": "api_hash", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "auth.SentCode" }, { "id": "63247716", "method": "auth.sendCall", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "453408308", "method": "auth.signUp", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" }, { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "auth.Authorization" }, { "id": "-1126886015", "method": "auth.signIn", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" }, { "name": "phone_code", "type": "string" } ], "type": "auth.Authorization" }, { "id": "1461180992", "method": "auth.logOut", "params": [], "type": "Bool" }, { "id": "-1616179942", "method": "auth.resetAuthorizations", "params": [], "type": "Bool" }, { "id": "1998331287", "method": "auth.sendInvites", "params": [ { "name": "phone_numbers", "type": "Vector<string>" }, { "name": "message", "type": "string" } ], "type": "Bool" }, { "id": "-440401971", "method": "auth.exportAuthorization", "params": [ { "name": "dc_id", "type": "int" } ], "type": "auth.ExportedAuthorization" }, { "id": "-470837741", "method": "auth.importAuthorization", "params": [ { "name": "id", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "auth.Authorization" }, { "id": "-841733627", "method": "auth.bindTempAuthKey", "params": [ { "name": "perm_auth_key_id", "type": "long" }, { "name": "nonce", "type": "long" }, { "name": "expires_at", "type": "int" }, { "name": "encrypted_message", "type": "bytes" } ], "type": "Bool" }, { "id": "1147957548", "method": "account.registerDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "app_sandbox", "type": "Bool" }, { "name": "lang_code", "type": "string" } ], "type": "Bool" }, { "id": "1707432768", "method": "account.unregisterDevice", "params": [ { "name": "token_type", "type": "int" }, { "name": "token", "type": "string" } ], "type": "Bool" }, { "id": "-2067899501", "method": "account.updateNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" }, { "name": "settings", "type": "InputPeerNotifySettings" } ], "type": "Bool" }, { "id": "313765169", "method": "account.getNotifySettings", "params": [ { "name": "peer", "type": "InputNotifyPeer" } ], "type": "PeerNotifySettings" }, { "id": "-612493497", "method": "account.resetNotifySettings", "params": [], "type": "Bool" }, { "id": "-259486360", "method": "account.updateProfile", "params": [ { "name": "first_name", "type": "string" }, { "name": "last_name", "type": "string" } ], "type": "User" }, { "id": "1713919532", "method": "account.updateStatus", "params": [ { "name": "offline", "type": "Bool" } ], "type": "Bool" }, { "id": "-1068696894", "method": "account.getWallPapers", "params": [], "type": "Vector<WallPaper>" }, { "id": "227648840", "method": "users.getUsers", "params": [ { "name": "id", "type": "Vector<InputUser>" } ], "type": "Vector<User>" }, { "id": "-902781519", "method": "users.getFullUser", "params": [ { "name": "id", "type": "InputUser" } ], "type": "UserFull" }, { "id": "-995929106", "method": "contacts.getStatuses", "params": [], "type": "Vector<ContactStatus>" }, { "id": "583445000", "method": "contacts.getContacts", "params": [ { "name": "hash", "type": "string" } ], "type": "contacts.Contacts" }, { "id": "-634342611", "method": "contacts.importContacts", "params": [ { "name": "contacts", "type": "Vector<InputContact>" }, { "name": "replace", "type": "Bool" } ], "type": "contacts.ImportedContacts" }, { "id": "-847825880", "method": "contacts.getSuggested", "params": [ { "name": "limit", "type": "int" } ], "type": "contacts.Suggested" }, { "id": "-1902823612", "method": "contacts.deleteContact", "params": [ { "name": "id", "type": "InputUser" } ], "type": "contacts.Link" }, { "id": "1504393374", "method": "contacts.deleteContacts", "params": [ { "name": "id", "type": "Vector<InputUser>" } ], "type": "Bool" }, { "id": "858475004", "method": "contacts.block", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-448724803", "method": "contacts.unblock", "params": [ { "name": "id", "type": "InputUser" } ], "type": "Bool" }, { "id": "-176409329", "method": "contacts.getBlocked", "params": [ { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "contacts.Blocked" }, { "id": "-2065352905", "method": "contacts.exportCard", "params": [], "type": "Vector<int>" }, { "id": "1340184318", "method": "contacts.importCard", "params": [ { "name": "export_card", "type": "Vector<int>" } ], "type": "User" }, { "id": "1109588596", "method": "messages.getMessages", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.Messages" }, { "id": "-321970698", "method": "messages.getDialogs", "params": [ { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Dialogs" }, { "id": "-1834885329", "method": "messages.getHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "132772523", "method": "messages.search", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "q", "type": "string" }, { "name": "filter", "type": "MessagesFilter" }, { "name": "min_date", "type": "int" }, { "name": "max_date", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "messages.Messages" }, { "id": "-287800122", "method": "messages.readHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "max_id", "type": "int" }, { "name": "offset", "type": "int" }, { "name": "read_contents", "type": "Bool" } ], "type": "messages.AffectedHistory" }, { "id": "-185009311", "method": "messages.deleteHistory", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "offset", "type": "int" } ], "type": "messages.AffectedHistory" }, { "id": "351460618", "method": "messages.deleteMessages", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "Vector<int>" }, { "id": "682347368", "method": "messages.receivedMessages", "params": [ { "name": "max_id", "type": "int" } ], "type": "Vector<int>" }, { "id": "-1551737264", "method": "messages.setTyping", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "action", "type": "SendMessageAction" } ], "type": "Bool" }, { "id": "1289620139", "method": "messages.sendMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "message", "type": "string" }, { "name": "random_id", "type": "long" } ], "type": "messages.SentMessage" }, { "id": "-1547149962", "method": "messages.sendMedia", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "media", "type": "InputMedia" }, { "name": "random_id", "type": "long" } ], "type": "messages.StatedMessage" }, { "id": "1363988751", "method": "messages.forwardMessages", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "Vector<int>" } ], "type": "messages.StatedMessages" }, { "id": "-820669733", "method": "messages.reportSpam", "params": [ { "name": "peer", "type": "InputPeer" } ], "type": "Bool" }, { "id": "1013621127", "method": "messages.getChats", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "messages.Chats" }, { "id": "998448230", "method": "messages.getFullChat", "params": [ { "name": "chat_id", "type": "int" } ], "type": "messages.ChatFull" }, { "id": "-1262720843", "method": "messages.editChatTitle", "params": [ { "name": "chat_id", "type": "int" }, { "name": "title", "type": "string" } ], "type": "messages.StatedMessage" }, { "id": "-662601187", "method": "messages.editChatPhoto", "params": [ { "name": "chat_id", "type": "int" }, { "name": "photo", "type": "InputChatPhoto" } ], "type": "messages.StatedMessage" }, { "id": "787082910", "method": "messages.addChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" }, { "name": "fwd_limit", "type": "int" } ], "type": "messages.StatedMessage" }, { "id": "-1010447069", "method": "messages.deleteChatUser", "params": [ { "name": "chat_id", "type": "int" }, { "name": "user_id", "type": "InputUser" } ], "type": "messages.StatedMessage" }, { "id": "1100847854", "method": "messages.createChat", "params": [ { "name": "users", "type": "Vector<InputUser>" }, { "name": "title", "type": "string" } ], "type": "messages.StatedMessage" }, { "id": "-304838614", "method": "updates.getState", "params": [], "type": "updates.State" }, { "id": "168039573", "method": "updates.getDifference", "params": [ { "name": "pts", "type": "int" }, { "name": "date", "type": "int" }, { "name": "qts", "type": "int" } ], "type": "updates.Difference" }, { "id": "-285902432", "method": "photos.updateProfilePhoto", "params": [ { "name": "id", "type": "InputPhoto" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "UserProfilePhoto" }, { "id": "-720397176", "method": "photos.uploadProfilePhoto", "params": [ { "name": "file", "type": "InputFile" }, { "name": "caption", "type": "string" }, { "name": "geo_point", "type": "InputGeoPoint" }, { "name": "crop", "type": "InputPhotoCrop" } ], "type": "photos.Photo" }, { "id": "-2016444625", "method": "photos.deletePhotos", "params": [ { "name": "id", "type": "Vector<InputPhoto>" } ], "type": "Vector<long>" }, { "id": "-1291540959", "method": "upload.saveFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "-475607115", "method": "upload.getFile", "params": [ { "name": "location", "type": "InputFileLocation" }, { "name": "offset", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "upload.File" }, { "id": "-990308245", "method": "help.getConfig", "params": [], "type": "Config" }, { "id": "531836966", "method": "help.getNearestDc", "params": [], "type": "NearestDc" }, { "id": "-938300290", "method": "help.getAppUpdate", "params": [ { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" } ], "type": "help.AppUpdate" }, { "id": "1862465352", "method": "help.saveAppLog", "params": [ { "name": "events", "type": "Vector<InputAppEvent>" } ], "type": "Bool" }, { "id": "-1532407418", "method": "help.getInviteText", "params": [ { "name": "lang_code", "type": "string" } ], "type": "help.InviteText" }, { "id": "-1209117380", "method": "photos.getUserPhotos", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "offset", "type": "int" }, { "name": "max_id", "type": "int" }, { "name": "limit", "type": "int" } ], "type": "photos.Photos" }, { "id": "66319602", "method": "messages.forwardMessage", "params": [ { "name": "peer", "type": "InputPeer" }, { "name": "id", "type": "int" }, { "name": "random_id", "type": "long" } ], "type": "messages.StatedMessage" }, { "id": "1102776690", "method": "messages.sendBroadcast", "params": [ { "name": "contacts", "type": "Vector<InputUser>" }, { "name": "message", "type": "string" }, { "name": "media", "type": "InputMedia" } ], "type": "messages.StatedMessages" }, { "id": "651135312", "method": "messages.getDhConfig", "params": [ { "name": "version", "type": "int" }, { "name": "random_length", "type": "int" } ], "type": "messages.DhConfig" }, { "id": "-162681021", "method": "messages.requestEncryption", "params": [ { "name": "user_id", "type": "InputUser" }, { "name": "random_id", "type": "int" }, { "name": "g_a", "type": "bytes" } ], "type": "EncryptedChat" }, { "id": "1035731989", "method": "messages.acceptEncryption", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "g_b", "type": "bytes" }, { "name": "key_fingerprint", "type": "long" } ], "type": "EncryptedChat" }, { "id": "-304536635", "method": "messages.discardEncryption", "params": [ { "name": "chat_id", "type": "int" } ], "type": "Bool" }, { "id": "2031374829", "method": "messages.setEncryptedTyping", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "typing", "type": "Bool" } ], "type": "Bool" }, { "id": "2135648522", "method": "messages.readEncryptedHistory", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "max_date", "type": "int" } ], "type": "Bool" }, { "id": "-1451792525", "method": "messages.sendEncrypted", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "-1701831834", "method": "messages.sendEncryptedFile", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" }, { "name": "file", "type": "InputEncryptedFile" } ], "type": "messages.SentEncryptedMessage" }, { "id": "852769188", "method": "messages.sendEncryptedService", "params": [ { "name": "peer", "type": "InputEncryptedChat" }, { "name": "random_id", "type": "long" }, { "name": "data", "type": "bytes" } ], "type": "messages.SentEncryptedMessage" }, { "id": "1436924774", "method": "messages.receivedQueue", "params": [ { "name": "max_qts", "type": "int" } ], "type": "Vector<long>" }, { "id": "-562337987", "method": "upload.saveBigFilePart", "params": [ { "name": "file_id", "type": "long" }, { "name": "file_part", "type": "int" }, { "name": "file_total_parts", "type": "int" }, { "name": "bytes", "type": "bytes" } ], "type": "Bool" }, { "id": "1769565673", "method": "initConnection", "params": [ { "name": "api_id", "type": "int" }, { "name": "device_model", "type": "string" }, { "name": "system_version", "type": "string" }, { "name": "app_version", "type": "string" }, { "name": "lang_code", "type": "string" }, { "name": "query", "type": "!X" } ], "type": "X" }, { "id": "-1663104819", "method": "help.getSupport", "params": [], "type": "help.Support" }, { "id": "229241832", "method": "auth.sendSms", "params": [ { "name": "phone_number", "type": "string" }, { "name": "phone_code_hash", "type": "string" } ], "type": "Bool" }, { "id": "894131138", "method": "messages.readMessageContents", "params": [ { "name": "id", "type": "Vector<int>" } ], "type": "Vector<int>" }, { "id": "655677548", "method": "account.checkUsername", "params": [ { "name": "username", "type": "string" } ], "type": "Bool" }, { "id": "1040964988", "method": "account.updateUsername", "params": [ { "name": "username", "type": "string" } ], "type": "User" }, { "id": "301470424", "method": "contacts.search", "params": [ { "name": "q", "type": "string" }, { "name": "limit", "type": "int" } ], "type": "contacts.Found" }, { "id": "479200567", "method": "invokeWithLayer18", "params": [ { "name": "query", "type": "!X" } ], "type": "X" } ] }MadelineProto.main flags:# encrypted_layer:int settings:MadelineProto.settings config:Config authorization:flags.0?auth.Authorization authorized:int rsa_keys:Vector<MadelineProto.RSA> last_recv:int dh_config:messages.DhConfig chats:Vector<Chat> last_stored:int qres:Vector<PWR.Chat> pending_updates:Vector<Update> updates_state:MadelineProto.Updates_state got_state:flags.1?true channels_state:MadelineProto.Channel_states updates:Vector<Update> updates_key:int getting_state:flags.2?true full_chats:MadelineProto.FullChat msg_ids:Vector<long> dialog_params:MadelineProto.DialogParams datacenter:MadelineProto.DataCenter v:int constructors:MadelineProto.Constructors td_constructors:flags.3?MadelineProto.Constructors methods:MadelineProto.Methods td_methods:flags.4?MadelineProto.Methods td_descriptions:flags.5?MadelineProto.Descriptions twoe1984:Serialized twoe2047:Serialized twoe2048:Serialized zero:Serialized one:Serialized two:Serialized three:Serialized four:Serialized = MadelineProto.Main; MadelineProto.settings = MadelineProto.Settings; MadelineProto.connection_settings = MadelineProto.Settings; MadelineProto.channel_states = pts:int pending_pts_updates:Vector<Update> sync_loading:Bool MadelineProto.Channel_states; MadelineProto.update_state = pts:int qts:int seq:int date:int pending_seq_updates:Vector<Update> pending_pts_updates:Vector<Update> sync_loading:Bool MadelineProto.Update_state; MadelineProto.rsa e:Serialized n:Serialized fp:string = MadelineProto.RSA; MadelineProto.dialogParams flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = MadelineProto.DialogParams; MadelineProto.dataCenter sockets:Vector<MadelineProto.Connection> curdc:int dclist:Vector<dcOption> settings:MadelineProto.Settings = MadelineProto.DataCenter; MadelineProto.connection flags:# protocol:string ip:string port:int timeout:int parsed:flags.0?MadelineProto.ParsedUrl temp_auth_key:MadelineProto.AuthKey auth_key:MadelineProto.AuthKey ipv6:flags.1?true incoming_messages:Vector<MadelineProto.Messages> outgoing_messages:Vector<MadelineProto.Messages> new_incoming:Vector<long> new_outgoing:Vector<long> MadelineProto.descriptions = MadelineProto.Descriptions; MadelineProto.methods = MadelineProto.Methods; MadelineProto.constructors = MadelineProto.Constructors; MadelineProto.parsedUrl = MadelineProto.ParsedUrl; MadelineProto.authKey server_salt:long id:long auth_key:string = MadelineProto.AuthKey; MadelineProto.messages flags:# seq_no:flags.0?int content:Object response:int = MadelineProto.Messages; pwr.chat flags:# type:string id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string lang_code:flags.3?string username:flags.4?string verified:flags.5?true restricted:flags.6?true restriction_reason:flags.7?string status:flags.8?UserStatus bot_inline_placeholder:flags.9?string about:flags.10?string bot_info:flags.11?BotInfo phone_calls_available:flags.12?true phone_calls_private:flags.13?true common_chats_count:flags.14?int photo:flags.15?string title:flags.16?string participants_count:flags.17?int kicked_count:flags.18?int admin_count:flags.19?int admin:flags.20?true all_members_are_administrators:flags.21?true invite:flags.22?string participants:flags.23?Vector<PWRParticipant> democracy:flags.24?true signatures:flags.25?true can_view_participants:flags.26?true can_set_username:flags.27?true migrated_from_chat_id:flags.28?int migrated_from_max_id:flags.29?int pinned_msg_id:flags.30?int = PWR.Chat; pwr.participant flags:# user:PWR.Chat inviter:flags.0?PWR.Chat date:int role:string = PWR.Participant; //auth.sentCodeMP flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int phone_number:flags.3?string phone_code:flags.4?string = auth.Authorization; //auth.noPasswordMP new_salt:bytes email_unconfirmed_pattern:string = auth.Authorization; //auth.passwordMP current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = auth.Authorization; <?php /** * ResponseException module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class ResponseException extends \Exception { } <?php /** * Methods module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\DocsBuilder; trait Methods { public function mk_methods() { $bots = json_decode(file_get_contents('https://rpc.pwrtelegram.xyz/?bot'), true)['result']; $errors = json_decode(file_get_contents('https://rpc.pwrtelegram.xyz/?all'), true); $errors['result'] = array_merge_recursive(...$errors['result']); foreach (glob('methods/'.$this->any) as $unlink) { unlink($unlink); } if (file_exists('methods')) { rmdir('methods'); } mkdir('methods'); $this->docs_methods = []; $this->human_docs_methods = []; $this->logger->logger('Generating methods documentation...', \danog\MadelineProto\Logger::NOTICE); foreach ($this->methods->by_id as $id => $data) { $method = str_replace('.', '_', $data['method']); $php_method = str_replace('.', '->', $data['method']); $type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']); $php_type = preg_replace('/.*_of_/', '', $type); if (!isset($this->types[$php_type])) { $this->types[$php_type] = ['methods' => [], 'constructors' => []]; } if (!in_array($data, $this->types[$php_type]['methods'])) { $this->types[$php_type]['methods'][] = $data; } $params = ''; foreach ($data['params'] as $param) { if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) { continue; } if ($param['name'] === 'data' && $type === 'messages_SentEncryptedMessage' && !isset($this->settings['td'])) { $param['name'] = 'message'; $param['type'] = 'DecryptedMessage'; } if ($param['name'] === 'chat_id' && $data['method'] !== 'messages.discardEncryption' && !isset($this->settings['td'])) { $param['type'] = 'InputPeer'; } $type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; $type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; $param[$type_or_subtype] = str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]); $param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)'; $params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', '; } if (!isset($this->td_descriptions['methods'][$data['method']])) { $this->add_to_lang('method_'.$data['method']); if (\danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']] !== '') { $this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']]; } } $md_method = '['.$php_method.']('.$method.'.md)'; $this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a> '; if (!isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]) && isset($this->td_descriptions['methods'][$data['method']])) { $this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method']] = '* <a href="'.$method.'.html" name="'.$method.'">'.$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method'].'</a> '; } $params = ''; $lua_params = ''; $pwr_params = ''; $json_params = ''; $table = empty($data['params']) ? '' : '### Parameters: | Name | Type | Required | |----------|---------------|----------| '; if (isset($this->td_descriptions['methods'][$data['method']]) && !empty($data['params'])) { $table = '### Parameters: | Name | Type | Description | Required | |----------|---------------|-------------|----------| '; } $hasentities = false; $hasreplymarkup = false; $hasmessage = false; foreach ($data['params'] as $param) { if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) { continue; } if ($param['name'] === 'data' && $type === 'messages_SentEncryptedMessage' && !isset($this->settings['td'])) { $param['name'] = 'message'; $param['type'] = 'DecryptedMessage'; } if ($param['name'] === 'chat_id' && $data['method'] !== 'messages.discardEncryption' && !isset($this->settings['td'])) { $param['type'] = 'InputPeer'; } if ($param['name'] === 'hash' && $param['type'] === 'int') { $param['pow'] = 'hi'; $param['type'] = 'Vector t'; $param['subtype'] = 'int'; } $ptype = str_replace('.', '_', $param[$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type']); switch ($ptype) { case 'true': case 'false': $ptype = 'Bool'; } $human_ptype = $ptype; if (in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) { $human_ptype = 'Username, chat ID, Update, Message or '.$ptype; } if (in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) { $human_ptype = 'MessageMedia, Update, Message or '.$ptype; } if (in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) { $human_ptype = 'Message ID or '.$ptype; } if (in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) { $human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype; } if (in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) { $human_ptype = 'File path or '.$ptype; } if (in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { $human_ptype = 'File path or '.$ptype; } $type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) { $this->add_to_lang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']); if (isset($this->td_descriptions['methods'][$data['method']]['description'])) { $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']]; } } if (isset($this->td_descriptions['methods'][$data['method']])) { $table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$data['method']]['params'][$param['name']].' | '.(isset($param['pow']) || (($id = $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->constructors->find_by_predicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|'; } else { $table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || (($id = $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty')) && $id['type'] === $param['type']) || (($id = $this->constructors->find_by_predicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type']) ? 'Optional' : 'Yes').'|'; } $table .= PHP_EOL; $pptype = in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype; $ppptype = in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype; $ppptype = in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype; $params .= "'".$param['name']."' => "; $params .= (isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype).', '; $json_params .= '"'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype).', '; $pwr_params .= $param['name'].' - Json encoded '.(isset($param['subtype']) ? ' array of '.$ptype : $ptype)."\n\n"; $lua_params .= $param['name'].'='; $lua_params .= (isset($param['subtype']) ? '{'.$pptype.'}' : $pptype).', '; if ($param['name'] === 'reply_markup') { $hasreplymarkup = true; } if ($param['name'] === 'message') { $hasmessage = true; } if ($param['name'] === 'entities') { $hasentities = true; $table .= '|parse\\_mode| [string](../types/string.md) | Whether to parse HTML or Markdown markup in the message| Optional | '; $params .= "'parse_mode' => 'string', "; $lua_params .= "parse_mode='string', "; $json_params .= '"parse_mode": "string"'; $pwr_params = "parse_mode - string\n"; } } $description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'].' parameters, return type and example'; $header = '--- title: '.$data['method'].' description: '.$description.' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Method: '.str_replace('_', '\\_', $data['method']).' [Back to methods index](index.md) '; if (isset(\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']])) { $header .= '**'.\danog\MadelineProto\MTProto::DISALLOWED_METHODS[$data['method']]."**\n\n\n\n\n"; file_put_contents('methods/'.$method.'.md', $header); continue; } if ($this->td) { $header .= 'YOU CANNOT USE THIS METHOD IN MADELINEPROTO '; } $header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'].PHP_EOL.PHP_EOL : ''; $table .= ' '; $return = '### Return type: ['.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) '; $bot = !in_array($data['method'], $bots); $example = ''; if (!isset($this->settings['td'])) { $example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n"; $example .= str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)): ```php if (!file_exists(\'madeline.php\')) { copy(\'https://phar.madelineproto.xyz/madeline.php\', \'madeline.php\'); } define(\'MADELINE_BRANCH\', \'\'); include \'madeline.php\'; $MadelineProto = new \danog\MadelineProto\API(\'session.madeline\'); $MadelineProto->start(); $'.$type.' = $MadelineProto->'.$php_method.'(['.$params.']); ``` Or, if you\'re into Lua: ```lua '.$type.' = '.$data['method'].'({'.$lua_params.'}) ``` '); if ($hasreplymarkup) { $example .= ' ## Usage of reply_markup You can provide bot API reply_markup objects here. '; } if ($hasmessage) { $example .= ' ## Return value If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead. '; } if ($hasentities) { $example .= ' ## Usage of parse_mode: Set parse_mode to html to enable HTML parsing of the message. Set parse_mode to Markdown to enable markown AND html parsing of the message. The following tags are currently supported: ```html <br>a newline <b><i>bold works ok, internal tags are stripped</i> </b> <strong>bold</strong> <em>italic</em> <i>italic</i> <code>inline fixed-width code</code> <pre>pre-formatted fixed-width code block</pre> <a href="https://github.com">URL</a> <a href="mention:@danogentili">Mention by username</a> <a href="mention:186785362">Mention by user id</a> <pre language="json">Pre tags can have a language attribute</pre> ``` You can also use normal markdown, note that to create mentions you must use the `mention:` syntax like in html: ```markdown [Mention by username](mention:@danogentili) [Mention by user id](mention:186785362) ``` MadelineProto supports all html entities supported by [html_entity_decode](http://php.net/manual/en/function.html-entity-decode.php). '; } if (isset($errors['result'][$data['method']])) { $example .= '### Errors this method can return: | Error | Description | |----------|---------------| '; foreach ($errors['result'][$data['method']] as $error) { $example .= '|'.$error.'|'.$errors['human_result'][$error][0].'|'."\n"; } $example .= "\n\n"; } } file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example); } $this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE); ksort($this->docs_methods); ksort($this->human_docs_methods); $last_namespace = ''; foreach ($this->docs_methods as $method => &$value) { $new_namespace = preg_replace('/_.*/', '', $method); $br = $new_namespace != $last_namespace ? '*** <br><br> ' : ''; $value = $br.$value; $last_namespace = $new_namespace; } file_put_contents('methods/api_'.$this->index, '--- title: Methods description: List of methods image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Methods [Back to API documentation index](..) [Go to the new description-version method index]('.$this->index.') $MadelineProto->[logout](https://docs.madelineproto.xyz/logout.html)(); $MadelineProto->[phone_login](https://docs.madelineproto.xyz/phone_login.html)($number); $MadelineProto->[complete_phone_login](https://docs.madelineproto.xyz/complete_phone_login.html)($code); $MadelineProto->[complete_2FA_login](https://docs.madelineproto.xyz/complete_2FA_login.html)($password); $MadelineProto->[bot_login](https://docs.madelineproto.xyz/bot_login.html)($token); $MadelineProto->[get_dialogs](https://docs.madelineproto.xyz/get_dialogs.html)(); $MadelineProto->[get_pwr_chat](https://docs.madelineproto.xyz/get_pwr_chat.html)($id); $MadelineProto->[get_info](https://docs.madelineproto.xyz/get_info.html)($id); $MadelineProto->[get_full_info](https://docs.madelineproto.xyz/get_full_info.html)($id); $MadelineProto->[get_self](https://docs.madelineproto.xyz/get_self.html)(); $MadelineProto->[request_call](https://docs.madelineproto.xyz/request_call.html)($id); $MadelineProto->[request_secret_chat](https://docs.madelineproto.xyz/request_secret_chat.html)($id); '.implode('', $this->docs_methods)); file_put_contents('methods/'.$this->index, '--- title: Methods description: What do you want to do? image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # What do you want to do? [Go back to API documentation index](..) [Go to the old code-version method index](api_'.$this->index.') * [Logout](https://docs.madelineproto.xyz/logout.html) * [Login](https://docs.madelineproto.xyz/docs/LOGIN.html) * [Change 2FA password](https://docs.madelineproto.xyz/update_2fa.html) * [Get all chats, broadcast a message to all chats](https://docs.madelineproto.xyz/docs/DIALOGS.html) * [Get the full participant list of a channel/group/supergroup](https://docs.madelineproto.xyz/get_pwr_chat.html) * [Get full info about a user/chat/supergroup/channel](https://docs.madelineproto.xyz/get_full_info.html) * [Get info about a user/chat/supergroup/channel](https://docs.madelineproto.xyz/get_info.html) * [Get info about the currently logged-in user](https://docs.madelineproto.xyz/get_self.html) * [Upload or download files up to 1.5 GB](https://docs.madelineproto.xyz/docs/FILES.html) * [Make a phone call and play a song](https://docs.madelineproto.xyz/docs/CALLS.html) * [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html) '.implode('', $this->human_docs_methods)); } } <?php /** * Constructors module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\DocsBuilder; trait Constructors { public function mk_constructors() { foreach (glob('constructors/'.$this->any) as $unlink) { unlink($unlink); } if (file_exists('constructors')) { rmdir('constructors'); } mkdir('constructors'); $this->docs_constructors = []; $this->logger->logger('Generating constructors documentation...', \danog\MadelineProto\Logger::NOTICE); $got = []; foreach ($this->constructors->by_predicate_and_layer as $predicate => $id) { $data = $this->constructors->by_id[$id]; if (isset($got[$id])) { $data['layer'] = ''; } $got[$id] = ''; /* if (preg_match('/%/', $type)) { $type = $this->constructors->find_by_type(str_replace('%', '', $type))['predicate']; }*/ $layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : ''; $type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['type']); $php_type = preg_replace('/.*_of_/', '', $type); $constructor = str_replace(['.', '<', '>'], ['_', '_of_', ''], $data['predicate']); $php_constructor = preg_replace('/.*_of_/', '', $constructor); if (!isset($this->types[$php_type])) { $this->types[$php_type] = ['constructors' => [], 'methods' => []]; } if (!in_array($data, $this->types[$php_type]['constructors'])) { $this->types[$php_type]['constructors'][] = $data; } $params = ''; foreach ($data['params'] as $param) { if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) { continue; } if ($type === 'EncryptedMessage' && $param['name'] === 'bytes' && !isset($this->settings['td'])) { $param['name'] = 'decrypted_message'; $param['type'] = 'DecryptedMessage'; } $type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; $type_or_bare_type = ctype_upper($this->end(explode('.', $param[$type_or_subtype]))[0]) || in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512']) ? 'types' : 'constructors'; $param[$type_or_subtype] = str_replace(['.', 'true', 'false'], ['_', 'Bool', 'Bool'], $param[$type_or_subtype]); if (preg_match('/%/', $param[$type_or_subtype])) { $param[$type_or_subtype] = $this->constructors->find_by_type(str_replace('%', '', $param[$type_or_subtype]))['predicate']; } if (substr($param[$type_or_subtype], -1) === '>') { $param[$type_or_subtype] = substr($param[$type_or_subtype], 0, -1); } $params .= "'".$param['name']."' => "; $param[$type_or_subtype] = '['.$this->escape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)'; $params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', '; } $md_constructor = str_replace('_', '\\_', $constructor.$layer); $this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\];<a name="'.$constructor.$layer.'"></a> '; $table = empty($data['params']) ? '' : '### Attributes: | Name | Type | Required | |----------|---------------|----------| '; if (!isset($this->td_descriptions['constructors'][$data['predicate']])) { $this->add_to_lang('object_'.$data['predicate']); if (\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']] !== '') { $this->td_descriptions['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']]; } } if (isset($this->td_descriptions['constructors'][$data['predicate']]) && !empty($data['params'])) { $table = '### Attributes: | Name | Type | Required | Description | |----------|---------------|----------|-------------| '; } $params = ''; $lua_params = ''; $pwr_params = ''; $hasreplymarkup = false; $hasentities = false; foreach ($data['params'] as $param) { if (in_array($param['name'], ['flags', 'random_id', 'random_bytes'])) { continue; } if ($type === 'EncryptedMessage' && $param['name'] === 'bytes' && !isset($this->settings['td'])) { $param['name'] = 'decrypted_message'; $param['type'] = 'DecryptedMessage'; } if ($type === 'DecryptedMessageMedia' && in_array($param['name'], ['key', 'iv'])) { unset(\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]); continue; } $ptype = str_replace('.', '_', $param[isset($param['subtype']) ? 'subtype' : 'type']); //$type_or_bare_type = 'types'; /*if (isset($param['subtype'])) { if ($param['type'] === 'vector') { $type_or_bare_type = 'constructors'; } }*/ if (preg_match('/%/', $ptype)) { $ptype = $this->constructors->find_by_type(str_replace('%', '', $ptype))['predicate']; } $type_or_bare_type = (ctype_upper($this->end(explode('_', $ptype))[0]) || in_array($ptype, ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int53', 'int', 'long', 'int128', 'int256', 'int512'])) && $ptype !== 'MTmessage' ? 'types' : 'constructors'; if (substr($ptype, -1) === '>') { $ptype = substr($ptype, 0, -1); } switch ($ptype) { case 'true': case 'false': $ptype = 'Bool'; } $human_ptype = $ptype; if (strpos($type, 'Input') === 0 && in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) { $human_ptype = 'Username, chat ID, Update, Message or '.$ptype; } if (strpos($type, 'Input') === 0 && in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) { $human_ptype = 'MessageMedia, Message, Update or '.$ptype; } if (in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) { $human_ptype = 'Message ID or '.$ptype; } if (in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) { $human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype; } if (in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) { $human_ptype = 'File path or '.$ptype; } if (in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { $human_ptype = 'File path or '.$ptype; } $table .= '|'.str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->constructors->find_by_predicate(lcfirst($param['type']).'Empty') || ($data['type'] === 'InputMedia' && $param['name'] === 'mime_type') || ($data['type'] === 'DocumentAttribute' && in_array($param['name'], ['w', 'h', 'duration'])) ? 'Optional' : 'Yes').'|'; if (!isset($this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']])) { $this->add_to_lang('object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']); if (isset($this->td_descriptions['constructors'][$data['predicate']]['description'])) { $this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]; } } if (isset($this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']])) { $table .= $this->td_descriptions['constructors'][$data['predicate']]['params'][$param['name']].'|'; } $table .= PHP_EOL; $pptype = in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype; $ppptype = in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype; $ppptype = in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype; $params .= ", '".$param['name']."' => "; $params .= isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype; $lua_params .= ', '.$param['name'].'='; $lua_params .= isset($param['subtype']) ? '{'.$pptype.'}' : $pptype; $pwr_params .= ', "'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype); if ($param['name'] === 'reply_markup') { $hasreplymarkup = true; } } $params = "['_' => '".$data['predicate']."'".$params.']'; $lua_params = "{_='".$data['predicate']."'".$lua_params.'}'; $pwr_params = '{"_": "'.$data['predicate'].'"'.$pwr_params.'}'; $description = isset($this->td_descriptions['constructors'][$data['predicate']]) ? $this->td_descriptions['constructors'][$data['predicate']]['description'] : $constructor.' attributes, type and example'; $header = '--- title: '.$data['predicate'].' description: '.$description.' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Constructor: '.str_replace('_', '\\_', $data['predicate'].$layer).' [Back to constructors index](index.md) '; $table .= ' '; if (isset($this->td_descriptions['constructors'][$data['predicate']])) { $header .= $this->td_descriptions['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL; } $type = '### Type: ['.str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md) '; $example = ''; if (!isset($this->settings['td'])) { $example = '### Example: ```php $'.$constructor.$layer.' = '.$params.'; ``` Or, if you\'re into Lua: ```lua '.$constructor.$layer.'='.$lua_params.' ``` '; if ($hasreplymarkup) { $example .= ' ## Usage of reply_markup You can provide bot API reply_markup objects here. '; } if ($hasentities) { $example .= ' ## Usage of parse_mode: Set parse_mode to html to enable HTML parsing of the message. Set parse_mode to Markdown to enable markown AND html parsing of the message. The following tags are currently supported: ```html <br>a newline <b><i>bold works ok, internal tags are stripped</i> </b> <strong>bold</strong> <em>italic</em> <i>italic</i> <code>inline fixed-width code</code> <pre>pre-formatted fixed-width code block</pre> <a href="https://github.com">URL</a> <a href="mention:@danogentili">Mention by username</a> <a href="mention:186785362">Mention by user id</a> <pre language="json">Pre tags can have a language attribute</pre> ``` You can also use normal markdown, note that to create mentions you must use the `mention:` syntax like in html: ```markdown [Mention by username](mention:@danogentili) [Mention by user id](mention:186785362) ``` MadelineProto supports all html entities supported by [html_entity_decode](http://php.net/manual/en/function.html-entity-decode.php). '; } } file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example); } $this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE); ksort($this->docs_constructors); $last_namespace = ''; foreach ($this->docs_constructors as $constructor => &$value) { $new_namespace = preg_replace('/_.*/', '', $constructor); $br = $new_namespace != $last_namespace ? '*** <br><br>' : ''; $value = $br.$value; $last_namespace = $new_namespace; } file_put_contents('constructors/'.$this->index, '--- title: Constructors description: List of constructors image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Constructors [Back to API documentation index](..) '.implode('', $this->docs_constructors)); } } <?php /** * TL callback module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; interface TLCallback { const METHOD_CALLBACK = 0; const METHOD_BEFORE_CALLBACK = 1; const CONSTRUCTOR_CALLBACK = 2; const CONSTRUCTOR_BEFORE_CALLBACK = 3; const CONSTRUCTOR_SERIALIZE_CALLBACK = 4; const TYPE_MISMATCH_CALLBACK = 5; public function getMethodCallbacks(): array; public function getMethodBeforeCallbacks(): array; public function getConstructorCallbacks(): array; public function getConstructorBeforeCallbacks(): array; public function getConstructorSerializeCallbacks(): array; public function getTypeMismatchCallbacks(): array; } <?php /** * TL module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; trait TL { public $encrypted_layer = -1; public $constructors; public $methods; public $td_constructors; public $td_methods; public $td_descriptions; public $tl_callbacks = []; public function construct_tl($files, $objects = []) { $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['TL_loading'], \danog\MadelineProto\Logger::VERBOSE); $this->update_callbacks($objects); $this->constructors = new TLConstructor(); $this->methods = new TLMethod(); $this->td_constructors = new TLConstructor(); $this->td_methods = new TLMethod(); $this->td_descriptions = ['types' => [], 'constructors' => [], 'methods' => []]; foreach ($files as $scheme_type => $file) { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['file_parsing'], basename($file)), \danog\MadelineProto\Logger::VERBOSE); $filec = file_get_contents(\danog\MadelineProto\Absolute::absolute($file)); $TL_dict = json_decode($filec, true); if ($TL_dict === null) { $TL_dict = ['methods' => [], 'constructors' => []]; $type = 'constructors'; $layer = null; $tl_file = explode("\n", $filec); $key = 0; $e = null; $class = null; $dparams = []; foreach ($tl_file as $line_number => $line) { $line = rtrim($line); if (preg_match('|^//@|', $line)) { $list = explode(' @', str_replace('//', ' ', $line)); foreach ($list as $elem) { if ($elem === '') { continue; } $elem = explode(' ', $elem, 2); if ($elem[0] === 'class') { $elem = explode(' ', $elem[1], 2); $class = $elem[0]; continue; } if ($elem[0] === 'description') { if (!is_null($class)) { $this->td_descriptions['types'][$class] = $elem[1]; $class = null; } else { $e = $elem[1]; } continue; } if ($elem[0] === 'param_description') { $elem[0] = 'description'; } $dparams[$elem[0]] = $elem[1]; } continue; } $line = preg_replace(['|//.*|', '|^\\s+$|'], '', $line); if ($line === '') { continue; } if ($line === '---functions---') { $type = 'methods'; continue; } if ($line === '---types---') { $type = 'constructors'; continue; } if (preg_match('|^===(\d*)===|', $line, $matches)) { $layer = (int) $matches[1]; continue; } if (strpos($line, 'vector#') === 0) { continue; } if (strpos($line, ' ?= ') !== false) { continue; } $name = preg_replace(['/#.*/', '/\\s.*/'], '', $line); if (in_array($name, ['bytes', 'int128', 'int256', 'int512'])) { continue; } $clean = preg_replace(['/:bytes /', '/;/', '/#[a-f0-9]+ /', '/ [a-zA-Z0-9_]+\\:flags\\.[0-9]+\\?true/', '/[<]/', '/[>]/', '/ /', '/^ /', '/ $/', '/\\?bytes /', '/{/', '/}/'], [':string ', '', ' ', '', ' ', ' ', ' ', '', '', '?string ', '', ''], $line); $id = hash('crc32b', $clean); if (preg_match('/^[^\s]+#([a-f0-9]*)/i', $line, $matches)) { $nid = str_pad($matches[1], 8, '0', \STR_PAD_LEFT); if ($id !== $nid && $scheme_type !== 'botAPI') { $this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['crc32_mismatch'], $id, $nid, $line), \danog\MadelineProto\Logger::ERROR); } $id = $nid; } if (!is_null($e)) { $this->td_descriptions[$type][$name] = ['description' => $e, 'params' => $dparams]; $e = null; $dparams = []; } $TL_dict[$type][$key][$type === 'constructors' ? 'predicate' : 'method'] = $name; $TL_dict[$type][$key]['id'] = strrev(hex2bin($id)); $TL_dict[$type][$key]['params'] = []; $TL_dict[$type][$key]['type'] = preg_replace(['/.+\\s+=\\s+/', '/;/'], '', $line); if ($layer !== null) { $TL_dict[$type][$key]['layer'] = $layer; } if ($name !== 'vector' && $TL_dict[$type][$key]['type'] !== 'Vector t') { foreach (explode(' ', preg_replace(['/^[^\\s]+\\s/', '/=\\s[^\\s]+/', '/\\s$/'], '', $line)) as $param) { if ($param === '') { continue; } if ($param[0] === '{') { continue; } if ($param === '#') { continue; } $explode = explode(':', $param); $TL_dict[$type][$key]['params'][] = ['name' => $explode[0], 'type' => $explode[1]]; } } $key++; } } else { foreach ($TL_dict['constructors'] as $key => $value) { $TL_dict['constructors'][$key]['id'] = $this->pack_signed_int($TL_dict['constructors'][$key]['id']); } foreach ($TL_dict['methods'] as $key => $value) { $TL_dict['methods'][$key]['id'] = $this->pack_signed_int($TL_dict['methods'][$key]['id']); } } if (empty($TL_dict) || empty($TL_dict['constructors']) || !isset($TL_dict['methods'])) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['src_file_invalid'].$file); } $orig = $this->encrypted_layer; $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['translating_obj'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); foreach ($TL_dict['constructors'] as $elem) { if ($scheme_type === 'secret') { $this->encrypted_layer = max($this->encrypted_layer, $elem['layer']); } $this->{($scheme_type === 'td' ? 'td_' : '').'constructors'}->add($elem, $scheme_type); } $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['translating_methods'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); foreach ($TL_dict['methods'] as $elem) { $this->{($scheme_type === 'td' ? 'td_' : '').'methods'}->add($elem); if ($scheme_type === 'secret') { $this->encrypted_layer = max($this->encrypted_layer, $elem['layer']); } } } if (isset($files['td']) && isset($files['telegram'])) { foreach ($this->td_constructors->by_id as $id => $data) { $name = $data['predicate']; if ($this->constructors->find_by_id($id) === false) { unset($this->td_descriptions['constructors'][$name]); } else { if (!count($this->td_descriptions['constructors'][$name]['params'])) { continue; } foreach ($this->td_descriptions['constructors'][$name]['params'] as $k => $param) { $this->td_descriptions['constructors'][$name]['params'][$k] = str_replace('nullable', 'optional', $param); } } } foreach ($this->td_methods->by_id as $id => $data) { $name = $data['method']; if ($this->methods->find_by_id($id) === false) { unset($this->td_descriptions['methods'][$name]); } else { foreach ($this->td_descriptions['methods'][$name]['params'] as $k => $param) { $this->td_descriptions['constructors'][$name]['params'][$k] = str_replace('nullable', 'optional', $param); } } } } } public function get_method_namespaces() { $res = []; foreach ($this->methods->method_namespace as $pair) { $a = key($pair); $res[$a] = $a; } return $res; } public function get_methods_namespaced() { return $this->methods->method_namespace; } public function update_callbacks($objects) { $this->tl_callbacks = []; foreach ($objects as $object) { if (!isset(class_implements(get_class($object))['danog\\MadelineProto\\TL\\TLCallback'])) { throw new Exception('Invalid callback object provided!'); } $new = [ TLCallback::METHOD_BEFORE_CALLBACK => $object->getMethodBeforeCallbacks(), TLCallback::METHOD_CALLBACK => $object->getMethodCallbacks(), TLCallback::CONSTRUCTOR_BEFORE_CALLBACK => $object->getConstructorBeforeCallbacks(), TLCallback::CONSTRUCTOR_CALLBACK => $object->getConstructorCallbacks(), TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK => $object->getConstructorSerializeCallbacks(), TLCallback::TYPE_MISMATCH_CALLBACK => $object->getTypeMismatchCallbacks(), ]; foreach ($new as $type => $values) { foreach ($values as $match => $callback) { if (!isset($this->tl_callbacks[$type][$match])) { $this->tl_callbacks[$type][$match] = []; } if (in_array($type, [TLCallback::TYPE_MISMATCH_CALLBACK, TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK])) { $this->tl_callbacks[$type][$match] = $callback; } else { $this->tl_callbacks[$type][$match] = array_merge($callback, $this->tl_callbacks[$type][$match]); } } } } } public function deserialize_bool($id) { $tl_elem = $this->constructors->find_by_id($id); if ($tl_elem === false) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['bool_error']); } return $tl_elem['predicate'] === 'boolTrue'; } public function serialize_object_async($type, $object, $ctx, $layer = -1) { switch ($type['type']) { case 'int': if (!is_numeric($object)) { if (is_array($object) && $type['name'] === 'hash') { $object = $this->gen_vector_hash($object); } else { throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']); } } return $this->pack_signed_int($object); case '#': if (!is_numeric($object)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']); } return $this->pack_unsigned_int($object); case 'long': if (is_object($object)) { return str_pad(strrev($object->toBytes()), 8, chr(0)); } if (is_string($object) && strlen($object) === 8) { return $object; } if (is_string($object) && strlen($object) === 9 && $object[0] === 'a') { return substr($object, 1); } if (!is_numeric($object)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['not_numeric']); } return $this->pack_signed_long($object); case 'int128': if (strlen($object) !== 16) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_16']); } return (string) $object; case 'int256': if (strlen($object) !== 32) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_32']); } return (string) $object; case 'int512': if (strlen($object) !== 64) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['long_not_64']); } return (string) $object; case 'double': return $this->pack_double($object); case 'string': if (!is_string($object)) { throw new Exception("You didn't provide a valid string"); } $object = pack('C*',...unpack('C*', $object)); $l = strlen($object); $concat = ''; if ($l <= 253) { $concat .= chr($l); $concat .= $object; $concat .= pack('@'.$this->posmod(-$l - 1, 4)); } else { $concat .= chr(254); $concat .= substr($this->pack_signed_int($l), 0, 3); $concat .= $object; $concat .= pack('@'.$this->posmod(-$l, 4)); } return $concat; case 'bytes': if (is_array($object) && isset($object['_']) && $object['_'] === 'bytes') { $object = base64_decode($object['bytes']); } if (!is_string($object) && !$object instanceof \danog\MadelineProto\TL\Types\Bytes) { throw new Exception("You didn't provide a valid string"); } $l = strlen($object); $concat = ''; if ($l <= 253) { $concat .= chr($l); $concat .= $object; $concat .= pack('@'.$this->posmod(-$l - 1, 4)); } else { $concat .= chr(254); $concat .= substr($this->pack_signed_int($l), 0, 3); $concat .= $object; $concat .= pack('@'.$this->posmod(-$l, 4)); } return $concat; case 'Bool': return $this->constructors->find_by_predicate((bool) $object ? 'boolTrue' : 'boolFalse')['id']; case 'true': return; case '!X': return $object; case 'Vector t': if (!is_array($object)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']); } if (isset($object['_'])) { throw new Exception('You must provide an array of '.$type['subtype'].' objects, not a '.$type['subtype']." object. Example: [['_' => ".$type['subtype'].',... ]]'); } $concat = $this->constructors->find_by_predicate('vector')['id']; $concat .= $this->pack_unsigned_int(count($object)); foreach ($object as $k => $current_object) { $concat .= yield $this->serialize_object_async(['type' => $type['subtype']], $current_object, $k); } return $concat; case 'vector': if (!is_array($object)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['array_invalid']); } $concat = $this->pack_unsigned_int(count($object)); foreach ($object as $k => $current_object) { $concat .= yield $this->serialize_object_async(['type' => $type['subtype']], $current_object, $k); } return $concat; case 'Object': if (is_string($object)) { return $object; } } $auto = false; if ($type['type'] === 'InputMessage' && !is_array($object)) { $object = ['_' => 'inputMessageID', 'id' => $object]; } elseif (isset($this->tl_callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]) && (!is_array($object) || isset($object['_']) && $this->constructors->find_by_predicate($object['_'])['type'] !== $type['type'])) { $object = yield $this->tl_callbacks[TLCallback::TYPE_MISMATCH_CALLBACK][$type['type']]($object); if (!isset($object[$type['type']])) { throw new \danog\MadelineProto\Exception("Could not convert {$type['type']} object"); } $object = $object[$type['type']]; } if (!isset($object['_'])) { $constructorData = $this->constructors->find_by_predicate($type['type'], $layer); if ($constructorData === false) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['predicate_not_set']); } $auto = true; $object['_'] = $constructorData['predicate']; } if (isset($this->tl_callbacks[TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK][$object['_']])) { $object = yield $this->tl_callbacks[TLCallback::CONSTRUCTOR_SERIALIZE_CALLBACK][$object['_']]($object); } $predicate = $object['_']; $constructorData = $this->constructors->find_by_predicate($predicate, $layer); if ($constructorData === false) { $this->logger->logger($object, \danog\MadelineProto\Logger::FATAL_ERROR); throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error'], $predicate)); } if ($bare = $type['type'] != '' && $type['type'][0] === '%') { $type['type'] = substr($type['type'], 1); } if ($predicate === $type['type'] && !$auto) { $bare = true; } if ($predicate === 'messageEntityMentionName') { $constructorData = $this->constructors->find_by_predicate('inputMessageEntityMentionName'); } $concat = ''; if (!$bare) { $concat = $constructorData['id']; } return $concat.yield $this->serialize_params_async($constructorData, $object, '', $layer); } public function serialize_method_async($method, $arguments) { if ($method === 'messages.importChatInvite' && isset($arguments['hash']) && is_string($arguments['hash']) && preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['hash'], $matches)) { if ($matches[1] === '') { $method = 'channels.joinChannel'; $arguments['channel'] = $matches[2]; } else { $arguments['hash'] = $matches[2]; } } elseif ($method === 'messages.checkChatInvite' && isset($arguments['hash']) && is_string($arguments['hash']) && preg_match('@(?:t|telegram)\.(?:me|dog)/joinchat/([a-z0-9_-]*)@i', $arguments['hash'], $matches)) { $arguments['hash'] = $matches[1]; } elseif ($method === 'channels.joinChannel' && isset($arguments['channel']) && is_string($arguments['channel']) && preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $arguments['channel'], $matches)) { if ($matches[1] !== '') { $method = 'messages.importChatInvite'; $arguments['hash'] = $matches[2]; } } elseif ($method === 'messages.sendMessage' && isset($arguments['peer']['_']) && $arguments['peer']['_'] === 'inputEncryptedChat') { $method = 'messages.sendEncrypted'; $arguments = ['peer' => $arguments['peer'], 'message' => $arguments]; if (!isset($arguments['message']['_'])) { $arguments['message']['_'] = 'decryptedMessage'; } if (!isset($arguments['message']['ttl'])) { $arguments['message']['ttl'] = 0; } if (isset($arguments['message']['reply_to_msg_id'])) { $arguments['message']['reply_to_random_id'] = $arguments['message']['reply_to_msg_id']; } } elseif ($method === 'messages.sendEncryptedFile') { if (isset($arguments['file'])) { if (!is_array($arguments['file']) && $this->settings['upload']['allow_automatic_upload']) { $arguments['file'] = yield $this->upload_encrypted_async($arguments['file']); } if (isset($arguments['file']['key'])) { $arguments['message']['media']['key'] = $arguments['file']['key']; } if (isset($arguments['file']['iv'])) { $arguments['message']['media']['iv'] = $arguments['file']['iv']; } } } elseif (in_array($method, ['messages.addChatUser', 'messages.deleteChatUser', 'messages.editChatAdmin', 'messages.editChatPhoto', 'messages.editChatTitle', 'messages.getFullChat', 'messages.exportChatInvite', 'messages.editChatAdmin', 'messages.migrateChat']) && isset($arguments['chat_id']) && (!is_numeric($arguments['chat_id']) || $arguments['chat_id'] < 0)) { $res = yield $this->get_info_async($arguments['chat_id']); if ($res['type'] !== 'chat') { throw new \danog\MadelineProto\Exception('chat_id is not a chat id (only normal groups allowed, not supergroups)!'); } $arguments['chat_id'] = $res['chat_id']; } elseif ($method === 'photos.updateProfilePhoto') { if (isset($arguments['id'])) { if (!is_array($arguments['id'])) { $method = 'photos.uploadProfilePhoto'; $arguments['file'] = $arguments['id']; } } elseif (isset($arguments['file'])) { $method = 'photos.uploadProfilePhoto'; } } elseif ($method === 'photos.uploadProfilePhoto') { if (isset($arguments['file'])) { if (is_array($arguments['file']) && !in_array($arguments['file']['_'], ['inputFile', 'inputFileBig'])) { $method = 'photos.uploadProfilePhoto'; $arguments['id'] = $arguments['file']; } } elseif (isset($arguments['id'])) { $method = 'photos.updateProfilePhoto'; } } $tl = $this->methods->find_by_method($method); if ($tl === false) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['method_not_found'].$method); } return $tl['id'].yield $this->serialize_params_async($tl, $arguments, $method); } public function serialize_params_async($tl, $arguments, $ctx, $layer = -1) { $serialized = ''; $arguments = yield $this->botAPI_to_MTProto_async($arguments); $flags = 0; foreach ($tl['params'] as $cur_flag) { if (isset($cur_flag['pow'])) { switch ($cur_flag['type']) { case 'true': case 'false': $flags = isset($arguments[$cur_flag['name']]) && $arguments[$cur_flag['name']] ? $flags | $cur_flag['pow'] : $flags & ~$cur_flag['pow']; unset($arguments[$cur_flag['name']]); break; case 'Bool': $arguments[$cur_flag['name']] = isset($arguments[$cur_flag['name']]) && $arguments[$cur_flag['name']] && ($flags & $cur_flag['pow']) != 0; if (($flags & $cur_flag['pow']) === 0) { unset($arguments[$cur_flag['name']]); } break; default: $flags = isset($arguments[$cur_flag['name']]) && $arguments[$cur_flag['name']] !== null ? $flags | $cur_flag['pow'] : $flags & ~$cur_flag['pow']; break; } } } $arguments['flags'] = $flags; foreach ($tl['params'] as $current_argument) { if (!isset($arguments[$current_argument['name']])) { if (isset($current_argument['pow']) && (in_array($current_argument['type'], ['true', 'false']) || ($flags & $current_argument['pow']) === 0)) { //$this->logger->logger('Skipping '.$current_argument['name'].' of type '.$current_argument['type'); continue; } if ($current_argument['name'] === 'random_bytes') { $serialized .= yield $this->serialize_object_async(['type' => 'bytes'], $this->random(15 + 4 * $this->random_int($modulus = 3)), 'random_bytes'); continue; } if ($current_argument['name'] === 'data' && isset($tl['method']) && in_array($tl['method'], ['messages.sendEncrypted', 'messages.sendEncryptedFile', 'messages.sendEncryptedService']) && isset($arguments['message'])) { $serialized .= yield $this->serialize_object_async($current_argument, yield $this->encrypt_secret_message_async($arguments['peer']['chat_id'], $arguments['message']), 'data'); continue; } if ($current_argument['name'] === 'random_id') { switch ($current_argument['type']) { case 'long': $serialized .= $this->random(8); continue 2; case 'int': $serialized .= $this->random(4); continue 2; case 'Vector t': if (isset($arguments['id'])) { $serialized .= $this->constructors->find_by_predicate('vector')['id']; $serialized .= $this->pack_unsigned_int(count($arguments['id'])); $serialized .= $this->random(8 * count($arguments['id'])); continue 2; } } } if ($current_argument['name'] === 'hash' && $current_argument['type'] === 'int') { $serialized .= pack('@4'); continue; } if ($tl['type'] === 'InputMedia' && $current_argument['name'] === 'mime_type') { $serialized .= yield $this->serialize_object_async($current_argument, $arguments['file']['mime_type'], $current_argument['name'], $layer); continue; } if ($tl['type'] === 'DocumentAttribute' && in_array($current_argument['name'], ['w', 'h', 'duration'])) { $serialized .= pack('@4'); continue; } if (in_array($current_argument['type'], ['bytes', 'string', 'Vector t'])) { $serialized .= pack('@4'); continue; } if (($id = $this->constructors->find_by_predicate(lcfirst($current_argument['type']).'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) { $serialized .= $id['id']; continue; } if (($id = $this->constructors->find_by_predicate('input'.$current_argument['type'].'Empty', isset($tl['layer']) ? $tl['layer'] : -1)) && $id['type'] === $current_argument['type']) { $serialized .= $id['id']; continue; } throw new Exception(\danog\MadelineProto\Lang::$current_lang['params_missing'], $current_argument['name']); } if (in_array($current_argument['type'], ['DataJSON', '%DataJSON'])) { $arguments[$current_argument['name']] = ['_' => 'dataJSON', 'data' => json_encode($arguments[$current_argument['name']])]; } if (isset($current_argument['subtype']) && in_array($current_argument['subtype'], ['DataJSON', '%DataJSON'])) { array_walk($arguments[$current_argument['name']], function (&$arg) { $arg = ['_' => 'dataJSON', 'data' => json_encode($arg)]; }); } if (!is_array($arguments[$current_argument['name']]) && $current_argument['type'] === 'InputFile' && $this->settings['upload']['allow_automatic_upload']) { $arguments[$current_argument['name']] = yield $this->upload_async($arguments[$current_argument['name']]); } if ($current_argument['type'] === 'InputEncryptedChat' && (!is_array($arguments[$current_argument['name']]) || isset($arguments[$current_argument['name']]['_']) && $this->constructors->find_by_predicate($arguments[$current_argument['name']]['_'])['type'] !== $current_argument['type'])) { if (is_array($arguments[$current_argument['name']])) { $arguments[$current_argument['name']] = (yield $this->get_info_async($arguments[$current_argument['name']]))['InputEncryptedChat']; } else { if (!isset($this->secret_chats[$arguments[$current_argument['name']]])) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['sec_peer_not_in_db']); } $arguments[$current_argument['name']] = $this->secret_chats[$arguments[$current_argument['name']]]['InputEncryptedChat']; } } //$this->logger->logger('Serializing '.$current_argument['name'].' of type '.$current_argument['type'); $serialized .= yield $this->serialize_object_async($current_argument, $arguments[$current_argument['name']], $current_argument['name'], $layer); } return $serialized; } public function get_length($stream, $type = ['type' => '']) { if (is_string($stream)) { $res = fopen('php://memory', 'rw+b'); fwrite($res, $stream); fseek($res, 0); $stream = $res; } elseif (!is_resource($stream)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']); } $this->deserialize($stream, $type); return ftell($stream); } /** * :type stream: io.BytesIO object. */ public function deserialize($stream, $type = ['type' => '']) { if (is_string($stream)) { $res = fopen('php://memory', 'rw+b'); fwrite($res, $stream); fseek($res, 0); $stream = $res; } elseif (!is_resource($stream)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']); } switch ($type['type']) { case 'Bool': return $this->deserialize_bool(stream_get_contents($stream, 4)); case 'int': return $this->unpack_signed_int(stream_get_contents($stream, 4)); case '#': return unpack('V', stream_get_contents($stream, 4))[1]; case 'long': if (isset($type['idstrlong'])) { return stream_get_contents($stream, 8); } return \danog\MadelineProto\Magic::$bigint || isset($type['strlong']) ? stream_get_contents($stream, 8) : $this->unpack_signed_long(stream_get_contents($stream, 8)); case 'double': return $this->unpack_double(stream_get_contents($stream, 8)); case 'int128': return stream_get_contents($stream, 16); case 'int256': return stream_get_contents($stream, 32); case 'int512': return stream_get_contents($stream, 64); case 'string': case 'bytes': $l = ord(stream_get_contents($stream, 1)); if ($l > 254) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['length_too_big']); } if ($l === 254) { $long_len = unpack('V', stream_get_contents($stream, 3).chr(0))[1]; $x = stream_get_contents($stream, $long_len); $resto = $this->posmod(-$long_len, 4); if ($resto > 0) { stream_get_contents($stream, $resto); } } else { $x = $l ? stream_get_contents($stream, $l) : ''; $resto = $this->posmod(-($l + 1), 4); if ($resto > 0) { stream_get_contents($stream, $resto); } } if (!is_string($x)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialize_not_str']); } return $type['type'] === 'bytes' ? new Types\Bytes($x) : $x; case 'Vector t': $id = stream_get_contents($stream, 4); $constructorData = $this->constructors->find_by_id($id); if ($constructorData === false) { $constructorData = $this->methods->find_by_id($id); $constructorData['predicate'] = 'method_'.$constructorData['method']; } if ($constructorData === false) { throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id)))); } switch ($constructorData['predicate']) { case 'gzip_packed': return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes', 'datacenter' => $type['datacenter']])), ['type' => '', 'datacenter' => $type['datacenter']]); case 'Vector t': case 'vector': break; default: throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'].$constructorData['predicate']); } case 'vector': $count = unpack('V', stream_get_contents($stream, 4))[1]; $result = []; $type['type'] = $type['subtype']; for ($i = 0; $i < $count; $i++) { $result[] = $this->deserialize($stream, $type); } return $result; } if ($type['type'] != '' && $type['type'][0] === '%') { $checkType = substr($type['type'], 1); $constructorData = $this->constructors->find_by_type($checkType); if ($constructorData === false) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'].$checkType); } } else { $constructorData = $this->constructors->find_by_predicate($type['type']); if ($constructorData === false) { $id = stream_get_contents($stream, 4); $constructorData = $this->constructors->find_by_id($id); if ($constructorData === false) { $constructorData = $this->methods->find_by_id($id); if ($constructorData === false) { throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id)))); } $constructorData['predicate'] = 'method_'.$constructorData['method']; } } } if ($constructorData['predicate'] === 'gzip_packed') { if (!isset($type['subtype'])) { $type['subtype'] = ''; } return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'datacenter' => $type['datacenter'], 'subtype' => $type['subtype']]); } if ($constructorData['type'] === 'Vector t') { $constructorData['datacenter'] = $type['datacenter']; $constructorData['subtype'] = isset($type['subtype']) ? $type['subtype'] : ''; $constructorData['type'] = 'vector'; return $this->deserialize($stream, $constructorData); } if ($constructorData['predicate'] === 'boolTrue') { return true; } if ($constructorData['predicate'] === 'boolFalse') { return false; } $x = ['_' => $constructorData['predicate']]; if (isset($this->tl_callbacks[TLCallback::CONSTRUCTOR_BEFORE_CALLBACK][$x['_']])) { foreach ($this->tl_callbacks[TLCallback::CONSTRUCTOR_BEFORE_CALLBACK][$x['_']] as $callback) { $callback($x['_']); } } foreach ($constructorData['params'] as $arg) { if (isset($arg['pow'])) { switch ($arg['type']) { case 'true': case 'false': $x[$arg['name']] = ($x['flags'] & $arg['pow']) !== 0; continue 2; case 'Bool': if (($x['flags'] & $arg['pow']) === 0) { $x[$arg['name']] = false; continue 2; } default: if (($x['flags'] & $arg['pow']) === 0) { continue 2; } } } if (in_array($arg['name'], ['msg_ids', 'msg_id', 'bad_msg_id', 'req_msg_id', 'answer_msg_id', 'first_msg_id'])) { $arg['idstrlong'] = true; } if (in_array($arg['name'], ['key_fingerprint', 'server_salt', 'new_server_salt', 'server_public_key_fingerprints', 'ping_id', 'exchange_id'])) { $arg['strlong'] = true; } if (in_array($arg['name'], ['peer_tag', 'file_token', 'cdn_key', 'cdn_iv'])) { $arg['type'] = 'string'; } if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') { if (isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']) && isset($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']]) ) { foreach ($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']] as $callback) { $callback($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']); } } if (isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type']) && stripos($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false ) { $arg['subtype'] = str_replace(['Vector<', '>'], '', $this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type']); } } if (isset($type['datacenter'])) { $arg['datacenter'] = $type['datacenter']; } $x[$arg['name']] = $this->deserialize($stream, $arg); if ($arg['name'] === 'random_bytes') { if (strlen($x[$arg['name']]) < 15) { throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_small']); } else { unset($x[$arg['name']]); } } } if (isset($x['flags'])) { // I don't think we need this anymore unset($x['flags']); } if ($x['_'] === 'dataJSON') { return json_decode($x['data'], true); } elseif ($constructorData['type'] === 'JSONValue') { switch ($x['_']) { case 'jsonNull': return; case 'jsonObject': $res = []; foreach ($x['value'] as $pair) { $res[$pair['key']] = $pair['value']; } return $res; default: return $x['value']; } } if (isset($this->tl_callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']])) { foreach ($this->tl_callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']] as $callback) { $this->callFork($callback($x)); } } elseif ($x['_'] === 'rpc_result' && isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']) && isset($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']]) ) { foreach ($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']] as $callback) { $callback($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']], $x['result']); } } if ($x['_'] === 'message' && isset($x['reply_markup']['rows'])) { foreach ($x['reply_markup']['rows'] as $key => $row) { foreach ($row['buttons'] as $bkey => $button) { $x['reply_markup']['rows'][$key]['buttons'][$bkey] = new Types\Button($this, $x, $button); } } } return $x; } } <?php /** * Button module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL\Types; class Button implements \JsonSerializable, \ArrayAccess { use \danog\Serializable; use \danog\MadelineProto\Tools; private $info = []; private $data = []; public function __magic_construct($API, $message, $button) { $this->data = $button; $this->info['peer'] = $message['to_id'] === ['_' => 'peerUser', 'user_id' => $API->authorization['user']['id']] ? $message['from_id'] : $message['to_id']; $this->info['id'] = $message['id']; $this->info['API'] = $API; } public function __sleep() { return ['data', 'info']; } public function click($donotwait = false, $params = []) { if (is_array($donotwait)) { $async = $donotwait; } else { $async = $params; } $async = isset($async['async']) ? $async['async'] : (isset($this->info['API']->wrapper) ? $this->info['API']->wrapper->async : true); $method = $donotwait === true ? 'method_call_async_write' : 'method_call_async_read'; switch ($this->data['_']) { default: return false; case 'keyboardButtonUrl': return $this->data['url']; case 'keyboardButton': $res = $this->info['API']->method_call_async_read('messages.sendMessage', ['peer' => $this->info['peer'], 'message' => $this->data['text'], 'reply_to_msg_id' => $this->info['id']], ['datacenter' => $this->info['API']->datacenter->curdc]); break; case 'keyboardButtonCallback': $res = $this->info['API']->$method('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'data' => $this->data['data']], ['datacenter' => $this->info['API']->datacenter->curdc]); break; case 'keyboardButtonGame': $res = $this->info['API']->$method('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['datacenter' => $this->info['API']->datacenter->curdc]); break; } return $async ? $res : $this->wait($res); } public function __debugInfo() { return ['data' => $this->data, 'info' => ['peer' => $this->info['peer'], 'id' => $this->info['id']]]; } public function jsonSerialize() { return (array) $this->data; } public function offsetSet($name, $value) { if ($name === null) { $this->data[] = $value; } else { $this->data[$name] = $value; } } public function offsetGet($name) { return $this->data[$name]; } public function offsetUnset($name) { unset($this->data[$name]); } public function offsetExists($name) { return isset($this->data[$name]); } } <?php /** * Bytes module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL\Types; class Bytes implements \JsonSerializable { use \danog\Serializable; private $bytes = []; public function __magic_construct($bytes) { $this->bytes = $bytes; } public function __sleep() { return ['bytes']; } public function __toString() { return $this->bytes; } public function jsonSerialize() { return ['_' => 'bytes', 'bytes' => base64_encode($this->bytes)]; } } <?php /** * TLParams module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; trait TLParams { public function parse_params($key, $mtproto = false) { foreach ($this->by_id[$key]['params'] as $kkey => $param) { if (preg_match('/(\w*)\.(\d*)\?(.*)/', $param['type'], $matches)) { $param['pow'] = pow(2, $matches[2]); $param['type'] = $matches[3]; } if (preg_match('/^(v|V)ector\<(.*)\>$/', $param['type'], $matches)) { $param['type'] = $matches[1] === 'v' ? 'vector' : 'Vector t'; $param['subtype'] = $matches[2]; $param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '').$param['subtype']; $param['subtype'] = $mtproto && $param['subtype'] === '%Message' ? '%MTMessage' : $param['subtype']; } $param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '').$param['type']; $param['type'] = $mtproto && $param['type'] === '%Message' ? '%MTMessage' : $param['type']; $this->by_id[$key]['params'][$kkey] = $param; } } } <?php /** * PrettyException module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; trait PrettyException { public $tl_trace; public function getTLTrace() { return $this->tl_trace; } public function prettify_tl($init = '') { $eol = PHP_EOL; if (php_sapi_name() !== 'cli') { $eol = '<br>'.PHP_EOL; } $tl = false; foreach (array_reverse($this->getTrace()) as $k => $frame) { if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) { if ($frame['args'][2] !== '') { $this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2]; $tl = true; } } else { if ($tl) { $this->tl_trace .= $eol; } if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') { continue; } $this->tl_trace .= isset($frame['file']) ? str_pad(basename($frame['file']).'('.$frame['line'].'):', 20)."\t" : ''; $this->tl_trace .= isset($frame['function']) ? $frame['function'].'(' : ''; $this->tl_trace .= isset($frame['args']) ? substr(json_encode($frame['args']), 1, -1) : ''; $this->tl_trace .= ')'; $this->tl_trace .= $eol; $tl = false; } } $this->tl_trace .= $init !== '' ? "['".$init."']" : ''; $this->tl_trace = implode($eol, array_reverse(explode($eol, $this->tl_trace))); } } <?php /** * TLConstructor module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; class TLConstructor { use \danog\Serializable; use \danog\MadelineProto\Tools; use TLParams; public $by_id = []; public $by_predicate_and_layer = []; public $layers = []; public function __sleep() { return ['by_predicate_and_layer', 'by_id', 'layers']; } public function add($json_dict, $scheme_type) { if (isset($this->by_id[$json_dict['id']]) && (!isset($this->by_id[$json_dict['id']]['layer']) || $this->by_id[$json_dict['id']]['layer'] > $json_dict['layer'])) { return false; } $predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '').$json_dict['predicate']); $this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '').$json_dict['type']]; if ($scheme_type === 'secret') { $this->by_id[$json_dict['id']]['layer'] = $json_dict['layer']; $this->layers[$json_dict['layer']] = $json_dict['layer']; ksort($this->layers); } else { $json_dict['layer'] = ''; } $this->by_predicate_and_layer[$predicate.$json_dict['layer']] = $json_dict['id']; $this->parse_params($json_dict['id'], $scheme_type === 'mtproto'); } public function find_by_type($type) { foreach ($this->by_id as $id => $constructor) { if ($constructor['type'] === $type) { $constructor['id'] = $id; return $constructor; } } return false; } public function find_by_predicate($predicate, $layer = -1) { if ($layer !== -1) { foreach ($this->layers as $alayer) { if ($alayer <= $layer) { if (isset($this->by_predicate_and_layer[$predicate.$alayer])) { $chosenid = $this->by_predicate_and_layer[$predicate.$alayer]; } } elseif (!isset($chosenid)) { $chosenid = $this->by_predicate_and_layer[$predicate.$alayer]; } } if (!isset($chosenid)) { return false; } $constructor = $this->by_id[$chosenid]; $constructor['id'] = $chosenid; return $constructor; } if (isset($this->by_predicate_and_layer[$predicate])) { $constructor = $this->by_id[$this->by_predicate_and_layer[$predicate]]; $constructor['id'] = $this->by_predicate_and_layer[$predicate]; return $constructor; } return false; } public function find_by_id($id) { if (isset($this->by_id[$id])) { $constructor = $this->by_id[$id]; $constructor['id'] = $id; return $constructor; } return false; } } <?php /** * TD module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL\Conversion; trait TD { public function tdcli_to_td(&$params, $key = null) { if (!is_array($params)) { return $params; } if (!isset($params['ID'])) { array_walk($params, [$this, 'tdcli_to_td']); return $params; } foreach ($params as $key => $value) { $value = $this->tdcli_to_td($value); if (preg_match('/_$/', $key)) { $params[preg_replace('/_$/', '', $key)] = $value; unset($params[$key]); } } $params['_'] = lcfirst($params['ID']); unset($params['ID']); return $params; } public function td_to_mtproto_async($params) { $newparams = ['_' => self::REVERSE[$params['_']]]; foreach (self::TD_PARAMS_CONVERSION[$newparams['_']] as $td => $mtproto) { if (is_array($mtproto)) { switch (end($mtproto)) { case 'choose_message_content': switch ($params[$td]['_']) { case 'inputMessageText': $params[$td]['_'] = 'messages.sendMessage'; if (isset($params['disable_web_page_preview'])) { $newparams['no_webpage'] = $params[$td]['disable_web_page_preview']; } $newparams = array_merge($params[$td], $newparams); break; default: throw new Exception(\danog\MadelineProto\Lang::$current_lang['non_text_conversion']); } break; default: $newparams[$mtproto[0]] = isset($params[$td]) ? $params[$td] : null; if (is_array($newparams[$mtproto[0]])) { $newparams[$mtproto[0]] = yield $this->mtproto_to_td_async($newparams[$mtproto[0]]); } } } } return $newparams; } public function mtproto_to_tdcli_async($params) { return $this->td_to_tdcli(yield $this->mtproto_to_td_async($params)); } public function mtproto_to_td_async(&$params) { if (!is_array($params)) { return $params; } if (!isset($params['_'])) { array_walk($params, [$this, 'mtproto_to_td']); return $params; } $newparams = ['_' => $params['_']]; if (in_array($params['_'], self::TD_IGNORE)) { return $params; } foreach (self::TD_PARAMS_CONVERSION[$params['_']] as $td => $mtproto) { if (is_string($mtproto)) { $newparams[$td] = $mtproto; } else { switch (end($mtproto)) { case 'choose_chat_id_from_botapi': $newparams[$td] = (yield $this->get_info_async($params[$mtproto[0]]))['bot_api_id'] == $this->authorization['user']['id'] ? $params['from_id'] : yield $this->get_info_async($params[$mtproto[0]])['bot_api_id']; break; case 'choose_incoming_or_sent': $newparams[$td] = ['_' => $params['out'] ? 'messageIsSuccessfullySent' : 'messageIsIncoming']; break; case 'choose_can_edit': $newparams[$td] = !isset($params['fwd_from']) && $params['out']; break; case 'choose_can_delete': $newparams[$td] = $params['out']; break; case 'choose_forward_info': if (isset($params['fwd_from'])) { $newparams[$td] = ['_' => 'messageForwardedFromUser']; if (isset($params['fwd_from']['channel_id'])) { $newparams[$td] = ['_' => 'messageForwardedPost', 'chat_id' => '-100'.$params['fwd_from']['channel_id']]; } $newparams[$td]['date'] = $params['fwd_from']['date']; if (isset($params['fwd_from']['channel_post'])) { $newparams[$td]['channel_post'] = $params['fwd_from']['channel_post']; } if (isset($params['fwd_from']['from_id'])) { $newparams[$td]['sender_user_id'] = $params['fwd_from']['from_id']; } } else { $newparams[$td] = null; } break; case 'choose_ttl': $newparams[$td] = isset($params['ttl']) ? $params['ttl'] : 0; break; case 'choose_ttl_expires_in': $newparams[$td] = $newparams['ttl'] - microtime(true); break; case 'choose_message_content': if ($params['message'] !== '') { $newparams[$td] = ['_' => 'messageText', 'text' => $params['message']]; if (isset($params['media']['_']) && $params['media']['_'] === 'messageMediaWebPage') { $newparams[$td]['web_page'] = yield $this->mtproto_to_td_async($params['media']['webpage']); } if (isset($params['entities'])) { $newparams[$td]['entities'] = $params['entities']; } } else { throw new Exception(\danog\MadelineProto\Lang::$current_lang['non_text_conversion']); } break; default: if (isset($mtproto[1])) { $newparams[$td] = isset($params[$mtproto[0]][$mtproto[1]]) ? $params[$mtproto[0]][$mtproto[1]] : null; } else { $newparams[$td] = isset($params[$mtproto[0]]) ? $params[$mtproto[0]] : null; } if (is_array($newparams[$td])) { $newparams[$td] = yield $this->mtproto_to_td_async($newparams[$td]); } } } } return $newparams; } public function td_to_tdcli($params) { if (!is_array($params)) { return $params; } $newparams = []; foreach ($params as $key => $value) { if ($key === '_') { $newparams['ID'] = ucfirst($value); } else { if (!is_numeric($key) && !preg_match('/_^/', $key)) { $key = $key.'_'; } $newparams[$key] = $this->td_to_tdcli($value); } } return $newparams; } } <?php /** * BotAPIFiles module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL\Conversion; trait BotAPIFiles { public function base64url_decode($data) { return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); } public function base64url_encode($data) { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } public function rle_decode($string) { $new = ''; $last = ''; $null = chr(0); foreach (str_split($string) as $cur) { if ($last === $null) { $new .= str_repeat($last, ord($cur)); $last = ''; } else { $new .= $last; $last = $cur; } } $string = $new.$last; return $string; } public function rle_encode($string) { $new = ''; $count = 0; $null = chr(0); foreach (str_split($string) as $cur) { if ($cur === $null) { $count++; } else { if ($count > 0) { $new .= $null.chr($count); $count = 0; } $new .= $cur; } } return $new; } public function photosize_to_botapi_async($photoSize, $photo, $thumbnail = false) { $ext = $this->get_extension_from_location(['_' => 'inputFileLocation', 'volume_id' => $photoSize['location']['volume_id'], 'local_id' => $photoSize['location']['local_id'], 'secret' => $photoSize['location']['secret'], 'dc_id' => $photoSize['location']['dc_id']], '.jpg'); $photoSize['location']['access_hash'] = isset($photo['access_hash']) ? $photo['access_hash'] : 0; $photoSize['location']['id'] = isset($photo['id']) ? $photo['id'] : 0; $photoSize['location']['_'] = $thumbnail ? 'bot_thumbnail' : 'bot_photo'; $data = (yield $this->serialize_object_async(['type' => 'File'], $photoSize['location'], 'File')).chr(2); return ['file_id' => $this->base64url_encode($this->rle_encode($data)), 'width' => $photoSize['w'], 'height' => $photoSize['h'], 'file_size' => isset($photoSize['size']) ? $photoSize['size'] : strlen($photoSize['bytes']), 'mime_type' => 'image/jpeg', 'file_name' => $photoSize['location']['volume_id'].'_'.$photoSize['location']['local_id'].$ext]; } public function unpack_file_id($file_id) { $file_id = $this->rle_decode($this->base64url_decode($file_id)); if ($file_id[strlen($file_id) - 1] !== chr(2)) { throw new Exception(\danog\MadelineProto\Lang::$current_lang['last_byte_invalid']); } $deserialized = $this->deserialize($file_id); $res = ['type' => str_replace('bot_', '', $deserialized['_'])]; switch ($deserialized['_']) { case 'bot_thumbnail': case 'bot_photo': $constructor = ['_' => 'photo', 'sizes' => []]; $constructor['id'] = $deserialized['id']; $constructor['access_hash'] = $deserialized['access_hash']; unset($deserialized['id']); unset($deserialized['access_hash']); unset($deserialized['_']); $deserialized['_'] = 'fileLocation'; $constructor['sizes'][0] = ['_' => 'photoSize', 'location' => $deserialized]; $res['MessageMedia'] = ['_' => 'messageMediaPhoto', 'photo' => $constructor, 'caption' => '']; return $res; case 'bot_voice': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; case 'bot_video': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => false]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; case 'bot_video_note': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeVideo', 'round_message' => true]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; case 'bot_document': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => []]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; case 'bot_sticker': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeSticker']]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; case 'bot_gif': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAnimated']]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; case 'bot_audio': unset($deserialized['_']); $constructor = array_merge($deserialized, ['_' => 'document', 'mime_type' => '', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false]]]); $res['MessageMedia'] = ['_' => 'messageMediaDocument', 'document' => $constructor, 'caption' => '']; return $res; default: throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['file_type_invalid'], $type)); } } } <?php /** * BotAPI module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL\Conversion; use danog\MadelineProto\Logger; trait BotAPI { public function html_entity_decode($stuff) { return html_entity_decode(preg_replace('#< *br */? *>#', "\n", $stuff)); } public function mb_strlen($text) { $length = 0; $textlength = strlen($text); for ($x = 0; $x < $textlength; $x++) { $char = ord($text[$x]); if (($char & 0xC0) != 0x80) { $length += 1 + ($char >= 0xf0); } } return $length; } public function mb_substr($text, $offset, $length = null) { $mb_text_length = $this->mb_strlen($text); if ($offset < 0) { $offset = $mb_text_length + $offset; } if ($length < 0) { $length = ($mb_text_length - $offset) + $length; } elseif ($length === null) { $length = $mb_text_length - $offset; } $new_text = ''; $current_offset = 0; $current_length = 0; $text_length = strlen($text); for ($x = 0; $x < $text_length; $x++) { $char = ord($text[$x]); if (($char & 0xC0) != 0x80) { $current_offset += 1 + ($char >= 0xf0); if ($current_offset > $offset) { $current_length += 1 + ($char >= 0xf0); } } if ($current_offset > $offset) { if ($current_length <= $length) { $new_text .= $text[$x]; } } } return $new_text; } public function mb_str_split($text, $length) { $tlength = mb_strlen($text, 'UTF-8'); $result = []; for ($x = 0; $x < $tlength; $x += $length) { $result[] = mb_substr($text, $x, $length, 'UTF-8'); } return $result; } public function parse_buttons($rows) { $newrows = []; $key = 0; $button_key = 0; foreach ($rows as $row) { $newrows[$key] = ['_' => 'keyboardButtonRow', 'buttons' => []]; foreach ($row as $button) { $newrows[$key]['buttons'][$button_key] = ['_' => 'keyboardButton', 'text' => $button['text']]; if (isset($button['url'])) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonUrl'; $newrows[$key]['buttons'][$button_key]['url'] = $button['url']; } elseif (isset($button['callback_data'])) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonCallback'; $newrows[$key]['buttons'][$button_key]['data'] = $button['callback_data']; } elseif (isset($button['switch_inline_query'])) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonSwitchInline'; $newrows[$key]['buttons'][$button_key]['same_peer'] = false; $newrows[$key]['buttons'][$button_key]['query'] = $button['switch_inline_query']; } elseif (isset($button['switch_inline_query_current_chat'])) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonSwitchInline'; $newrows[$key]['buttons'][$button_key]['same_peer'] = true; $newrows[$key]['buttons'][$button_key]['query'] = $button['switch_inline_query_current_chat']; } elseif (isset($button['callback_game'])) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonGame'; $newrows[$key]['buttons'][$button_key]['text'] = $button['callback_game']; } elseif (isset($button['request_contact']) && $button['request_contact']) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonRequestPhone'; } elseif (isset($button['request_location']) && $button['request_location']) { $newrows[$key]['buttons'][$button_key]['_'] = 'keyboardButtonRequestGeoLocation'; } $button_key++; } $key++; } return $newrows; } public function parse_reply_markup($markup) { if (isset($markup['force_reply']) && $markup['force_reply']) { $markup['_'] = 'replyKeyboardForceReply'; unset($markup['force_reply']); } if (isset($markup['remove_keyboard']) && $markup['remove_keyboard']) { $markup['_'] = 'replyKeyboardHide'; unset($markup['remove_keyboard']); } if (isset($markup['keyboard'])) { $markup['_'] = 'replyKeyboardMarkup'; if (isset($markup['resize_keyboard'])) { $markup['resize'] = $markup['resize_keyboard']; unset($markup['resize_keyboard']); } if (isset($markup['one_time_keyboard'])) { $markup['single_use'] = $markup['one_time_keyboard']; unset($markup['one_time_keyboard']); } $markup['rows'] = $this->parse_buttons($markup['keyboard']); unset($markup['keyboard']); } if (isset($markup['inline_keyboard'])) { $markup['_'] = 'replyInlineMarkup'; $markup['rows'] = $this->parse_buttons($markup['inline_keyboard']); unset($markup['inline_keyboard']); } return $markup; } public function MTProto_to_botAPI_async($data, $sent_arguments = []) { $newd = []; if (!isset($data['_'])) { foreach ($data as $key => $element) { $newd[$key] = yield $this->MTProto_to_botAPI_async($element, $sent_arguments); } return $newd; } switch ($data['_']) { case 'updateShortSentMessage': $newd['message_id'] = $data['id']; $newd['date'] = $data['date']; $newd['text'] = $sent_arguments['message']; if ($data['out']) { $newd['from'] = yield $this->get_pwr_chat_async($this->authorization['user']); } $newd['chat'] = yield $this->get_pwr_chat_async($sent_arguments['peer']); if (isset($data['entities'])) { $newd['entities'] = yield $this->MTProto_to_botAPI_async($data['entities'], $sent_arguments); } if (isset($data['media'])) { $newd = array_merge($newd, yield $this->MTProto_to_botAPI_async($data['media'], $sent_arguments)); } return $newd; case 'updateNewChannelMessage': case 'updateNewMessage': return yield $this->MTProto_to_botAPI_async($data['message']); case 'message': $newd['message_id'] = $data['id']; $newd['date'] = $data['date']; $newd['text'] = $data['message']; $newd['post'] = $data['post']; $newd['silent'] = $data['silent']; if (isset($data['from_id'])) { $newd['from'] = yield $this->get_pwr_chat_async($data['from_id']); } $newd['chat'] = yield $this->get_pwr_chat_async($data['to_id']); if (isset($data['entities'])) { $newd['entities'] = yield $this->MTProto_to_botAPI_async($data['entities'], $sent_arguments); } if (isset($data['views'])) { $newd['views'] = $data['views']; } if (isset($data['edit_date'])) { $newd['edit_date'] = $data['edit_date']; } if (isset($data['via_bot_id'])) { $newd['via_bot'] = yield $this->get_pwr_chat_async($data['via_bot_id']); } if (isset($data['fwd_from']['from_id'])) { $newd['forward_from'] = yield $this->get_pwr_chat_async($data['fwd_from']['from_id']); } if (isset($data['fwd_from']['channel_id'])) { $newd['forward_from_chat'] = yield $this->get_pwr_chat_async($data['fwd_from']['channel_id']); } if (isset($data['fwd_from']['date'])) { $newd['forward_date'] = $data['fwd_from']['date']; } if (isset($data['fwd_from']['channel_post'])) { $newd['forward_from_message_id'] = $data['fwd_from']['channel_post']; } if (isset($data['media'])) { $newd = array_merge($newd, yield $this->MTProto_to_botAPI_async($data['media'], $sent_arguments)); } return $newd; case 'messageEntityMention': unset($data['_']); $data['type'] = 'mention'; return $data; case 'messageEntityHashtag': unset($data['_']); $data['type'] = 'hashtag'; return $data; case 'messageEntityBotCommand': unset($data['_']); $data['type'] = 'bot_command'; return $data; case 'messageEntityUrl': unset($data['_']); $data['type'] = 'url'; return $data; case 'messageEntityEmail': unset($data['_']); $data['type'] = 'email'; return $data; case 'messageEntityBold': unset($data['_']); $data['type'] = 'bold'; return $data; case 'messageEntityItalic': unset($data['_']); $data['type'] = 'italic'; return $data; case 'messageEntityCode': unset($data['_']); $data['type'] = 'code'; return $data; case 'messageEntityPre': unset($data['_']); $data['type'] = 'pre'; return $data; case 'messageEntityTextUrl': unset($data['_']); $data['type'] = 'text_url'; return $data; case 'messageEntityMentionName': unset($data['_']); $data['type'] = 'text_mention'; $data['user'] = yield $this->get_pwr_chat_async($data['user_id']); unset($data['user_id']); return $data; case 'messageMediaPhoto': if (isset($data['caption'])) { $res['caption'] = $data['caption']; } $res['photo'] = []; foreach ($data['photo']['sizes'] as $key => $photo) { if (in_array($photo['_'], ['photoCachedSize', 'photoSize'])) { $res['photo'][$key] = yield $this->photosize_to_botapi_async($photo, $data['photo']); } } return $res; case 'messageMediaEmpty': return []; case 'messageMediaDocument': $type_name = 'document'; $res = []; if (isset($data['document']['thumbs']) && $data['document']['thumbs'] && in_array(end($data['document']['thumbs'])['_'], ['photoCachedSize', 'photoSize'])) { $res['thumb'] = yield $this->photosize_to_botapi_async(end($data['document']['thumbs']), [], true); } foreach ($data['document']['attributes'] as $attribute) { switch ($attribute['_']) { case 'documentAttributeFilename': $pathinfo = pathinfo($attribute['file_name']); $res['ext'] = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : ''; $res['file_name'] = $pathinfo['filename']; break; case 'documentAttributeAudio': $audio = $attribute; $type_name = 'audio'; if ($attribute['voice']) { $type_name = 'voice'; } $res['duration'] = $attribute['duration']; if (isset($attribute['performer'])) { $res['performer'] = $attribute['performer']; } if (isset($attribute['title'])) { $res['title'] = $attribute['title']; } if (isset($attribute['waveform'])) { $res['title'] = $attribute['waveform']; } break; case 'documentAttributeVideo': $type_name = $attribute['round_message'] ? 'video_note' : 'video'; $res['width'] = $attribute['w']; $res['height'] = $attribute['h']; $res['duration'] = $attribute['duration']; break; case 'documentAttributeImageSize': $res['width'] = $attribute['w']; $res['height'] = $attribute['h']; break; case 'documentAttributeAnimated': $type_name = 'gif'; $res['animated'] = true; break; case 'documentAttributeHasStickers': $res['has_stickers'] = true; break; case 'documentAttributeSticker': $type_name = 'sticker'; $res['mask'] = $attribute['mask']; $res['emoji'] = $attribute['alt']; $res['sticker_set'] = $attribute['stickerset']; if (isset($attribute['mask_coords'])) { $res['mask_coords'] = $attribute['mask_coords']; } break; } } if (isset($audio) && isset($audio['title']) && !isset($res['file_name'])) { $res['file_name'] = $audio['title']; if (isset($audio['performer'])) { $res['file_name'] .= ' - '.$audio['performer']; } } if (!isset($res['file_name'])) { $res['file_name'] = $data['document']['access_hash']; } $res['file_name'] .= '_'.$data['document']['id']; if (isset($res['ext'])) { $res['file_name'] .= $res['ext']; unset($res['ext']); } else { $res['file_name'] .= $this->get_extension_from_mime($data['document']['mime_type']); } $data['document']['_'] = 'bot_'.$type_name; $res['file_size'] = $data['document']['size']; $res['mime_type'] = $data['document']['mime_type']; $res['file_id'] = $this->base64url_encode($this->rle_encode((yield $this->serialize_object_async(['type' => 'File'], $data['document'], 'File')).chr(2))); return [$type_name => $res, 'caption' => isset($data['caption']) ? $data['caption'] : '']; default: throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['botapi_conversion_error'], $data['_'])); } } public function botAPI_to_MTProto_async($arguments) { foreach (self::BOTAPI_PARAMS_CONVERSION as $bot => $mtproto) { if (isset($arguments[$bot]) && !isset($arguments[$mtproto])) { $arguments[$mtproto] = $arguments[$bot]; //unset($arguments[$bot]); } } if (isset($arguments['reply_markup'])) { $arguments['reply_markup'] = $this->parse_reply_markup($arguments['reply_markup']); } if (isset($arguments['parse_mode'])) { $arguments = yield $this->parse_mode_async($arguments); } return $arguments; } public function parse_node_async($node, &$entities, &$new_message, &$offset) { switch ($node->nodeName) { case 'br': $new_message .= "\n"; $offset++; break; case 'b': case 'strong': $text = $this->html_entity_decode($node->textContent); $length = $this->mb_strlen($text); $entities[] = ['_' => 'messageEntityBold', 'offset' => $offset, 'length' => $length]; $new_message .= $text; $offset += $length; break; case 'i': case 'em': $text = $this->html_entity_decode($node->textContent); $length = $this->mb_strlen($text); $entities[] = ['_' => 'messageEntityItalic', 'offset' => $offset, 'length' => $length]; $new_message .= $text; $offset += $length; break; case 'code': $text = $this->html_entity_decode($node->textContent); $length = $this->mb_strlen($text); $entities[] = ['_' => 'messageEntityCode', 'offset' => $offset, 'length' => $length]; $new_message .= $text; $offset += $length; break; case 'pre': $text = $this->html_entity_decode($node->textContent); $length = $this->mb_strlen($text); $language = $node->getAttribute('language'); if ($language === null) { $language = ''; } $entities[] = ['_' => 'messageEntityPre', 'offset' => $offset, 'length' => $length, 'language' => $language]; $new_message .= $text; $offset += $length; break; case 'p': foreach ($node->childNodes as $node) { yield $this->parse_node_async($node, $entities, $new_message, $offset); } break; case 'a': $text = $this->html_entity_decode($node->textContent); $length = $this->mb_strlen($text); $href = $node->getAttribute('href'); if (preg_match('|mention:(.*)|', $href, $matches) || preg_match('|tg://user\?id=(.*)|', $href, $matches)) { $mention = yield $this->get_info_async($matches[1]); if (!isset($mention['InputUser'])) { throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['peer_not_in_db']); } $entities[] = ['_' => 'inputMessageEntityMentionName', 'offset' => $offset, 'length' => $length, 'user_id' => $mention['InputUser']]; } elseif (preg_match('|buttonurl:(.*)|', $href)) { if (!isset($entities['buttons'])) { $entities['buttons'] = []; } if (strpos(substr($href, -4), '|:new|') !== false) { $entities['buttons'][] = ['_' => 'keyboardButtonUrl', 'text' => $text, 'url' => str_replace(['buttonurl:', ':new'], '', $href), 'new' => true]; } else { $entities['buttons'][] = ['_' => 'keyboardButtonUrl', 'text' => $text, 'url' => str_replace('buttonurl:', '', $href)]; } break; } else { $entities[] = ['_' => 'messageEntityTextUrl', 'offset' => $offset, 'length' => $length, 'url' => $href]; } $new_message .= $text; $offset += $length; break; default: $text = $this->html_entity_decode($node->textContent); $length = $this->mb_strlen($text); $new_message .= $text; $offset += $length; break; } } public function parse_mode_async($arguments) { if ($arguments['message'] === '' || !isset($arguments['message']) || !isset($arguments['parse_mode'])) { return $arguments; } if (isset($arguments['parse_mode']['_'])) { $arguments['parse_mode'] = str_replace('textParseMode', '', $arguments['parse_mode']['_']); } if (stripos($arguments['parse_mode'], 'markdown') !== false) { $arguments['message'] = \Parsedown::instance()->line($arguments['message']); $arguments['parse_mode'] = 'HTML'; } if (stripos($arguments['parse_mode'], 'html') !== false) { $new_message = ''; $arguments['message'] = trim($this->html_fixtags($arguments['message'])); $dom = new \DOMDocument(); if (!extension_loaded('mbstring')) { throw new \danog\MadelineProto\Exception(['extension', 'mbstring']); } $dom->loadHTML(mb_convert_encoding($arguments['message'], 'HTML-ENTITIES', 'UTF-8')); if (!isset($arguments['entities'])) { $arguments['entities'] = []; } $offset = 0; foreach ($dom->getElementsByTagName('body')->item(0)->childNodes as $node) { yield $this->parse_node_async($node, $arguments['entities'], $new_message, $offset); } if (isset($arguments['entities']['buttons'])) { $arguments['reply_markup'] = $this->build_rows($arguments['entities']['buttons']); unset($arguments['entities']['buttons']); } unset($arguments['parse_mode']); $arguments['message'] = $new_message; } return $arguments; } public function split_to_chunks_async($args) { $args = yield $this->parse_mode_async($args); if (!isset($args['entities'])) { $args['entities'] = []; } $max_length = isset($args['media']) ? $this->config['caption_length_max'] : $this->config['message_length_max']; $max_entity_length = 100; $max_entity_size = 8110; $text_arr = []; foreach ($this->multipleExplodeKeepDelimiters(["\n"], $args['message']) as $word) { if (mb_strlen($word, 'UTF-8') > $max_length) { foreach ($this->mb_str_split($word, $max_length) as $vv) { $text_arr[] = $vv; } } else { $text_arr[] = $word; } } $multiple_args_base = array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']); $multiple_args = [$multiple_args_base]; $i = 0; foreach ($text_arr as $word) { if ($this->mb_strlen($multiple_args[$i]['message'].$word) <= $max_length) { $multiple_args[$i]['message'] .= $word; } else { $i++; $multiple_args[$i] = $multiple_args_base; $multiple_args[$i]['message'] .= $word; } } $i = 0; $offset = 0; for ($k = 0; $k < count($args['entities']); $k++) { $entity = $args['entities'][$k]; do { while ($entity['offset'] > $offset + $this->mb_strlen($multiple_args[$i]['message'])) { $offset += $this->mb_strlen($multiple_args[$i]['message']); $i++; } $entity['offset'] -= $offset; if ($entity['offset'] + $entity['length'] > $this->mb_strlen($multiple_args[$i]['message'])) { $newentity = $entity; $newentity['length'] = $entity['length'] - ($this->mb_strlen($multiple_args[$i]['message']) - $entity['offset']); $entity['length'] = $this->mb_strlen($multiple_args[$i]['message']) - $entity['offset']; $offset += $entity['length']; //$this->mb_strlen($multiple_args[$i]['message']); $newentity['offset'] = $offset; $prev_length = $this->mb_strlen($multiple_args[$i]['message']); $multiple_args[$i]['message'] = rtrim($multiple_args[$i]['message']); $diff = $prev_length - $this->mb_strlen($multiple_args[$i]['message']); if ($diff) { $entity['length'] -= $diff; foreach ($args['entities'] as $key => &$eentity) { if ($key > $k) { $eentity['offset'] -= $diff; } } } $multiple_args[$i]['entities'][] = $entity; $i++; $entity = $newentity; continue; } else { $prev_length = $this->mb_strlen($multiple_args[$i]['message']); $multiple_args[$i]['message'] = rtrim($multiple_args[$i]['message']); $diff = $prev_length - $this->mb_strlen($multiple_args[$i]['message']); if ($diff) { $entity['length'] -= $diff; foreach ($args['entities'] as $key => &$eentity) { if ($key > $k) { $eentity['offset'] -= $diff; } } } $multiple_args[$i]['entities'][] = $entity; break; } } while (true); } $total = 0; foreach ($multiple_args as $args) { if (count($args['entities']) > $max_entity_length) { $total += count($args['entities']) - $max_entity_length; } $c = 0; foreach ($args['entities'] as $entity) { if (isset($entity['url'])) { $c += strlen($entity['url']); } } if ($c >= $max_entity_size) { $this->logger->logger('Entity size limit possibly exceeded, you may get an error indicating that the entities are too long. Reduce the number of entities and/or size of the URLs used.', Logger::FATAL_ERROR); } } if ($total) { $this->logger->logger("Too many entities, $total entities will be truncated", Logger::FATAL_ERROR); } return $multiple_args; } public function multipleExplodeKeepDelimiters($delimiters, $string) { $initialArray = explode(chr(1), str_replace($delimiters, chr(1), $string)); $finalArray = []; $delimOffset = 0; foreach ($initialArray as $item) { $delimOffset += $this->mb_strlen($item); //if ($this->mb_strlen($item) > 0) { $finalArray[] = $item.($delimOffset < $this->mb_strlen($string) ? $string[$delimOffset] : ''); //} $delimOffset++; } return $finalArray; } public function html_fixtags($text) { $diff = 0; preg_match_all('#(.*?)(<(a|b|\bstrong\b|\bem\b|i|\bcode\b|\bpre\b)[^>]*>)(.*?)(<\s*/\s*\3>)#is', $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); if ($matches) { foreach ($matches as $match) { if (trim($match[1][0]) != '') { $mod = htmlentities($match[1][0]); $temp = substr($text, 0, $match[1][1] + $diff); $temp .= $mod; $temp .= substr($text, $match[1][1] + $diff + strlen($match[1][0])); $diff += strlen($mod) - strlen($match[1][0]); $text = $temp; } $mod = htmlentities($match[4][0]); $temp = substr($text, 0, $match[4][1] + $diff); $temp .= $mod; $temp .= substr($text, $match[4][1] + $diff + strlen($match[4][0])); $diff += strlen($mod) - strlen($match[4][0]); $text = $temp; } $diff = 0; preg_match_all('#<a\s*href=("|\')(.+?)("|\')\s*>#is', $text, $matches, PREG_OFFSET_CAPTURE); foreach ($matches[2] as $match) { $mod = htmlentities($match[0]); $temp = substr($text, 0, $match[1] + $diff); $temp .= $mod; $temp .= substr($text, $match[1] + $diff + strlen($match[0])); $diff += strlen($mod) - strlen($match[0]); $text = $temp; } return $text; } else { return htmlentities($text); } } public function build_rows($button_list) { $end = false; $rows = []; $buttons = []; $cols = 0; foreach ($button_list as $button) { if (isset($button['new'])) { if (count($buttons) == 0) { $buttons[] = $button; } else { $row = ['_' => 'keyboardButtonRow', 'buttons' => $buttons]; $rows[] = $row; $buttons = [$button]; } } else { $buttons[] = $button; $end = true; } } if ($end) { $row = ['_' => 'keyboardButtonRow', 'buttons' => $buttons]; $rows[] = $row; } return ['_' => 'replyInlineMarkup', 'rows' => $rows]; } } <?php /* Copyright 2016-2019 Daniil Gentili (https://daniil.it) This file is part of MadelineProto. MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU General Public License along with MadelineProto. If not, see <http://www.gnu.org/licenses/>. */ namespace danog\MadelineProto\TL\Conversion; /** * Manages generation of extensions for files. */ trait Extension { public function get_mime_from_extension($extension, $default) { $ext = ltrim($extension, '.'); if (isset(self::ALL_MIMES[$ext])) { return self::ALL_MIMES[$ext][0]; } return $default; } public function get_extension_from_mime($mime) { foreach (self::ALL_MIMES as $key => $value) { if (array_search($mime, $value) !== false) { return '.'.$key; } } return ''; } public function get_extension_from_location($location, $default) { return $default; //('upload.getFile', ['location' => $location, 'offset' => 0, 'limit' => 2], ['heavy' => true, 'datacenter' => $location['dc_id']]); if (!isset($res['type']['_'])) { return $default; } switch ($res['type']['_']) { case 'storage.fileJpeg': return '.jpg'; case 'storage.fileGif': return '.gif'; case 'storage.filePng': return '.png'; case 'storage.filePdf': return '.pdf'; case 'storage.fileMp3': return '.mp3'; case 'storage.fileMov': return '.mov'; case 'storage.fileMp4': return '.mp4'; case 'storage.fileWebp': return '.webp'; default: return $default; } } public function get_mime_from_file($file) { $finfo = new \finfo(FILEINFO_MIME_TYPE); return $finfo->file($file); } public function get_mime_from_buffer($buffer) { $finfo = new \finfo(FILEINFO_MIME_TYPE); return $finfo->buffer($buffer); } } <?php /** * Exception module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL\Conversion; class Exception extends \Exception { use \danog\MadelineProto\TL\PrettyException; public function __toString() { $result = get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL; if (php_sapi_name() !== 'cli') { $result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); } return $result; } public function __construct($message, $file = '') { parent::__construct($message); $this->prettify_tl($file); } } <?php /** * Exception module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; class Exception extends \Exception { use PrettyException; public function __toString() { $result = get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL; if (php_sapi_name() !== 'cli') { $result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); } return $result; } public function __construct($message, $file = '') { parent::__construct($message); $this->prettify_tl($file); } } <?php /** * TLMethod module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\TL; class TLMethod { use \danog\Serializable; use \danog\MadelineProto\Tools; use TLParams; public $by_id = []; public $by_method = []; public $method_namespace = []; public function __sleep() { return ['by_id', 'by_method', 'method_namespace']; } public function add($json_dict) { $this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']]; $this->by_method[$json_dict['method']] = $json_dict['id']; $namespace = explode('.', $json_dict['method']); if (isset($namespace[1])) { $this->method_namespace[] = [$namespace[0] => $namespace[1]]; } $this->parse_params($json_dict['id']); } public function find_by_id($id) { if (isset($this->by_id[$id])) { $method = $this->by_id[$id]; $method['id'] = $id; return $method; } return false; } public function find_by_method($method_name) { if (isset($this->by_method[$method_name])) { $method = $this->by_id[$this->by_method[$method_name]]; $method['id'] = $this->by_method[$method_name]; return $method; } return false; } } <?php /** * Handler module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Server; /* * Socket handler for server */ class Handler extends \danog\MadelineProto\Connection { use \danog\MadelineProto\TL\TL; use \danog\MadelineProto\TL\Conversion\BotAPI; use \danog\MadelineProto\TL\Conversion\BotAPIFiles; use \danog\MadelineProto\TL\Conversion\Extension; use \danog\MadelineProto\TL\Conversion\TD; use \danog\MadelineProto\Tools; private $madeline; public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6) { \danog\MadelineProto\Magic::$pid = getmypid(); $this->sock = $socket; $this->sock->setBlocking(true); $this->must_open = false; $timeout = 2; $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout); $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout); $this->logger = new \danog\MadelineProto\Logger(3); $this->construct_TL(['socket' => __DIR__.'/../TL_socket.tl']); } public function __destruct() { echo 'Closing socket in fork '.getmypid().PHP_EOL; unset($this->sock); $this->destruct_madeline(); } public function destruct_madeline() { if (isset($this->madeline) && $this->madeline !== null) { $this->madeline->API->settings['logger'] = ['logger' => 0, 'logger_param' => '']; $this->madeline->API->settings['updates']['callback'] = []; unset($this->madeline); return true; } return false; } public function loop() { $buffer = ''; $first_byte = $this->sock->read(1); if ($first_byte === chr(239)) { $this->protocol = 'tcp_abridged'; } else { $first_byte .= $this->sock->read(3); if ($first_byte === str_repeat(chr(238), 4)) { $this->protocol = 'tcp_intermediate'; } else { $this->protocol = 'tcp_full'; $packet_length = unpack('V', $first_byte)[1]; $packet = $this->read($packet_length - 4); if (strrev(hash('crc32b', $first_byte.substr($packet, 0, -4), true)) !== substr($packet, -4)) { throw new Exception('CRC32 was not correct!'); } $this->in_seq_no++; $in_seq_no = unpack('V', substr($packet, 0, 4))[1]; if ($in_seq_no != $this->in_seq_no) { throw new Exception('Incoming seq_no mismatch'); } $buffer = substr($packet, 4, $packet_length - 12); } } while (true) { pcntl_signal_dispatch(); $request_id = 0; try { if ($buffer) { $message = $buffer; $buffer = ''; } else { $time = time(); $message = $this->read_message(); } } catch (\danog\MadelineProto\NothingInTheSocketException $e) { echo $e; if (time() - $time < 2) { $this->sock = null; } continue; } try { $message = $this->deserialize($message, ['type' => '', 'datacenter' => '']); if ($message['_'] !== 'socketMessageRequest') { throw new \danog\MadelineProto\Exception('Invalid object received'); } $request_id = $message['request_id']; $this->send_response($request_id, $this->on_request($request_id, $message['method'], $message['args'])); } catch (\danog\MadelineProto\TL\Exception $e) { $this->send_exception($request_id, $e); continue; } catch (\danog\MadelineProto\Exception $e) { $this->send_exception($request_id, $e); continue; } catch (\danog\MadelineProto\RPCErrorException $e) { $this->send_exception($request_id, $e); continue; } catch (\DOMException $e) { $this->send_exception($request_id, $e); continue; } } } public function on_request($request_id, $method, $args) { if (count($method) === 0 || count($method) > 2) { throw new \danog\MadelineProto\Exception('Invalid method called'); } array_walk($args, [$this, 'walker']); if ($method[0] === '__construct') { if (count($args) === 1 && is_array($args[0])) { $args[0]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']]; $args[0]['updates']['callback'] = [$this, 'update_handler']; } elseif (count($args) === 2 && is_array($args[1])) { $args[1]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']]; $args[1]['updates']['callback'] = [$this, 'update_handler']; } $this->madeline = new \danog\MadelineProto\API(...$args); return true; } if ($method[0] === '__destruct') { $this->__destruct(); exit(); } if ($this->madeline === null) { throw new \danog\MadelineProto\Exception('__construct was not called'); } if (count($method) === 1) { return $this->madeline->{$method[0]}(...$args); } if (count($method) === 2) { return $this->madeline->{$method[0]}->{$method[1]}(...$args); } } private function walker(&$arg) { if (is_array($arg)) { if (isset($arg['_'])) { if ($arg['_'] === 'fileCallback' && isset($arg['callback']) && isset($arg['file']) && !method_exists($this, $arg['callback']['callback'])) { if (isset($arg['file']['_']) && $arg['file']['_'] === 'stream') { $arg['file'] = fopen('madelineSocket://', 'r+b', false, Stream::getContext($this, $arg['file']['stream_id'])); } $arg = new \danog\MadelineProto\FileCallback($arg['file'], [$this, $arg['callback']['callback']]); return; } elseif ($arg['_'] === 'callback' && isset($arg['callback']) && !method_exists($this, $arg['callback'])) { $arg = [$this, $arg['callback']]; return; } elseif ($arg['_'] === 'stream' && isset($arg['stream_id'])) { $arg = fopen('madelineSocket://', 'r+b', false, Stream::getContext($this, $arg['stream_id'])); return; } elseif ($arg['_'] === 'bytes' && isset($arg['bytes'])) { $arg = base64_decode($args['bytes']); return; } else { array_walk($arg, [$this, 'walker']); } } else { array_walk($arg, [$this, 'walker']); } } } public function send_exception($request_id, $e) { echo $e.PHP_EOL; if ($e instanceof \danog\MadelineProto\RPCErrorException) { $exception = ['_' => 'socketRPCErrorException']; if ($e->getMessage() === $e->rpc) { $exception['rpc_message'] = $e->rpc; } else { $exception['rpc_message'] = $e->rpc; $exception['message'] = $e->getMessage(); } } elseif ($e instanceof \danog\MadelineProto\TL\Exception) { $exception = ['_' => 'socketTLException', 'message' => $e->getMessage()]; } elseif ($e instanceof \DOMException) { $exception = ['_' => 'socketDOMException', 'message' => $e->getMessage()]; } else { $exception = ['_' => 'socketException', 'message' => $e->getMessage()]; } $exception['code'] = $e->getCode(); $exception['trace'] = ['_' => 'socketTLTrace', 'frames' => []]; $tl = false; foreach (array_reverse($e->getTrace()) as $k => $frame) { $tl_frame = ['_' => 'socketTLFrame']; if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) { if ($frame['args'][2] !== '') { $tl_frame['tl_param'] = (string) $frame['args'][2]; $tl = true; } } else { if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') { continue; } if (isset($frame['file'])) { $tl_frame['file'] = $frame['file']; $tl_frame['line'] = $frame['line']; } if (isset($frame['function'])) { $tl_frame['function'] = $frame['function']; } if (isset($frame['args'])) { $args = json_encode($frame['args']); if ($args !== false) { $tl_frame['args'] = $args; } } $tl = false; } $exception['trace']['frames'][] = $tl_frame; } $this->send_message_safe(yield $this->serialize_object_async(['type' => ''], ['_' => 'socketMessageException', 'request_id' => $request_id, 'exception' => $exception], 'exception')); } public function send_response($request_id, $response) { $this->send_message_safe(yield $this->serialize_object_async(['type' => ''], ['_' => 'socketMessageResponse', 'request_id' => $request_id, 'data' => $response], 'exception')); } public function send_data($stream_id, $data) { $this->send_message_safe(yield $this->serialize_object_async(['type' => ''], ['_' => 'socketMessageRawData', 'stream_id' => $stream_id, 'data' => $data], 'data')); } public $logging = false; public function logger($message, $level) { if (!$this->logging) { try { $this->logging = true; $message = ['_' => 'socketMessageLog', 'data' => $message, 'level' => $level, 'thread' => \danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()), 'process' => \danog\MadelineProto\Magic::is_fork(), 'file' => basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['file'], '.php')]; $this->send_message_safe(yield $this->serialize_object_async(['type' => ''], $message, 'log')); } finally { $this->logging = false; } } } public function send_message_safe($message) { if (!isset($this->sock)) { return false; } try { $this->send_message($message); } catch (\danog\MadelineProto\Exception $e) { $this->__destruct(); die; } } public function update_handler($update) { $this->send_message_safe(yield $this->serialize_object_async(['type' => ''], ['_' => 'socketMessageUpdate', 'data' => $update], 'update')); } public function __call($method, $args) { $this->send_message_safe(yield $this->serialize_object_async(['type' => ''], ['_' => 'socketMessageRequest', 'request_id' => 0, 'method' => [$method], 'args' => $args], 'method')); } } <?php /** * Proxy module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Server; /* * Socket handler for server */ class Proxy extends \danog\MadelineProto\Connection { public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6) { \danog\MadelineProto\Logger::log('Got connection '.getmypid().'!'); \danog\MadelineProto\Magic::$pid = getmypid(); \danog\MadelineProto\Lang::$current_lang = []; $this->sock = $socket; $this->sock->setBlocking(true); $this->must_open = false; $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $extra['timeout']); $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $extra['timeout']); $this->logger = new \danog\MadelineProto\Logger(3); $this->extra = $extra; if ($this->extra['madeline'] instanceof \danog\MadelineProto\API) { $this->extra['madeline'] = $this->extra['madeline']->API->datacenter->sockets; } } public function __destruct() { \danog\MadelineProto\Logger::log('Closing fork '.getmypid().'!'); unset($this->sock); } public function loop() { $this->protocol = 'obfuscated2'; $random = $this->sock->read(64); $reversed = strrev(substr($random, 8, 48)); $key = substr($random, 8, 32); $keyRev = substr($reversed, 0, 32); if (isset($this->extra['secret'])) { $key = hash('sha256', $key.$this->extra['secret'], true); $keyRev = hash('sha256', $keyRev.$this->extra['secret'], true); } $this->obfuscated = ['encryption' => new \phpseclib\Crypt\AES('ctr'), 'decryption' => new \phpseclib\Crypt\AES('ctr')]; $this->obfuscated['encryption']->enableContinuousBuffer(); $this->obfuscated['decryption']->enableContinuousBuffer(); $this->obfuscated['decryption']->setKey($key); $this->obfuscated['decryption']->setIV(substr($random, 40, 16)); $this->obfuscated['encryption']->setKey($keyRev); $this->obfuscated['encryption']->setIV(substr($reversed, 32, 16)); $random = substr_replace($random, substr(@$this->obfuscated['decryption']->encrypt($random), 56, 8), 56, 8); if (substr($random, 56, 4) !== str_repeat(chr(0xef), 4)) { throw new \danog\MadelineProto\Exception('Wrong protocol version'); } $dc = abs(unpack('s', substr($random, 60, 2))[1]); $socket = $this->extra['madeline'][$dc]; $socket->__construct($socket->proxy, $socket->extra, $socket->ip, $socket->port, $socket->protocol, $timeout = $this->extra['timeout'], $socket->ipv6); unset($this->extra); $write = []; $except = []; while (true) { pcntl_signal_dispatch(); try { $read = [$this->getSocket(), $socket->getSocket()]; \Socket::select($read, $write, $except, $timeout); if (isset($read[0])) { //\danog\MadelineProto\Logger::log("Will write to DC $dc on ".\danog\MadelineProto\Magic::$pid); $socket->send_message($this->read_message()); } if (isset($read[1])) { //\danog\MadelineProto\Logger::log("Will read from DC $dc on ".\danog\MadelineProto\Magic::$pid); $this->send_message($socket->read_message()); } if (empty($read)) { throw new \danog\MadelineProto\NothingInTheSocketException('Inactivity'); } } catch (\danog\MadelineProto\NothingInTheSocketException $e) { exit(); } } } } <?php /** * Stream module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Server; class Stream { const WRAPPER_NAME = 'madelineSocket'; public $context; private $_handler; private $_stream_id; private static $_isRegistered = false; public static function getContext($handler, $stream_id) { if (!self::$_isRegistered) { stream_wrapper_register(self::WRAPPER_NAME, get_class()); self::$_isRegistered = true; } return stream_context_create([self::WRAPPER_NAME => ['handler' => $handler, 'stream_id' => $stream_id]]); } public function stream_open($path, $mode, $options, &$opened_path) { $opt = stream_context_get_options($this->context); if (!is_array($opt[self::WRAPPER_NAME]) || !isset($opt[self::WRAPPER_NAME]['handler']) || !($opt[self::WRAPPER_NAME]['handler'] instanceof Handler) || !isset($opt[self::WRAPPER_NAME]['stream_id'])) { return false; } $this->_handler = $opt[self::WRAPPER_NAME]['handler']; $this->_stream_id = $opt[self::WRAPPER_NAME]['stream_id']; return true; } public function stream_write($data) { $this->_handler->send_data($this->_stream_id, $data); } public function stream_lock($mode) { } } <?php /** * Server module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; /* * Socket server for multi-language API */ class Server { private $settings; private $pids = []; private $mypid; public function __construct($settings) { set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); \danog\MadelineProto\Logger::constructor(3); if (!extension_loaded('sockets')) { throw new Exception(['extension', 'sockets']); } if (!extension_loaded('pcntl')) { throw new Exception(['extension', 'pcntl']); } $this->settings = $settings; $this->mypid = getmypid(); } public function start() { pcntl_signal(SIGTERM, [$this, 'sig_handler']); pcntl_signal(SIGINT, [$this, 'sig_handler']); pcntl_signal(SIGCHLD, [$this, 'sig_handler']); $this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']); $this->sock->bind($this->settings['address'], $this->settings['port']); $this->sock->listen(); $this->sock->setBlocking(true); $timeout = 2; $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout); $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout); \danog\MadelineProto\Logger::log('Server started! Listening on '.$this->settings['address'].':'.$this->settings['port']); while (true) { pcntl_signal_dispatch(); try { if ($sock = $this->sock->accept()) { $this->handle($sock); } } catch (\danog\MadelineProto\Exception $e) { } } } private function handle($socket) { $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } elseif ($pid) { return $this->pids[] = $pid; } $handler = new $this->settings['handler']($socket, $this->settings['extra'], null, null, null, null, null); $handler->loop(); die; } public function __destruct() { if ($this->mypid === getmypid()) { \danog\MadelineProto\Logger::log('Shutting main process '.$this->mypid.' down'); unset($this->sock); foreach ($this->pids as $pid) { \danog\MadelineProto\Logger::log("Waiting for $pid"); pcntl_wait($pid); } \danog\MadelineProto\Logger::log('Done, closing main process'); return; } } public function sig_handler($sig) { switch ($sig) { case SIGTERM: case SIGINT: exit(); case SIGCHLD: pcntl_waitpid(-1, $status); break; } } } {"constructors":[{"id":"-1132882121","predicate":"boolFalse","params":[],"type":"Bool"},{"id":"-1720552011","predicate":"boolTrue","params":[],"type":"Bool"},{"id":"1072550713","predicate":"true","params":[],"type":"True"},{"id":"481674261","predicate":"vector","params":[],"type":"Vector t"},{"id":"-994444869","predicate":"error","params":[{"name":"code","type":"int"},{"name":"text","type":"string"}],"type":"Error"},{"id":"1450380236","predicate":"null","params":[],"type":"Null"},{"id":"2134579434","predicate":"inputPeerEmpty","params":[],"type":"InputPeer"},{"id":"2107670217","predicate":"inputPeerSelf","params":[],"type":"InputPeer"},{"id":"396093539","predicate":"inputPeerChat","params":[{"name":"chat_id","type":"int"}],"type":"InputPeer"},{"id":"-1182234929","predicate":"inputUserEmpty","params":[],"type":"InputUser"},{"id":"-138301121","predicate":"inputUserSelf","params":[],"type":"InputUser"},{"id":"-208488460","predicate":"inputPhoneContact","params":[{"name":"client_id","type":"long"},{"name":"phone","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"InputContact"},{"id":"-181407105","predicate":"inputFile","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"name","type":"string"},{"name":"md5_checksum","type":"string"}],"type":"InputFile"},{"id":"-1771768449","predicate":"inputMediaEmpty","params":[],"type":"InputMedia"},{"id":"1661770481","predicate":"inputMediaUploadedPhoto","params":[{"name":"flags","type":"#"},{"name":"file","type":"InputFile"},{"name":"caption","type":"string"},{"name":"stickers","type":"flags.0?Vector<InputDocument>"}],"type":"InputMedia"},{"id":"-373312269","predicate":"inputMediaPhoto","params":[{"name":"id","type":"InputPhoto"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-104578748","predicate":"inputMediaGeoPoint","params":[{"name":"geo_point","type":"InputGeoPoint"}],"type":"InputMedia"},{"id":"-1494984313","predicate":"inputMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"InputMedia"},{"id":"480546647","predicate":"inputChatPhotoEmpty","params":[],"type":"InputChatPhoto"},{"id":"-1837345356","predicate":"inputChatUploadedPhoto","params":[{"name":"file","type":"InputFile"}],"type":"InputChatPhoto"},{"id":"-1991004873","predicate":"inputChatPhoto","params":[{"name":"id","type":"InputPhoto"}],"type":"InputChatPhoto"},{"id":"-457104426","predicate":"inputGeoPointEmpty","params":[],"type":"InputGeoPoint"},{"id":"-206066487","predicate":"inputGeoPoint","params":[{"name":"lat","type":"double"},{"name":"long","type":"double"}],"type":"InputGeoPoint"},{"id":"483901197","predicate":"inputPhotoEmpty","params":[],"type":"InputPhoto"},{"id":"-74070332","predicate":"inputPhoto","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputPhoto"},{"id":"342061462","predicate":"inputFileLocation","params":[{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"InputFileLocation"},{"id":"1996904104","predicate":"inputAppEvent","params":[{"name":"time","type":"double"},{"name":"type","type":"string"},{"name":"peer","type":"long"},{"name":"data","type":"string"}],"type":"InputAppEvent"},{"id":"-1649296275","predicate":"peerUser","params":[{"name":"user_id","type":"int"}],"type":"Peer"},{"id":"-1160714821","predicate":"peerChat","params":[{"name":"chat_id","type":"int"}],"type":"Peer"},{"id":"-1432995067","predicate":"storage.fileUnknown","params":[],"type":"storage.FileType"},{"id":"8322574","predicate":"storage.fileJpeg","params":[],"type":"storage.FileType"},{"id":"-891180321","predicate":"storage.fileGif","params":[],"type":"storage.FileType"},{"id":"172975040","predicate":"storage.filePng","params":[],"type":"storage.FileType"},{"id":"-1373745011","predicate":"storage.filePdf","params":[],"type":"storage.FileType"},{"id":"1384777335","predicate":"storage.fileMp3","params":[],"type":"storage.FileType"},{"id":"1258941372","predicate":"storage.fileMov","params":[],"type":"storage.FileType"},{"id":"1086091090","predicate":"storage.filePartial","params":[],"type":"storage.FileType"},{"id":"-1278304028","predicate":"storage.fileMp4","params":[],"type":"storage.FileType"},{"id":"276907596","predicate":"storage.fileWebp","params":[],"type":"storage.FileType"},{"id":"2086234950","predicate":"fileLocationUnavailable","params":[{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"FileLocation"},{"id":"1406570614","predicate":"fileLocation","params":[{"name":"dc_id","type":"int"},{"name":"volume_id","type":"long"},{"name":"local_id","type":"int"},{"name":"secret","type":"long"}],"type":"FileLocation"},{"id":"537022650","predicate":"userEmpty","params":[{"name":"id","type":"int"}],"type":"User"},{"id":"1326562017","predicate":"userProfilePhotoEmpty","params":[],"type":"UserProfilePhoto"},{"id":"-715532088","predicate":"userProfilePhoto","params":[{"name":"photo_id","type":"long"},{"name":"photo_small","type":"FileLocation"},{"name":"photo_big","type":"FileLocation"}],"type":"UserProfilePhoto"},{"id":"164646985","predicate":"userStatusEmpty","params":[],"type":"UserStatus"},{"id":"-306628279","predicate":"userStatusOnline","params":[{"name":"expires","type":"int"}],"type":"UserStatus"},{"id":"9203775","predicate":"userStatusOffline","params":[{"name":"was_online","type":"int"}],"type":"UserStatus"},{"id":"-1683826688","predicate":"chatEmpty","params":[{"name":"id","type":"int"}],"type":"Chat"},{"id":"-652419756","predicate":"chat","params":[{"name":"flags","type":"#"},{"name":"creator","type":"flags.0?true"},{"name":"kicked","type":"flags.1?true"},{"name":"left","type":"flags.2?true"},{"name":"admins_enabled","type":"flags.3?true"},{"name":"admin","type":"flags.4?true"},{"name":"deactivated","type":"flags.5?true"},{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"photo","type":"ChatPhoto"},{"name":"participants_count","type":"int"},{"name":"date","type":"int"},{"name":"version","type":"int"},{"name":"migrated_to","type":"flags.6?InputChannel"}],"type":"Chat"},{"id":"120753115","predicate":"chatForbidden","params":[{"name":"id","type":"int"},{"name":"title","type":"string"}],"type":"Chat"},{"id":"771925524","predicate":"chatFull","params":[{"name":"id","type":"int"},{"name":"participants","type":"ChatParticipants"},{"name":"chat_photo","type":"Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"exported_invite","type":"ExportedChatInvite"},{"name":"bot_info","type":"Vector<BotInfo>"}],"type":"ChatFull"},{"id":"-925415106","predicate":"chatParticipant","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChatParticipant"},{"id":"-57668565","predicate":"chatParticipantsForbidden","params":[{"name":"flags","type":"#"},{"name":"chat_id","type":"int"},{"name":"self_participant","type":"flags.0?ChatParticipant"}],"type":"ChatParticipants"},{"id":"1061556205","predicate":"chatParticipants","params":[{"name":"chat_id","type":"int"},{"name":"participants","type":"Vector<ChatParticipant>"},{"name":"version","type":"int"}],"type":"ChatParticipants"},{"id":"935395612","predicate":"chatPhotoEmpty","params":[],"type":"ChatPhoto"},{"id":"1632839530","predicate":"chatPhoto","params":[{"name":"photo_small","type":"FileLocation"},{"name":"photo_big","type":"FileLocation"}],"type":"ChatPhoto"},{"id":"-2082087340","predicate":"messageEmpty","params":[{"name":"id","type":"int"}],"type":"Message"},{"id":"-1063525281","predicate":"message","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"post","type":"flags.14?true"},{"name":"id","type":"int"},{"name":"from_id","type":"flags.8?int"},{"name":"to_id","type":"Peer"},{"name":"fwd_from","type":"flags.2?MessageFwdHeader"},{"name":"via_bot_id","type":"flags.11?int"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"date","type":"int"},{"name":"message","type":"string"},{"name":"media","type":"flags.9?MessageMedia"},{"name":"reply_markup","type":"flags.6?ReplyMarkup"},{"name":"entities","type":"flags.7?Vector<MessageEntity>"},{"name":"views","type":"flags.10?int"},{"name":"edit_date","type":"flags.15?int"}],"type":"Message"},{"id":"-1642487306","predicate":"messageService","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"post","type":"flags.14?true"},{"name":"id","type":"int"},{"name":"from_id","type":"flags.8?int"},{"name":"to_id","type":"Peer"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"date","type":"int"},{"name":"action","type":"MessageAction"}],"type":"Message"},{"id":"1038967584","predicate":"messageMediaEmpty","params":[],"type":"MessageMedia"},{"id":"1032643901","predicate":"messageMediaPhoto","params":[{"name":"photo","type":"Photo"},{"name":"caption","type":"string"}],"type":"MessageMedia"},{"id":"1457575028","predicate":"messageMediaGeo","params":[{"name":"geo","type":"GeoPoint"}],"type":"MessageMedia"},{"id":"1585262393","predicate":"messageMediaContact","params":[{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"user_id","type":"int"}],"type":"MessageMedia"},{"id":"-1618676578","predicate":"messageMediaUnsupported","params":[],"type":"MessageMedia"},{"id":"-1230047312","predicate":"messageActionEmpty","params":[],"type":"MessageAction"},{"id":"-1503425638","predicate":"messageActionChatCreate","params":[{"name":"title","type":"string"},{"name":"users","type":"Vector<int>"}],"type":"MessageAction"},{"id":"-1247687078","predicate":"messageActionChatEditTitle","params":[{"name":"title","type":"string"}],"type":"MessageAction"},{"id":"2144015272","predicate":"messageActionChatEditPhoto","params":[{"name":"photo","type":"Photo"}],"type":"MessageAction"},{"id":"-1780220945","predicate":"messageActionChatDeletePhoto","params":[],"type":"MessageAction"},{"id":"1217033015","predicate":"messageActionChatAddUser","params":[{"name":"users","type":"Vector<int>"}],"type":"MessageAction"},{"id":"-1297179892","predicate":"messageActionChatDeleteUser","params":[{"name":"user_id","type":"int"}],"type":"MessageAction"},{"id":"1728035348","predicate":"dialog","params":[{"name":"flags","type":"#"},{"name":"peer","type":"Peer"},{"name":"top_message","type":"int"},{"name":"read_inbox_max_id","type":"int"},{"name":"read_outbox_max_id","type":"int"},{"name":"unread_count","type":"int"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"pts","type":"flags.0?int"},{"name":"draft","type":"flags.1?DraftMessage"}],"type":"Dialog"},{"id":"590459437","predicate":"photoEmpty","params":[{"name":"id","type":"long"}],"type":"Photo"},{"id":"-1836524247","predicate":"photo","params":[{"name":"flags","type":"#"},{"name":"has_stickers","type":"flags.0?true"},{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"sizes","type":"Vector<PhotoSize>"}],"type":"Photo"},{"id":"236446268","predicate":"photoSizeEmpty","params":[{"name":"type","type":"string"}],"type":"PhotoSize"},{"id":"2009052699","predicate":"photoSize","params":[{"name":"type","type":"string"},{"name":"location","type":"FileLocation"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"size","type":"int"}],"type":"PhotoSize"},{"id":"-374917894","predicate":"photoCachedSize","params":[{"name":"type","type":"string"},{"name":"location","type":"FileLocation"},{"name":"w","type":"int"},{"name":"h","type":"int"},{"name":"bytes","type":"bytes"}],"type":"PhotoSize"},{"id":"286776671","predicate":"geoPointEmpty","params":[],"type":"GeoPoint"},{"id":"541710092","predicate":"geoPoint","params":[{"name":"long","type":"double"},{"name":"lat","type":"double"}],"type":"GeoPoint"},{"id":"-2128698738","predicate":"auth.checkedPhone","params":[{"name":"phone_registered","type":"Bool"}],"type":"auth.CheckedPhone"},{"id":"1577067778","predicate":"auth.sentCode","params":[{"name":"flags","type":"#"},{"name":"phone_registered","type":"flags.0?true"},{"name":"type","type":"auth.SentCodeType"},{"name":"phone_code_hash","type":"string"},{"name":"next_type","type":"flags.1?auth.CodeType"},{"name":"timeout","type":"flags.2?int"}],"type":"auth.SentCode"},{"id":"-855308010","predicate":"auth.authorization","params":[{"name":"flags","type":"#"},{"name":"tmp_sessions","type":"flags.0?int"},{"name":"user","type":"User"}],"type":"auth.Authorization"},{"id":"-543777747","predicate":"auth.exportedAuthorization","params":[{"name":"id","type":"int"},{"name":"bytes","type":"bytes"}],"type":"auth.ExportedAuthorization"},{"id":"-1195615476","predicate":"inputNotifyPeer","params":[{"name":"peer","type":"InputPeer"}],"type":"InputNotifyPeer"},{"id":"423314455","predicate":"inputNotifyUsers","params":[],"type":"InputNotifyPeer"},{"id":"1251338318","predicate":"inputNotifyChats","params":[],"type":"InputNotifyPeer"},{"id":"-1540769658","predicate":"inputNotifyAll","params":[],"type":"InputNotifyPeer"},{"id":"-265263912","predicate":"inputPeerNotifyEventsEmpty","params":[],"type":"InputPeerNotifyEvents"},{"id":"-395694988","predicate":"inputPeerNotifyEventsAll","params":[],"type":"InputPeerNotifyEvents"},{"id":"949182130","predicate":"inputPeerNotifySettings","params":[{"name":"flags","type":"#"},{"name":"show_previews","type":"flags.0?true"},{"name":"silent","type":"flags.1?true"},{"name":"mute_until","type":"int"},{"name":"sound","type":"string"}],"type":"InputPeerNotifySettings"},{"id":"-1378534221","predicate":"peerNotifyEventsEmpty","params":[],"type":"PeerNotifyEvents"},{"id":"1830677896","predicate":"peerNotifyEventsAll","params":[],"type":"PeerNotifyEvents"},{"id":"1889961234","predicate":"peerNotifySettingsEmpty","params":[],"type":"PeerNotifySettings"},{"id":"-1697798976","predicate":"peerNotifySettings","params":[{"name":"flags","type":"#"},{"name":"show_previews","type":"flags.0?true"},{"name":"silent","type":"flags.1?true"},{"name":"mute_until","type":"int"},{"name":"sound","type":"string"}],"type":"PeerNotifySettings"},{"id":"-2122045747","predicate":"peerSettings","params":[{"name":"flags","type":"#"},{"name":"report_spam","type":"flags.0?true"}],"type":"PeerSettings"},{"id":"-860866985","predicate":"wallPaper","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"sizes","type":"Vector<PhotoSize>"},{"name":"color","type":"int"}],"type":"WallPaper"},{"id":"1490799288","predicate":"inputReportReasonSpam","params":[],"type":"ReportReason"},{"id":"505595789","predicate":"inputReportReasonViolence","params":[],"type":"ReportReason"},{"id":"777640226","predicate":"inputReportReasonPornography","params":[],"type":"ReportReason"},{"id":"-512463606","predicate":"inputReportReasonOther","params":[{"name":"text","type":"string"}],"type":"ReportReason"},{"id":"1496513539","predicate":"userFull","params":[{"name":"flags","type":"#"},{"name":"blocked","type":"flags.0?true"},{"name":"user","type":"User"},{"name":"about","type":"flags.1?string"},{"name":"link","type":"contacts.Link"},{"name":"profile_photo","type":"flags.2?Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"bot_info","type":"flags.3?BotInfo"}],"type":"UserFull"},{"id":"-116274796","predicate":"contact","params":[{"name":"user_id","type":"int"},{"name":"mutual","type":"Bool"}],"type":"Contact"},{"id":"-805141448","predicate":"importedContact","params":[{"name":"user_id","type":"int"},{"name":"client_id","type":"long"}],"type":"ImportedContact"},{"id":"1444661369","predicate":"contactBlocked","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"ContactBlocked"},{"id":"-748155807","predicate":"contactStatus","params":[{"name":"user_id","type":"int"},{"name":"status","type":"UserStatus"}],"type":"ContactStatus"},{"id":"986597452","predicate":"contacts.link","params":[{"name":"my_link","type":"ContactLink"},{"name":"foreign_link","type":"ContactLink"},{"name":"user","type":"User"}],"type":"contacts.Link"},{"id":"-1219778094","predicate":"contacts.contactsNotModified","params":[],"type":"contacts.Contacts"},{"id":"1871416498","predicate":"contacts.contacts","params":[{"name":"contacts","type":"Vector<Contact>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.Contacts"},{"id":"-1387117803","predicate":"contacts.importedContacts","params":[{"name":"imported","type":"Vector<ImportedContact>"},{"name":"retry_contacts","type":"Vector<long>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.ImportedContacts"},{"id":"471043349","predicate":"contacts.blocked","params":[{"name":"blocked","type":"Vector<ContactBlocked>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.Blocked"},{"id":"-1878523231","predicate":"contacts.blockedSlice","params":[{"name":"count","type":"int"},{"name":"blocked","type":"Vector<ContactBlocked>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.Blocked"},{"id":"364538944","predicate":"messages.dialogs","params":[{"name":"dialogs","type":"Vector<Dialog>"},{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"messages.Dialogs"},{"id":"1910543603","predicate":"messages.dialogsSlice","params":[{"name":"count","type":"int"},{"name":"dialogs","type":"Vector<Dialog>"},{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"messages.Dialogs"},{"id":"-1938715001","predicate":"messages.messages","params":[{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"messages.Messages"},{"id":"189033187","predicate":"messages.messagesSlice","params":[{"name":"count","type":"int"},{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"messages.Messages"},{"id":"1694474197","predicate":"messages.chats","params":[{"name":"chats","type":"Vector<Chat>"}],"type":"messages.Chats"},{"id":"-438840932","predicate":"messages.chatFull","params":[{"name":"full_chat","type":"ChatFull"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"messages.ChatFull"},{"id":"-1269012015","predicate":"messages.affectedHistory","params":[{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"offset","type":"int"}],"type":"messages.AffectedHistory"},{"id":"1474492012","predicate":"inputMessagesFilterEmpty","params":[],"type":"MessagesFilter"},{"id":"-1777752804","predicate":"inputMessagesFilterPhotos","params":[],"type":"MessagesFilter"},{"id":"-1614803355","predicate":"inputMessagesFilterVideo","params":[],"type":"MessagesFilter"},{"id":"1458172132","predicate":"inputMessagesFilterPhotoVideo","params":[],"type":"MessagesFilter"},{"id":"-648121413","predicate":"inputMessagesFilterPhotoVideoDocuments","params":[],"type":"MessagesFilter"},{"id":"-1629621880","predicate":"inputMessagesFilterDocument","params":[],"type":"MessagesFilter"},{"id":"2129714567","predicate":"inputMessagesFilterUrl","params":[],"type":"MessagesFilter"},{"id":"-3644025","predicate":"inputMessagesFilterGif","params":[],"type":"MessagesFilter"},{"id":"522914557","predicate":"updateNewMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"1318109142","predicate":"updateMessageID","params":[{"name":"id","type":"int"},{"name":"random_id","type":"long"}],"type":"Update"},{"id":"-1576161051","predicate":"updateDeleteMessages","params":[{"name":"messages","type":"Vector<int>"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"1548249383","predicate":"updateUserTyping","params":[{"name":"user_id","type":"int"},{"name":"action","type":"SendMessageAction"}],"type":"Update"},{"id":"-1704596961","predicate":"updateChatUserTyping","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"action","type":"SendMessageAction"}],"type":"Update"},{"id":"125178264","predicate":"updateChatParticipants","params":[{"name":"participants","type":"ChatParticipants"}],"type":"Update"},{"id":"469489699","predicate":"updateUserStatus","params":[{"name":"user_id","type":"int"},{"name":"status","type":"UserStatus"}],"type":"Update"},{"id":"-1489818765","predicate":"updateUserName","params":[{"name":"user_id","type":"int"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"username","type":"string"}],"type":"Update"},{"id":"-1791935732","predicate":"updateUserPhoto","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"},{"name":"photo","type":"UserProfilePhoto"},{"name":"previous","type":"Bool"}],"type":"Update"},{"id":"628472761","predicate":"updateContactRegistered","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"Update"},{"id":"-1657903163","predicate":"updateContactLink","params":[{"name":"user_id","type":"int"},{"name":"my_link","type":"ContactLink"},{"name":"foreign_link","type":"ContactLink"}],"type":"Update"},{"id":"-1895411046","predicate":"updateNewAuthorization","params":[{"name":"auth_key_id","type":"long"},{"name":"date","type":"int"},{"name":"device","type":"string"},{"name":"location","type":"string"}],"type":"Update"},{"id":"-1519637954","predicate":"updates.state","params":[{"name":"pts","type":"int"},{"name":"qts","type":"int"},{"name":"date","type":"int"},{"name":"seq","type":"int"},{"name":"unread_count","type":"int"}],"type":"updates.State"},{"id":"1567990072","predicate":"updates.differenceEmpty","params":[{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"updates.Difference"},{"id":"16030880","predicate":"updates.difference","params":[{"name":"new_messages","type":"Vector<Message>"},{"name":"new_encrypted_messages","type":"Vector<EncryptedMessage>"},{"name":"other_updates","type":"Vector<Update>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"},{"name":"state","type":"updates.State"}],"type":"updates.Difference"},{"id":"-1459938943","predicate":"updates.differenceSlice","params":[{"name":"new_messages","type":"Vector<Message>"},{"name":"new_encrypted_messages","type":"Vector<EncryptedMessage>"},{"name":"other_updates","type":"Vector<Update>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"},{"name":"intermediate_state","type":"updates.State"}],"type":"updates.Difference"},{"id":"-484987010","predicate":"updatesTooLong","params":[],"type":"Updates"},{"id":"-1857044719","predicate":"updateShortMessage","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"id","type":"int"},{"name":"user_id","type":"int"},{"name":"message","type":"string"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"date","type":"int"},{"name":"fwd_from","type":"flags.2?MessageFwdHeader"},{"name":"via_bot_id","type":"flags.11?int"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"entities","type":"flags.7?Vector<MessageEntity>"}],"type":"Updates"},{"id":"377562760","predicate":"updateShortChatMessage","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"mentioned","type":"flags.4?true"},{"name":"media_unread","type":"flags.5?true"},{"name":"silent","type":"flags.13?true"},{"name":"id","type":"int"},{"name":"from_id","type":"int"},{"name":"chat_id","type":"int"},{"name":"message","type":"string"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"date","type":"int"},{"name":"fwd_from","type":"flags.2?MessageFwdHeader"},{"name":"via_bot_id","type":"flags.11?int"},{"name":"reply_to_msg_id","type":"flags.3?int"},{"name":"entities","type":"flags.7?Vector<MessageEntity>"}],"type":"Updates"},{"id":"2027216577","predicate":"updateShort","params":[{"name":"update","type":"Update"},{"name":"date","type":"int"}],"type":"Updates"},{"id":"1918567619","predicate":"updatesCombined","params":[{"name":"updates","type":"Vector<Update>"},{"name":"users","type":"Vector<User>"},{"name":"chats","type":"Vector<Chat>"},{"name":"date","type":"int"},{"name":"seq_start","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"1957577280","predicate":"updates","params":[{"name":"updates","type":"Vector<Update>"},{"name":"users","type":"Vector<User>"},{"name":"chats","type":"Vector<Chat>"},{"name":"date","type":"int"},{"name":"seq","type":"int"}],"type":"Updates"},{"id":"-1916114267","predicate":"photos.photos","params":[{"name":"photos","type":"Vector<Photo>"},{"name":"users","type":"Vector<User>"}],"type":"photos.Photos"},{"id":"352657236","predicate":"photos.photosSlice","params":[{"name":"count","type":"int"},{"name":"photos","type":"Vector<Photo>"},{"name":"users","type":"Vector<User>"}],"type":"photos.Photos"},{"id":"539045032","predicate":"photos.photo","params":[{"name":"photo","type":"Photo"},{"name":"users","type":"Vector<User>"}],"type":"photos.Photo"},{"id":"157948117","predicate":"upload.file","params":[{"name":"type","type":"storage.FileType"},{"name":"mtime","type":"int"},{"name":"bytes","type":"bytes"}],"type":"upload.File"},{"id":"98092748","predicate":"dcOption","params":[{"name":"flags","type":"#"},{"name":"ipv6","type":"flags.0?true"},{"name":"media_only","type":"flags.1?true"},{"name":"tcpo_only","type":"flags.2?true"},{"name":"id","type":"int"},{"name":"ip_address","type":"string"},{"name":"port","type":"int"}],"type":"DcOption"},{"id":"-1704251862","predicate":"config","params":[{"name":"flags","type":"#"},{"name":"date","type":"int"},{"name":"expires","type":"int"},{"name":"test_mode","type":"Bool"},{"name":"this_dc","type":"int"},{"name":"dc_options","type":"Vector<DcOption>"},{"name":"chat_size_max","type":"int"},{"name":"megagroup_size_max","type":"int"},{"name":"forwarded_count_max","type":"int"},{"name":"online_update_period_ms","type":"int"},{"name":"offline_blur_timeout_ms","type":"int"},{"name":"offline_idle_timeout_ms","type":"int"},{"name":"online_cloud_timeout_ms","type":"int"},{"name":"notify_cloud_delay_ms","type":"int"},{"name":"notify_default_delay_ms","type":"int"},{"name":"chat_big_size","type":"int"},{"name":"push_chat_period_ms","type":"int"},{"name":"push_chat_limit","type":"int"},{"name":"saved_gifs_limit","type":"int"},{"name":"edit_time_limit","type":"int"},{"name":"rating_e_decay","type":"int"},{"name":"stickers_recent_limit","type":"int"},{"name":"tmp_sessions","type":"flags.0?int"},{"name":"disabled_features","type":"Vector<DisabledFeature>"}],"type":"Config"},{"id":"-1910892683","predicate":"nearestDc","params":[{"name":"country","type":"string"},{"name":"this_dc","type":"int"},{"name":"nearest_dc","type":"int"}],"type":"NearestDc"},{"id":"-1987579119","predicate":"help.appUpdate","params":[{"name":"id","type":"int"},{"name":"critical","type":"Bool"},{"name":"url","type":"string"},{"name":"text","type":"string"}],"type":"help.AppUpdate"},{"id":"-1000708810","predicate":"help.noAppUpdate","params":[],"type":"help.AppUpdate"},{"id":"415997816","predicate":"help.inviteText","params":[{"name":"message","type":"string"}],"type":"help.InviteText"},{"id":"1662091044","predicate":"wallPaperSolid","params":[{"name":"id","type":"int"},{"name":"title","type":"string"},{"name":"bg_color","type":"int"},{"name":"color","type":"int"}],"type":"WallPaper"},{"id":"314359194","predicate":"updateNewEncryptedMessage","params":[{"name":"message","type":"EncryptedMessage"},{"name":"qts","type":"int"}],"type":"Update"},{"id":"386986326","predicate":"updateEncryptedChatTyping","params":[{"name":"chat_id","type":"int"}],"type":"Update"},{"id":"-1264392051","predicate":"updateEncryption","params":[{"name":"chat","type":"EncryptedChat"},{"name":"date","type":"int"}],"type":"Update"},{"id":"956179895","predicate":"updateEncryptedMessagesRead","params":[{"name":"chat_id","type":"int"},{"name":"max_date","type":"int"},{"name":"date","type":"int"}],"type":"Update"},{"id":"-1417756512","predicate":"encryptedChatEmpty","params":[{"name":"id","type":"int"}],"type":"EncryptedChat"},{"id":"1006044124","predicate":"encryptedChatWaiting","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"}],"type":"EncryptedChat"},{"id":"-931638658","predicate":"encryptedChatRequested","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"},{"name":"g_a","type":"bytes"}],"type":"EncryptedChat"},{"id":"-94974410","predicate":"encryptedChat","params":[{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"admin_id","type":"int"},{"name":"participant_id","type":"int"},{"name":"g_a_or_b","type":"bytes"},{"name":"key_fingerprint","type":"long"}],"type":"EncryptedChat"},{"id":"332848423","predicate":"encryptedChatDiscarded","params":[{"name":"id","type":"int"}],"type":"EncryptedChat"},{"id":"-247351839","predicate":"inputEncryptedChat","params":[{"name":"chat_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputEncryptedChat"},{"id":"-1038136962","predicate":"encryptedFileEmpty","params":[],"type":"EncryptedFile"},{"id":"1248893260","predicate":"encryptedFile","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"size","type":"int"},{"name":"dc_id","type":"int"},{"name":"key_fingerprint","type":"int"}],"type":"EncryptedFile"},{"id":"406307684","predicate":"inputEncryptedFileEmpty","params":[],"type":"InputEncryptedFile"},{"id":"1690108678","predicate":"inputEncryptedFileUploaded","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"md5_checksum","type":"string"},{"name":"key_fingerprint","type":"int"}],"type":"InputEncryptedFile"},{"id":"1511503333","predicate":"inputEncryptedFile","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputEncryptedFile"},{"id":"-182231723","predicate":"inputEncryptedFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputFileLocation"},{"id":"-317144808","predicate":"encryptedMessage","params":[{"name":"random_id","type":"long"},{"name":"chat_id","type":"int"},{"name":"date","type":"int"},{"name":"bytes","type":"bytes"},{"name":"file","type":"EncryptedFile"}],"type":"EncryptedMessage"},{"id":"594758406","predicate":"encryptedMessageService","params":[{"name":"random_id","type":"long"},{"name":"chat_id","type":"int"},{"name":"date","type":"int"},{"name":"bytes","type":"bytes"}],"type":"EncryptedMessage"},{"id":"-1058912715","predicate":"messages.dhConfigNotModified","params":[{"name":"random","type":"bytes"}],"type":"messages.DhConfig"},{"id":"740433629","predicate":"messages.dhConfig","params":[{"name":"g","type":"int"},{"name":"p","type":"bytes"},{"name":"version","type":"int"},{"name":"random","type":"bytes"}],"type":"messages.DhConfig"},{"id":"1443858741","predicate":"messages.sentEncryptedMessage","params":[{"name":"date","type":"int"}],"type":"messages.SentEncryptedMessage"},{"id":"-1802240206","predicate":"messages.sentEncryptedFile","params":[{"name":"date","type":"int"},{"name":"file","type":"EncryptedFile"}],"type":"messages.SentEncryptedMessage"},{"id":"-95482955","predicate":"inputFileBig","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"name","type":"string"}],"type":"InputFile"},{"id":"767652808","predicate":"inputEncryptedFileBigUploaded","params":[{"name":"id","type":"long"},{"name":"parts","type":"int"},{"name":"key_fingerprint","type":"int"}],"type":"InputEncryptedFile"},{"id":"-364179876","predicate":"updateChatParticipantAdd","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"},{"name":"version","type":"int"}],"type":"Update"},{"id":"1851755554","predicate":"updateChatParticipantDelete","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"version","type":"int"}],"type":"Update"},{"id":"-1906403213","predicate":"updateDcOptions","params":[{"name":"dc_options","type":"Vector<DcOption>"}],"type":"Update"},{"id":"-797904407","predicate":"inputMediaUploadedDocument","params":[{"name":"flags","type":"#"},{"name":"file","type":"InputFile"},{"name":"mime_type","type":"string"},{"name":"attributes","type":"Vector<DocumentAttribute>"},{"name":"caption","type":"string"},{"name":"stickers","type":"flags.0?Vector<InputDocument>"}],"type":"InputMedia"},{"id":"1356369070","predicate":"inputMediaUploadedThumbDocument","params":[{"name":"flags","type":"#"},{"name":"file","type":"InputFile"},{"name":"thumb","type":"InputFile"},{"name":"mime_type","type":"string"},{"name":"attributes","type":"Vector<DocumentAttribute>"},{"name":"caption","type":"string"},{"name":"stickers","type":"flags.0?Vector<InputDocument>"}],"type":"InputMedia"},{"id":"444068508","predicate":"inputMediaDocument","params":[{"name":"id","type":"InputDocument"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-203411800","predicate":"messageMediaDocument","params":[{"name":"document","type":"Document"},{"name":"caption","type":"string"}],"type":"MessageMedia"},{"id":"1928391342","predicate":"inputDocumentEmpty","params":[],"type":"InputDocument"},{"id":"410618194","predicate":"inputDocument","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputDocument"},{"id":"1125058340","predicate":"inputDocumentFileLocation","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"version","type":"int"}],"type":"InputFileLocation"},{"id":"922273905","predicate":"documentEmpty","params":[{"name":"id","type":"long"}],"type":"Document"},{"id":"-2027738169","predicate":"document","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"date","type":"int"},{"name":"mime_type","type":"string"},{"name":"size","type":"int"},{"name":"thumb","type":"PhotoSize"},{"name":"dc_id","type":"int"},{"name":"version","type":"int"},{"name":"attributes","type":"Vector<DocumentAttribute>"}],"type":"Document"},{"id":"398898678","predicate":"help.support","params":[{"name":"phone_number","type":"string"},{"name":"user","type":"User"}],"type":"help.Support"},{"id":"-1613493288","predicate":"notifyPeer","params":[{"name":"peer","type":"Peer"}],"type":"NotifyPeer"},{"id":"-1261946036","predicate":"notifyUsers","params":[],"type":"NotifyPeer"},{"id":"-1073230141","predicate":"notifyChats","params":[],"type":"NotifyPeer"},{"id":"1959820384","predicate":"notifyAll","params":[],"type":"NotifyPeer"},{"id":"-2131957734","predicate":"updateUserBlocked","params":[{"name":"user_id","type":"int"},{"name":"blocked","type":"Bool"}],"type":"Update"},{"id":"-1094555409","predicate":"updateNotifySettings","params":[{"name":"peer","type":"NotifyPeer"},{"name":"notify_settings","type":"PeerNotifySettings"}],"type":"Update"},{"id":"381645902","predicate":"sendMessageTypingAction","params":[],"type":"SendMessageAction"},{"id":"-44119819","predicate":"sendMessageCancelAction","params":[],"type":"SendMessageAction"},{"id":"-1584933265","predicate":"sendMessageRecordVideoAction","params":[],"type":"SendMessageAction"},{"id":"-378127636","predicate":"sendMessageUploadVideoAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"-718310409","predicate":"sendMessageRecordAudioAction","params":[],"type":"SendMessageAction"},{"id":"-212740181","predicate":"sendMessageUploadAudioAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"-774682074","predicate":"sendMessageUploadPhotoAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"-1441998364","predicate":"sendMessageUploadDocumentAction","params":[{"name":"progress","type":"int"}],"type":"SendMessageAction"},{"id":"393186209","predicate":"sendMessageGeoLocationAction","params":[],"type":"SendMessageAction"},{"id":"1653390447","predicate":"sendMessageChooseContactAction","params":[],"type":"SendMessageAction"},{"id":"446822276","predicate":"contacts.found","params":[{"name":"results","type":"Vector<Peer>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.Found"},{"id":"942527460","predicate":"updateServiceNotification","params":[{"name":"type","type":"string"},{"name":"message","type":"string"},{"name":"media","type":"MessageMedia"},{"name":"popup","type":"Bool"}],"type":"Update"},{"id":"-496024847","predicate":"userStatusRecently","params":[],"type":"UserStatus"},{"id":"129960444","predicate":"userStatusLastWeek","params":[],"type":"UserStatus"},{"id":"2011940674","predicate":"userStatusLastMonth","params":[],"type":"UserStatus"},{"id":"-298113238","predicate":"updatePrivacy","params":[{"name":"key","type":"PrivacyKey"},{"name":"rules","type":"Vector<PrivacyRule>"}],"type":"Update"},{"id":"1335282456","predicate":"inputPrivacyKeyStatusTimestamp","params":[],"type":"InputPrivacyKey"},{"id":"-1137792208","predicate":"privacyKeyStatusTimestamp","params":[],"type":"PrivacyKey"},{"id":"218751099","predicate":"inputPrivacyValueAllowContacts","params":[],"type":"InputPrivacyRule"},{"id":"407582158","predicate":"inputPrivacyValueAllowAll","params":[],"type":"InputPrivacyRule"},{"id":"320652927","predicate":"inputPrivacyValueAllowUsers","params":[{"name":"users","type":"Vector<InputUser>"}],"type":"InputPrivacyRule"},{"id":"195371015","predicate":"inputPrivacyValueDisallowContacts","params":[],"type":"InputPrivacyRule"},{"id":"-697604407","predicate":"inputPrivacyValueDisallowAll","params":[],"type":"InputPrivacyRule"},{"id":"-1877932953","predicate":"inputPrivacyValueDisallowUsers","params":[{"name":"users","type":"Vector<InputUser>"}],"type":"InputPrivacyRule"},{"id":"-123988","predicate":"privacyValueAllowContacts","params":[],"type":"PrivacyRule"},{"id":"1698855810","predicate":"privacyValueAllowAll","params":[],"type":"PrivacyRule"},{"id":"1297858060","predicate":"privacyValueAllowUsers","params":[{"name":"users","type":"Vector<int>"}],"type":"PrivacyRule"},{"id":"-125240806","predicate":"privacyValueDisallowContacts","params":[],"type":"PrivacyRule"},{"id":"-1955338397","predicate":"privacyValueDisallowAll","params":[],"type":"PrivacyRule"},{"id":"209668535","predicate":"privacyValueDisallowUsers","params":[{"name":"users","type":"Vector<int>"}],"type":"PrivacyRule"},{"id":"1430961007","predicate":"account.privacyRules","params":[{"name":"rules","type":"Vector<PrivacyRule>"},{"name":"users","type":"Vector<User>"}],"type":"account.PrivacyRules"},{"id":"-1194283041","predicate":"accountDaysTTL","params":[{"name":"days","type":"int"}],"type":"AccountDaysTTL"},{"id":"314130811","predicate":"updateUserPhone","params":[{"name":"user_id","type":"int"},{"name":"phone","type":"string"}],"type":"Update"},{"id":"1815593308","predicate":"documentAttributeImageSize","params":[{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"DocumentAttribute"},{"id":"297109817","predicate":"documentAttributeAnimated","params":[],"type":"DocumentAttribute"},{"id":"1662637586","predicate":"documentAttributeSticker","params":[{"name":"flags","type":"#"},{"name":"mask","type":"flags.1?true"},{"name":"alt","type":"string"},{"name":"stickerset","type":"InputStickerSet"},{"name":"mask_coords","type":"flags.0?MaskCoords"}],"type":"DocumentAttribute"},{"id":"1494273227","predicate":"documentAttributeVideo","params":[{"name":"duration","type":"int"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"DocumentAttribute"},{"id":"-1739392570","predicate":"documentAttributeAudio","params":[{"name":"flags","type":"#"},{"name":"voice","type":"flags.10?true"},{"name":"duration","type":"int"},{"name":"title","type":"flags.0?string"},{"name":"performer","type":"flags.1?string"},{"name":"waveform","type":"flags.2?bytes"}],"type":"DocumentAttribute"},{"id":"358154344","predicate":"documentAttributeFilename","params":[{"name":"file_name","type":"string"}],"type":"DocumentAttribute"},{"id":"-244016606","predicate":"messages.stickersNotModified","params":[],"type":"messages.Stickers"},{"id":"-1970352846","predicate":"messages.stickers","params":[{"name":"hash","type":"string"},{"name":"stickers","type":"Vector<Document>"}],"type":"messages.Stickers"},{"id":"313694676","predicate":"stickerPack","params":[{"name":"emoticon","type":"string"},{"name":"documents","type":"Vector<long>"}],"type":"StickerPack"},{"id":"-395967805","predicate":"messages.allStickersNotModified","params":[],"type":"messages.AllStickers"},{"id":"-302170017","predicate":"messages.allStickers","params":[{"name":"hash","type":"int"},{"name":"sets","type":"Vector<StickerSet>"}],"type":"messages.AllStickers"},{"id":"-1369215196","predicate":"disabledFeature","params":[{"name":"feature","type":"string"},{"name":"description","type":"string"}],"type":"DisabledFeature"},{"id":"-1721631396","predicate":"updateReadHistoryInbox","params":[{"name":"peer","type":"Peer"},{"name":"max_id","type":"int"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"791617983","predicate":"updateReadHistoryOutbox","params":[{"name":"peer","type":"Peer"},{"name":"max_id","type":"int"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-2066640507","predicate":"messages.affectedMessages","params":[{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"messages.AffectedMessages"},{"id":"1599050311","predicate":"contactLinkUnknown","params":[],"type":"ContactLink"},{"id":"-17968211","predicate":"contactLinkNone","params":[],"type":"ContactLink"},{"id":"646922073","predicate":"contactLinkHasPhone","params":[],"type":"ContactLink"},{"id":"-721239344","predicate":"contactLinkContact","params":[],"type":"ContactLink"},{"id":"2139689491","predicate":"updateWebPage","params":[{"name":"webpage","type":"WebPage"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-350980120","predicate":"webPageEmpty","params":[{"name":"id","type":"long"}],"type":"WebPage"},{"id":"-981018084","predicate":"webPagePending","params":[{"name":"id","type":"long"},{"name":"date","type":"int"}],"type":"WebPage"},{"id":"-897446185","predicate":"webPage","params":[{"name":"flags","type":"#"},{"name":"id","type":"long"},{"name":"url","type":"string"},{"name":"display_url","type":"string"},{"name":"type","type":"flags.0?string"},{"name":"site_name","type":"flags.1?string"},{"name":"title","type":"flags.2?string"},{"name":"description","type":"flags.3?string"},{"name":"photo","type":"flags.4?Photo"},{"name":"embed_url","type":"flags.5?string"},{"name":"embed_type","type":"flags.5?string"},{"name":"embed_width","type":"flags.6?int"},{"name":"embed_height","type":"flags.6?int"},{"name":"duration","type":"flags.7?int"},{"name":"author","type":"flags.8?string"},{"name":"document","type":"flags.9?Document"}],"type":"WebPage"},{"id":"-1557277184","predicate":"messageMediaWebPage","params":[{"name":"webpage","type":"WebPage"}],"type":"MessageMedia"},{"id":"2079516406","predicate":"authorization","params":[{"name":"hash","type":"long"},{"name":"flags","type":"int"},{"name":"device_model","type":"string"},{"name":"platform","type":"string"},{"name":"system_version","type":"string"},{"name":"api_id","type":"int"},{"name":"app_name","type":"string"},{"name":"app_version","type":"string"},{"name":"date_created","type":"int"},{"name":"date_active","type":"int"},{"name":"ip","type":"string"},{"name":"country","type":"string"},{"name":"region","type":"string"}],"type":"Authorization"},{"id":"307276766","predicate":"account.authorizations","params":[{"name":"authorizations","type":"Vector<Authorization>"}],"type":"account.Authorizations"},{"id":"-1764049896","predicate":"account.noPassword","params":[{"name":"new_salt","type":"bytes"},{"name":"email_unconfirmed_pattern","type":"string"}],"type":"account.Password"},{"id":"2081952796","predicate":"account.password","params":[{"name":"current_salt","type":"bytes"},{"name":"new_salt","type":"bytes"},{"name":"hint","type":"string"},{"name":"has_recovery","type":"Bool"},{"name":"email_unconfirmed_pattern","type":"string"}],"type":"account.Password"},{"id":"-1212732749","predicate":"account.passwordSettings","params":[{"name":"email","type":"string"}],"type":"account.PasswordSettings"},{"id":"-2037289493","predicate":"account.passwordInputSettings","params":[{"name":"flags","type":"#"},{"name":"new_salt","type":"flags.0?bytes"},{"name":"new_password_hash","type":"flags.0?bytes"},{"name":"hint","type":"flags.0?string"},{"name":"email","type":"flags.1?string"}],"type":"account.PasswordInputSettings"},{"id":"326715557","predicate":"auth.passwordRecovery","params":[{"name":"email_pattern","type":"string"}],"type":"auth.PasswordRecovery"},{"id":"673687578","predicate":"inputMediaVenue","params":[{"name":"geo_point","type":"InputGeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"}],"type":"InputMedia"},{"id":"2031269663","predicate":"messageMediaVenue","params":[{"name":"geo","type":"GeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"}],"type":"MessageMedia"},{"id":"-1551583367","predicate":"receivedNotifyMessage","params":[{"name":"id","type":"int"},{"name":"flags","type":"int"}],"type":"ReceivedNotifyMessage"},{"id":"1776236393","predicate":"chatInviteEmpty","params":[],"type":"ExportedChatInvite"},{"id":"-64092740","predicate":"chatInviteExported","params":[{"name":"link","type":"string"}],"type":"ExportedChatInvite"},{"id":"1516793212","predicate":"chatInviteAlready","params":[{"name":"chat","type":"Chat"}],"type":"ChatInvite"},{"id":"-613092008","predicate":"chatInvite","params":[{"name":"flags","type":"#"},{"name":"channel","type":"flags.0?true"},{"name":"broadcast","type":"flags.1?true"},{"name":"public","type":"flags.2?true"},{"name":"megagroup","type":"flags.3?true"},{"name":"title","type":"string"},{"name":"photo","type":"ChatPhoto"},{"name":"participants_count","type":"int"},{"name":"participants","type":"flags.4?Vector<User>"}],"type":"ChatInvite"},{"id":"-123931160","predicate":"messageActionChatJoinedByLink","params":[{"name":"inviter_id","type":"int"}],"type":"MessageAction"},{"id":"1757493555","predicate":"updateReadMessagesContents","params":[{"name":"messages","type":"Vector<int>"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-4838507","predicate":"inputStickerSetEmpty","params":[],"type":"InputStickerSet"},{"id":"-1645763991","predicate":"inputStickerSetID","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputStickerSet"},{"id":"-2044933984","predicate":"inputStickerSetShortName","params":[{"name":"short_name","type":"string"}],"type":"InputStickerSet"},{"id":"-852477119","predicate":"stickerSet","params":[{"name":"flags","type":"#"},{"name":"installed","type":"flags.0?true"},{"name":"archived","type":"flags.1?true"},{"name":"official","type":"flags.2?true"},{"name":"masks","type":"flags.3?true"},{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"title","type":"string"},{"name":"short_name","type":"string"},{"name":"count","type":"int"},{"name":"hash","type":"int"}],"type":"StickerSet"},{"id":"-1240849242","predicate":"messages.stickerSet","params":[{"name":"set","type":"StickerSet"},{"name":"packs","type":"Vector<StickerPack>"},{"name":"documents","type":"Vector<Document>"}],"type":"messages.StickerSet"},{"id":"-787638374","predicate":"user","params":[{"name":"flags","type":"#"},{"name":"self","type":"flags.10?true"},{"name":"contact","type":"flags.11?true"},{"name":"mutual_contact","type":"flags.12?true"},{"name":"deleted","type":"flags.13?true"},{"name":"bot","type":"flags.14?true"},{"name":"bot_chat_history","type":"flags.15?true"},{"name":"bot_nochats","type":"flags.16?true"},{"name":"verified","type":"flags.17?true"},{"name":"restricted","type":"flags.18?true"},{"name":"min","type":"flags.20?true"},{"name":"bot_inline_geo","type":"flags.21?true"},{"name":"id","type":"int"},{"name":"access_hash","type":"flags.0?long"},{"name":"first_name","type":"flags.1?string"},{"name":"last_name","type":"flags.2?string"},{"name":"username","type":"flags.3?string"},{"name":"phone","type":"flags.4?string"},{"name":"photo","type":"flags.5?UserProfilePhoto"},{"name":"status","type":"flags.6?UserStatus"},{"name":"bot_info_version","type":"flags.14?int"},{"name":"restriction_reason","type":"flags.18?string"},{"name":"bot_inline_placeholder","type":"flags.19?string"}],"type":"User"},{"id":"-1032140601","predicate":"botCommand","params":[{"name":"command","type":"string"},{"name":"description","type":"string"}],"type":"BotCommand"},{"id":"-1729618630","predicate":"botInfo","params":[{"name":"user_id","type":"int"},{"name":"description","type":"string"},{"name":"commands","type":"Vector<BotCommand>"}],"type":"BotInfo"},{"id":"-1560655744","predicate":"keyboardButton","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"2002815875","predicate":"keyboardButtonRow","params":[{"name":"buttons","type":"Vector<KeyboardButton>"}],"type":"KeyboardButtonRow"},{"id":"-1606526075","predicate":"replyKeyboardHide","params":[{"name":"flags","type":"#"},{"name":"selective","type":"flags.2?true"}],"type":"ReplyMarkup"},{"id":"-200242528","predicate":"replyKeyboardForceReply","params":[{"name":"flags","type":"#"},{"name":"single_use","type":"flags.1?true"},{"name":"selective","type":"flags.2?true"}],"type":"ReplyMarkup"},{"id":"889353612","predicate":"replyKeyboardMarkup","params":[{"name":"flags","type":"#"},{"name":"resize","type":"flags.0?true"},{"name":"single_use","type":"flags.1?true"},{"name":"selective","type":"flags.2?true"},{"name":"rows","type":"Vector<KeyboardButtonRow>"}],"type":"ReplyMarkup"},{"id":"2072935910","predicate":"inputPeerUser","params":[{"name":"user_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputPeer"},{"id":"-668391402","predicate":"inputUser","params":[{"name":"user_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputUser"},{"id":"-1350696044","predicate":"help.appChangelogEmpty","params":[],"type":"help.AppChangelog"},{"id":"1181279933","predicate":"help.appChangelog","params":[{"name":"text","type":"string"}],"type":"help.AppChangelog"},{"id":"-1148011883","predicate":"messageEntityUnknown","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"-100378723","predicate":"messageEntityMention","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1868782349","predicate":"messageEntityHashtag","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1827637959","predicate":"messageEntityBotCommand","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1859134776","predicate":"messageEntityUrl","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1692693954","predicate":"messageEntityEmail","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"-1117713463","predicate":"messageEntityBold","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"-2106619040","predicate":"messageEntityItalic","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"681706865","predicate":"messageEntityCode","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"}],"type":"MessageEntity"},{"id":"1938967520","predicate":"messageEntityPre","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"language","type":"string"}],"type":"MessageEntity"},{"id":"1990644519","predicate":"messageEntityTextUrl","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"url","type":"string"}],"type":"MessageEntity"},{"id":"301019932","predicate":"updateShortSentMessage","params":[{"name":"flags","type":"#"},{"name":"out","type":"flags.1?true"},{"name":"id","type":"int"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"},{"name":"date","type":"int"},{"name":"media","type":"flags.9?MessageMedia"},{"name":"entities","type":"flags.7?Vector<MessageEntity>"}],"type":"Updates"},{"id":"-292807034","predicate":"inputChannelEmpty","params":[],"type":"InputChannel"},{"id":"-1343524562","predicate":"inputChannel","params":[{"name":"channel_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputChannel"},{"id":"-1109531342","predicate":"peerChannel","params":[{"name":"channel_id","type":"int"}],"type":"Peer"},{"id":"548253432","predicate":"inputPeerChannel","params":[{"name":"channel_id","type":"int"},{"name":"access_hash","type":"long"}],"type":"InputPeer"},{"id":"-1588737454","predicate":"channel","params":[{"name":"flags","type":"#"},{"name":"creator","type":"flags.0?true"},{"name":"kicked","type":"flags.1?true"},{"name":"left","type":"flags.2?true"},{"name":"editor","type":"flags.3?true"},{"name":"moderator","type":"flags.4?true"},{"name":"broadcast","type":"flags.5?true"},{"name":"verified","type":"flags.7?true"},{"name":"megagroup","type":"flags.8?true"},{"name":"restricted","type":"flags.9?true"},{"name":"democracy","type":"flags.10?true"},{"name":"signatures","type":"flags.11?true"},{"name":"min","type":"flags.12?true"},{"name":"id","type":"int"},{"name":"access_hash","type":"flags.13?long"},{"name":"title","type":"string"},{"name":"username","type":"flags.6?string"},{"name":"photo","type":"ChatPhoto"},{"name":"date","type":"int"},{"name":"version","type":"int"},{"name":"restriction_reason","type":"flags.9?string"}],"type":"Chat"},{"id":"-2059962289","predicate":"channelForbidden","params":[{"name":"flags","type":"#"},{"name":"broadcast","type":"flags.5?true"},{"name":"megagroup","type":"flags.8?true"},{"name":"id","type":"int"},{"name":"access_hash","type":"long"},{"name":"title","type":"string"}],"type":"Chat"},{"id":"2131196633","predicate":"contacts.resolvedPeer","params":[{"name":"peer","type":"Peer"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.ResolvedPeer"},{"id":"-1009430225","predicate":"channelFull","params":[{"name":"flags","type":"#"},{"name":"can_view_participants","type":"flags.3?true"},{"name":"can_set_username","type":"flags.6?true"},{"name":"id","type":"int"},{"name":"about","type":"string"},{"name":"participants_count","type":"flags.0?int"},{"name":"admins_count","type":"flags.1?int"},{"name":"kicked_count","type":"flags.2?int"},{"name":"read_inbox_max_id","type":"int"},{"name":"read_outbox_max_id","type":"int"},{"name":"unread_count","type":"int"},{"name":"chat_photo","type":"Photo"},{"name":"notify_settings","type":"PeerNotifySettings"},{"name":"exported_invite","type":"ExportedChatInvite"},{"name":"bot_info","type":"Vector<BotInfo>"},{"name":"migrated_from_chat_id","type":"flags.4?int"},{"name":"migrated_from_max_id","type":"flags.4?int"},{"name":"pinned_msg_id","type":"flags.5?int"}],"type":"ChatFull"},{"id":"182649427","predicate":"messageRange","params":[{"name":"min_id","type":"int"},{"name":"max_id","type":"int"}],"type":"MessageRange"},{"id":"-1725551049","predicate":"messages.channelMessages","params":[{"name":"flags","type":"#"},{"name":"pts","type":"int"},{"name":"count","type":"int"},{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"messages.Messages"},{"id":"-1781355374","predicate":"messageActionChannelCreate","params":[{"name":"title","type":"string"}],"type":"MessageAction"},{"id":"-352032773","predicate":"updateChannelTooLong","params":[{"name":"flags","type":"#"},{"name":"channel_id","type":"int"},{"name":"pts","type":"flags.0?int"}],"type":"Update"},{"id":"-1227598250","predicate":"updateChannel","params":[{"name":"channel_id","type":"int"}],"type":"Update"},{"id":"1656358105","predicate":"updateNewChannelMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"1108669311","predicate":"updateReadChannelInbox","params":[{"name":"channel_id","type":"int"},{"name":"max_id","type":"int"}],"type":"Update"},{"id":"-1015733815","predicate":"updateDeleteChannelMessages","params":[{"name":"channel_id","type":"int"},{"name":"messages","type":"Vector<int>"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-1734268085","predicate":"updateChannelMessageViews","params":[{"name":"channel_id","type":"int"},{"name":"id","type":"int"},{"name":"views","type":"int"}],"type":"Update"},{"id":"1041346555","predicate":"updates.channelDifferenceEmpty","params":[{"name":"flags","type":"#"},{"name":"final","type":"flags.0?true"},{"name":"pts","type":"int"},{"name":"timeout","type":"flags.1?int"}],"type":"updates.ChannelDifference"},{"id":"1091431943","predicate":"updates.channelDifferenceTooLong","params":[{"name":"flags","type":"#"},{"name":"final","type":"flags.0?true"},{"name":"pts","type":"int"},{"name":"timeout","type":"flags.1?int"},{"name":"top_message","type":"int"},{"name":"read_inbox_max_id","type":"int"},{"name":"read_outbox_max_id","type":"int"},{"name":"unread_count","type":"int"},{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"updates.ChannelDifference"},{"id":"543450958","predicate":"updates.channelDifference","params":[{"name":"flags","type":"#"},{"name":"final","type":"flags.0?true"},{"name":"pts","type":"int"},{"name":"timeout","type":"flags.1?int"},{"name":"new_messages","type":"Vector<Message>"},{"name":"other_updates","type":"Vector<Update>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"updates.ChannelDifference"},{"id":"-1798033689","predicate":"channelMessagesFilterEmpty","params":[],"type":"ChannelMessagesFilter"},{"id":"-847783593","predicate":"channelMessagesFilter","params":[{"name":"flags","type":"#"},{"name":"exclude_new_messages","type":"flags.1?true"},{"name":"ranges","type":"Vector<MessageRange>"}],"type":"ChannelMessagesFilter"},{"id":"367766557","predicate":"channelParticipant","params":[{"name":"user_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1557620115","predicate":"channelParticipantSelf","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1861910545","predicate":"channelParticipantModerator","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1743180447","predicate":"channelParticipantEditor","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-1933187430","predicate":"channelParticipantKicked","params":[{"name":"user_id","type":"int"},{"name":"kicked_by","type":"int"},{"name":"date","type":"int"}],"type":"ChannelParticipant"},{"id":"-471670279","predicate":"channelParticipantCreator","params":[{"name":"user_id","type":"int"}],"type":"ChannelParticipant"},{"id":"-566281095","predicate":"channelParticipantsRecent","params":[],"type":"ChannelParticipantsFilter"},{"id":"-1268741783","predicate":"channelParticipantsAdmins","params":[],"type":"ChannelParticipantsFilter"},{"id":"1010285434","predicate":"channelParticipantsKicked","params":[],"type":"ChannelParticipantsFilter"},{"id":"-1299865402","predicate":"channelRoleEmpty","params":[],"type":"ChannelParticipantRole"},{"id":"-1776756363","predicate":"channelRoleModerator","params":[],"type":"ChannelParticipantRole"},{"id":"-2113143156","predicate":"channelRoleEditor","params":[],"type":"ChannelParticipantRole"},{"id":"-177282392","predicate":"channels.channelParticipants","params":[{"name":"count","type":"int"},{"name":"participants","type":"Vector<ChannelParticipant>"},{"name":"users","type":"Vector<User>"}],"type":"channels.ChannelParticipants"},{"id":"-791039645","predicate":"channels.channelParticipant","params":[{"name":"participant","type":"ChannelParticipant"},{"name":"users","type":"Vector<User>"}],"type":"channels.ChannelParticipant"},{"id":"-636267638","predicate":"chatParticipantCreator","params":[{"name":"user_id","type":"int"}],"type":"ChatParticipant"},{"id":"-489233354","predicate":"chatParticipantAdmin","params":[{"name":"user_id","type":"int"},{"name":"inviter_id","type":"int"},{"name":"date","type":"int"}],"type":"ChatParticipant"},{"id":"1855224129","predicate":"updateChatAdmins","params":[{"name":"chat_id","type":"int"},{"name":"enabled","type":"Bool"},{"name":"version","type":"int"}],"type":"Update"},{"id":"-1232070311","predicate":"updateChatParticipantAdmin","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"int"},{"name":"is_admin","type":"Bool"},{"name":"version","type":"int"}],"type":"Update"},{"id":"1371385889","predicate":"messageActionChatMigrateTo","params":[{"name":"channel_id","type":"int"}],"type":"MessageAction"},{"id":"-1336546578","predicate":"messageActionChannelMigrateFrom","params":[{"name":"title","type":"string"},{"name":"chat_id","type":"int"}],"type":"MessageAction"},{"id":"-1328445861","predicate":"channelParticipantsBots","params":[],"type":"ChannelParticipantsFilter"},{"id":"-236044656","predicate":"help.termsOfService","params":[{"name":"text","type":"string"}],"type":"help.TermsOfService"},{"id":"1753886890","predicate":"updateNewStickerSet","params":[{"name":"stickerset","type":"messages.StickerSet"}],"type":"Update"},{"id":"196268545","predicate":"updateStickerSetsOrder","params":[{"name":"flags","type":"#"},{"name":"masks","type":"flags.0?true"},{"name":"order","type":"Vector<long>"}],"type":"Update"},{"id":"1135492588","predicate":"updateStickerSets","params":[],"type":"Update"},{"id":"372165663","predicate":"foundGif","params":[{"name":"url","type":"string"},{"name":"thumb_url","type":"string"},{"name":"content_url","type":"string"},{"name":"content_type","type":"string"},{"name":"w","type":"int"},{"name":"h","type":"int"}],"type":"FoundGif"},{"id":"-1670052855","predicate":"foundGifCached","params":[{"name":"url","type":"string"},{"name":"photo","type":"Photo"},{"name":"document","type":"Document"}],"type":"FoundGif"},{"id":"1212395773","predicate":"inputMediaGifExternal","params":[{"name":"url","type":"string"},{"name":"q","type":"string"}],"type":"InputMedia"},{"id":"1158290442","predicate":"messages.foundGifs","params":[{"name":"next_offset","type":"int"},{"name":"results","type":"Vector<FoundGif>"}],"type":"messages.FoundGifs"},{"id":"-402498398","predicate":"messages.savedGifsNotModified","params":[],"type":"messages.SavedGifs"},{"id":"772213157","predicate":"messages.savedGifs","params":[{"name":"hash","type":"int"},{"name":"gifs","type":"Vector<Document>"}],"type":"messages.SavedGifs"},{"id":"-1821035490","predicate":"updateSavedGifs","params":[],"type":"Update"},{"id":"691006739","predicate":"inputBotInlineMessageMediaAuto","params":[{"name":"flags","type":"#"},{"name":"caption","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"1036876423","predicate":"inputBotInlineMessageText","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.0?true"},{"name":"message","type":"string"},{"name":"entities","type":"flags.1?Vector<MessageEntity>"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"750510426","predicate":"inputBotInlineResult","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"title","type":"flags.1?string"},{"name":"description","type":"flags.2?string"},{"name":"url","type":"flags.3?string"},{"name":"thumb_url","type":"flags.4?string"},{"name":"content_url","type":"flags.5?string"},{"name":"content_type","type":"flags.5?string"},{"name":"w","type":"flags.6?int"},{"name":"h","type":"flags.6?int"},{"name":"duration","type":"flags.7?int"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"175419739","predicate":"botInlineMessageMediaAuto","params":[{"name":"flags","type":"#"},{"name":"caption","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"-1937807902","predicate":"botInlineMessageText","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.0?true"},{"name":"message","type":"string"},{"name":"entities","type":"flags.1?Vector<MessageEntity>"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"-1679053127","predicate":"botInlineResult","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"title","type":"flags.1?string"},{"name":"description","type":"flags.2?string"},{"name":"url","type":"flags.3?string"},{"name":"thumb_url","type":"flags.4?string"},{"name":"content_url","type":"flags.5?string"},{"name":"content_type","type":"flags.5?string"},{"name":"w","type":"flags.6?int"},{"name":"h","type":"flags.6?int"},{"name":"duration","type":"flags.7?int"},{"name":"send_message","type":"BotInlineMessage"}],"type":"BotInlineResult"},{"id":"627509670","predicate":"messages.botResults","params":[{"name":"flags","type":"#"},{"name":"gallery","type":"flags.0?true"},{"name":"query_id","type":"long"},{"name":"next_offset","type":"flags.1?string"},{"name":"switch_pm","type":"flags.2?InlineBotSwitchPM"},{"name":"results","type":"Vector<BotInlineResult>"}],"type":"messages.BotResults"},{"id":"1417832080","predicate":"updateBotInlineQuery","params":[{"name":"flags","type":"#"},{"name":"query_id","type":"long"},{"name":"user_id","type":"int"},{"name":"query","type":"string"},{"name":"geo","type":"flags.0?GeoPoint"},{"name":"offset","type":"string"}],"type":"Update"},{"id":"239663460","predicate":"updateBotInlineSend","params":[{"name":"flags","type":"#"},{"name":"user_id","type":"int"},{"name":"query","type":"string"},{"name":"geo","type":"flags.0?GeoPoint"},{"name":"id","type":"string"},{"name":"msg_id","type":"flags.1?InputBotInlineMessageID"}],"type":"Update"},{"id":"1358283666","predicate":"inputMessagesFilterVoice","params":[],"type":"MessagesFilter"},{"id":"928101534","predicate":"inputMessagesFilterMusic","params":[],"type":"MessagesFilter"},{"id":"-1107622874","predicate":"inputPrivacyKeyChatInvite","params":[],"type":"InputPrivacyKey"},{"id":"1343122938","predicate":"privacyKeyChatInvite","params":[],"type":"PrivacyKey"},{"id":"524838915","predicate":"exportedMessageLink","params":[{"name":"link","type":"string"}],"type":"ExportedMessageLink"},{"id":"-947462709","predicate":"messageFwdHeader","params":[{"name":"flags","type":"#"},{"name":"from_id","type":"flags.0?int"},{"name":"date","type":"int"},{"name":"channel_id","type":"flags.1?int"},{"name":"channel_post","type":"flags.2?int"}],"type":"MessageFwdHeader"},{"id":"457133559","predicate":"updateEditChannelMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-1738988427","predicate":"updateChannelPinnedMessage","params":[{"name":"channel_id","type":"int"},{"name":"id","type":"int"}],"type":"Update"},{"id":"-1799538451","predicate":"messageActionPinMessage","params":[],"type":"MessageAction"},{"id":"1923290508","predicate":"auth.codeTypeSms","params":[],"type":"auth.CodeType"},{"id":"1948046307","predicate":"auth.codeTypeCall","params":[],"type":"auth.CodeType"},{"id":"577556219","predicate":"auth.codeTypeFlashCall","params":[],"type":"auth.CodeType"},{"id":"1035688326","predicate":"auth.sentCodeTypeApp","params":[{"name":"length","type":"int"}],"type":"auth.SentCodeType"},{"id":"-1073693790","predicate":"auth.sentCodeTypeSms","params":[{"name":"length","type":"int"}],"type":"auth.SentCodeType"},{"id":"1398007207","predicate":"auth.sentCodeTypeCall","params":[{"name":"length","type":"int"}],"type":"auth.SentCodeType"},{"id":"-1425815847","predicate":"auth.sentCodeTypeFlashCall","params":[{"name":"pattern","type":"string"}],"type":"auth.SentCodeType"},{"id":"629866245","predicate":"keyboardButtonUrl","params":[{"name":"text","type":"string"},{"name":"url","type":"string"}],"type":"KeyboardButton"},{"id":"1748655686","predicate":"keyboardButtonCallback","params":[{"name":"text","type":"string"},{"name":"data","type":"bytes"}],"type":"KeyboardButton"},{"id":"-1318425559","predicate":"keyboardButtonRequestPhone","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"-59151553","predicate":"keyboardButtonRequestGeoLocation","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"90744648","predicate":"keyboardButtonSwitchInline","params":[{"name":"flags","type":"#"},{"name":"same_peer","type":"flags.0?true"},{"name":"text","type":"string"},{"name":"query","type":"string"}],"type":"KeyboardButton"},{"id":"1218642516","predicate":"replyInlineMarkup","params":[{"name":"rows","type":"Vector<KeyboardButtonRow>"}],"type":"ReplyMarkup"},{"id":"-1324486149","predicate":"messages.botCallbackAnswer","params":[{"name":"flags","type":"#"},{"name":"alert","type":"flags.1?true"},{"name":"has_url","type":"flags.3?true"},{"name":"message","type":"flags.0?string"},{"name":"url","type":"flags.2?string"}],"type":"messages.BotCallbackAnswer"},{"id":"-415938591","predicate":"updateBotCallbackQuery","params":[{"name":"flags","type":"#"},{"name":"query_id","type":"long"},{"name":"user_id","type":"int"},{"name":"peer","type":"Peer"},{"name":"msg_id","type":"int"},{"name":"chat_instance","type":"long"},{"name":"data","type":"flags.0?bytes"},{"name":"game_short_name","type":"flags.1?string"}],"type":"Update"},{"id":"649453030","predicate":"messages.messageEditData","params":[{"name":"flags","type":"#"},{"name":"caption","type":"flags.0?true"}],"type":"messages.MessageEditData"},{"id":"-469536605","predicate":"updateEditMessage","params":[{"name":"message","type":"Message"},{"name":"pts","type":"int"},{"name":"pts_count","type":"int"}],"type":"Update"},{"id":"-190472735","predicate":"inputBotInlineMessageMediaGeo","params":[{"name":"flags","type":"#"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"-1431327288","predicate":"inputBotInlineMessageMediaVenue","params":[{"name":"flags","type":"#"},{"name":"geo_point","type":"InputGeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"766443943","predicate":"inputBotInlineMessageMediaContact","params":[{"name":"flags","type":"#"},{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"982505656","predicate":"botInlineMessageMediaGeo","params":[{"name":"flags","type":"#"},{"name":"geo","type":"GeoPoint"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"1130767150","predicate":"botInlineMessageMediaVenue","params":[{"name":"flags","type":"#"},{"name":"geo","type":"GeoPoint"},{"name":"title","type":"string"},{"name":"address","type":"string"},{"name":"provider","type":"string"},{"name":"venue_id","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"904770772","predicate":"botInlineMessageMediaContact","params":[{"name":"flags","type":"#"},{"name":"phone_number","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"BotInlineMessage"},{"id":"-1462213465","predicate":"inputBotInlineResultPhoto","params":[{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"photo","type":"InputPhoto"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"-459324","predicate":"inputBotInlineResultDocument","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"title","type":"flags.1?string"},{"name":"description","type":"flags.2?string"},{"name":"document","type":"InputDocument"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"400266251","predicate":"botInlineMediaResult","params":[{"name":"flags","type":"#"},{"name":"id","type":"string"},{"name":"type","type":"string"},{"name":"photo","type":"flags.0?Photo"},{"name":"document","type":"flags.1?Document"},{"name":"title","type":"flags.2?string"},{"name":"description","type":"flags.3?string"},{"name":"send_message","type":"BotInlineMessage"}],"type":"BotInlineResult"},{"id":"-1995686519","predicate":"inputBotInlineMessageID","params":[{"name":"dc_id","type":"int"},{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputBotInlineMessageID"},{"id":"-103646630","predicate":"updateInlineBotCallbackQuery","params":[{"name":"flags","type":"#"},{"name":"query_id","type":"long"},{"name":"user_id","type":"int"},{"name":"msg_id","type":"InputBotInlineMessageID"},{"name":"chat_instance","type":"long"},{"name":"data","type":"flags.0?bytes"},{"name":"game_short_name","type":"flags.1?string"}],"type":"Update"},{"id":"1008755359","predicate":"inlineBotSwitchPM","params":[{"name":"text","type":"string"},{"name":"start_param","type":"string"}],"type":"InlineBotSwitchPM"},{"id":"863093588","predicate":"messages.peerDialogs","params":[{"name":"dialogs","type":"Vector<Dialog>"},{"name":"messages","type":"Vector<Message>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"},{"name":"state","type":"updates.State"}],"type":"messages.PeerDialogs"},{"id":"-305282981","predicate":"topPeer","params":[{"name":"peer","type":"Peer"},{"name":"rating","type":"double"}],"type":"TopPeer"},{"id":"-1419371685","predicate":"topPeerCategoryBotsPM","params":[],"type":"TopPeerCategory"},{"id":"344356834","predicate":"topPeerCategoryBotsInline","params":[],"type":"TopPeerCategory"},{"id":"104314861","predicate":"topPeerCategoryCorrespondents","params":[],"type":"TopPeerCategory"},{"id":"-1122524854","predicate":"topPeerCategoryGroups","params":[],"type":"TopPeerCategory"},{"id":"371037736","predicate":"topPeerCategoryChannels","params":[],"type":"TopPeerCategory"},{"id":"-75283823","predicate":"topPeerCategoryPeers","params":[{"name":"category","type":"TopPeerCategory"},{"name":"count","type":"int"},{"name":"peers","type":"Vector<TopPeer>"}],"type":"TopPeerCategoryPeers"},{"id":"-567906571","predicate":"contacts.topPeersNotModified","params":[],"type":"contacts.TopPeers"},{"id":"1891070632","predicate":"contacts.topPeers","params":[{"name":"categories","type":"Vector<TopPeerCategoryPeers>"},{"name":"chats","type":"Vector<Chat>"},{"name":"users","type":"Vector<User>"}],"type":"contacts.TopPeers"},{"id":"892193368","predicate":"messageEntityMentionName","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"user_id","type":"int"}],"type":"MessageEntity"},{"id":"546203849","predicate":"inputMessageEntityMentionName","params":[{"name":"offset","type":"int"},{"name":"length","type":"int"},{"name":"user_id","type":"InputUser"}],"type":"MessageEntity"},{"id":"975236280","predicate":"inputMessagesFilterChatPhotos","params":[],"type":"MessagesFilter"},{"id":"634833351","predicate":"updateReadChannelOutbox","params":[{"name":"channel_id","type":"int"},{"name":"max_id","type":"int"}],"type":"Update"},{"id":"-299124375","predicate":"updateDraftMessage","params":[{"name":"peer","type":"Peer"},{"name":"draft","type":"DraftMessage"}],"type":"Update"},{"id":"-1169445179","predicate":"draftMessageEmpty","params":[],"type":"DraftMessage"},{"id":"-40996577","predicate":"draftMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"message","type":"string"},{"name":"entities","type":"flags.3?Vector<MessageEntity>"},{"name":"date","type":"int"}],"type":"DraftMessage"},{"id":"-1615153660","predicate":"messageActionHistoryClear","params":[],"type":"MessageAction"},{"id":"82699215","predicate":"messages.featuredStickersNotModified","params":[],"type":"messages.FeaturedStickers"},{"id":"-123893531","predicate":"messages.featuredStickers","params":[{"name":"hash","type":"int"},{"name":"sets","type":"Vector<StickerSetCovered>"},{"name":"unread","type":"Vector<long>"}],"type":"messages.FeaturedStickers"},{"id":"1461528386","predicate":"updateReadFeaturedStickers","params":[],"type":"Update"},{"id":"186120336","predicate":"messages.recentStickersNotModified","params":[],"type":"messages.RecentStickers"},{"id":"1558317424","predicate":"messages.recentStickers","params":[{"name":"hash","type":"int"},{"name":"stickers","type":"Vector<Document>"}],"type":"messages.RecentStickers"},{"id":"-1706939360","predicate":"updateRecentStickers","params":[],"type":"Update"},{"id":"1338747336","predicate":"messages.archivedStickers","params":[{"name":"count","type":"int"},{"name":"sets","type":"Vector<StickerSetCovered>"}],"type":"messages.ArchivedStickers"},{"id":"946083368","predicate":"messages.stickerSetInstallResultSuccess","params":[],"type":"messages.StickerSetInstallResult"},{"id":"904138920","predicate":"messages.stickerSetInstallResultArchive","params":[{"name":"sets","type":"Vector<StickerSetCovered>"}],"type":"messages.StickerSetInstallResult"},{"id":"1678812626","predicate":"stickerSetCovered","params":[{"name":"set","type":"StickerSet"},{"name":"cover","type":"Document"}],"type":"StickerSetCovered"},{"id":"-1574314746","predicate":"updateConfig","params":[],"type":"Update"},{"id":"861169551","predicate":"updatePtsChanged","params":[],"type":"Update"},{"id":"-1252045032","predicate":"inputMediaPhotoExternal","params":[{"name":"url","type":"string"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"-437690244","predicate":"inputMediaDocumentExternal","params":[{"name":"url","type":"string"},{"name":"caption","type":"string"}],"type":"InputMedia"},{"id":"872932635","predicate":"stickerSetMultiCovered","params":[{"name":"set","type":"StickerSet"},{"name":"covers","type":"Vector<Document>"}],"type":"StickerSetCovered"},{"id":"-1361650766","predicate":"maskCoords","params":[{"name":"n","type":"int"},{"name":"x","type":"double"},{"name":"y","type":"double"},{"name":"zoom","type":"double"}],"type":"MaskCoords"},{"id":"-1744710921","predicate":"documentAttributeHasStickers","params":[],"type":"DocumentAttribute"},{"id":"1251549527","predicate":"inputStickeredMediaPhoto","params":[{"name":"id","type":"InputPhoto"}],"type":"InputStickeredMedia"},{"id":"70813275","predicate":"inputStickeredMediaDocument","params":[{"name":"id","type":"InputDocument"}],"type":"InputStickeredMedia"},{"id":"-1107729093","predicate":"game","params":[{"name":"flags","type":"#"},{"name":"id","type":"long"},{"name":"access_hash","type":"long"},{"name":"short_name","type":"string"},{"name":"title","type":"string"},{"name":"description","type":"string"},{"name":"photo","type":"Photo"},{"name":"document","type":"flags.0?Document"}],"type":"Game"},{"id":"1336154098","predicate":"inputBotInlineResultGame","params":[{"name":"id","type":"string"},{"name":"short_name","type":"string"},{"name":"send_message","type":"InputBotInlineMessage"}],"type":"InputBotInlineResult"},{"id":"1262639204","predicate":"inputBotInlineMessageGame","params":[{"name":"flags","type":"#"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"InputBotInlineMessage"},{"id":"-580219064","predicate":"sendMessageGamePlayAction","params":[],"type":"SendMessageAction"},{"id":"-38694904","predicate":"messageMediaGame","params":[{"name":"game","type":"Game"}],"type":"MessageMedia"},{"id":"-750828557","predicate":"inputMediaGame","params":[{"name":"id","type":"InputGame"}],"type":"InputMedia"},{"id":"53231223","predicate":"inputGameID","params":[{"name":"id","type":"long"},{"name":"access_hash","type":"long"}],"type":"InputGame"},{"id":"-1020139510","predicate":"inputGameShortName","params":[{"name":"bot_id","type":"InputUser"},{"name":"short_name","type":"string"}],"type":"InputGame"},{"id":"1358175439","predicate":"keyboardButtonGame","params":[{"name":"text","type":"string"}],"type":"KeyboardButton"},{"id":"-1834538890","predicate":"messageActionGameScore","params":[{"name":"game_id","type":"long"},{"name":"score","type":"int"}],"type":"MessageAction"},{"id":"1493171408","predicate":"highScore","params":[{"name":"pos","type":"int"},{"name":"user_id","type":"int"},{"name":"score","type":"int"}],"type":"HighScore"},{"id":"-1707344487","predicate":"messages.highScores","params":[{"name":"scores","type":"Vector<HighScore>"},{"name":"users","type":"Vector<User>"}],"type":"messages.HighScores"}],"methods":[{"id":"-878758099","method":"invokeAfterMsg","params":[{"name":"msg_id","type":"long"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1036301552","method":"invokeAfterMsgs","params":[{"name":"msg_ids","type":"Vector<long>"},{"name":"query","type":"!X"}],"type":"X"},{"id":"1877286395","method":"auth.checkPhone","params":[{"name":"phone_number","type":"string"}],"type":"auth.CheckedPhone"},{"id":"-2035355412","method":"auth.sendCode","params":[{"name":"flags","type":"#"},{"name":"allow_flashcall","type":"flags.0?true"},{"name":"phone_number","type":"string"},{"name":"current_number","type":"flags.0?Bool"},{"name":"api_id","type":"int"},{"name":"api_hash","type":"string"}],"type":"auth.SentCode"},{"id":"453408308","method":"auth.signUp","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"},{"name":"first_name","type":"string"},{"name":"last_name","type":"string"}],"type":"auth.Authorization"},{"id":"-1126886015","method":"auth.signIn","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"auth.Authorization"},{"id":"1461180992","method":"auth.logOut","params":[],"type":"Bool"},{"id":"-1616179942","method":"auth.resetAuthorizations","params":[],"type":"Bool"},{"id":"1998331287","method":"auth.sendInvites","params":[{"name":"phone_numbers","type":"Vector<string>"},{"name":"message","type":"string"}],"type":"Bool"},{"id":"-440401971","method":"auth.exportAuthorization","params":[{"name":"dc_id","type":"int"}],"type":"auth.ExportedAuthorization"},{"id":"-470837741","method":"auth.importAuthorization","params":[{"name":"id","type":"int"},{"name":"bytes","type":"bytes"}],"type":"auth.Authorization"},{"id":"-841733627","method":"auth.bindTempAuthKey","params":[{"name":"perm_auth_key_id","type":"long"},{"name":"nonce","type":"long"},{"name":"expires_at","type":"int"},{"name":"encrypted_message","type":"bytes"}],"type":"Bool"},{"id":"1669245048","method":"account.registerDevice","params":[{"name":"token_type","type":"int"},{"name":"token","type":"string"}],"type":"Bool"},{"id":"1707432768","method":"account.unregisterDevice","params":[{"name":"token_type","type":"int"},{"name":"token","type":"string"}],"type":"Bool"},{"id":"-2067899501","method":"account.updateNotifySettings","params":[{"name":"peer","type":"InputNotifyPeer"},{"name":"settings","type":"InputPeerNotifySettings"}],"type":"Bool"},{"id":"313765169","method":"account.getNotifySettings","params":[{"name":"peer","type":"InputNotifyPeer"}],"type":"PeerNotifySettings"},{"id":"-612493497","method":"account.resetNotifySettings","params":[],"type":"Bool"},{"id":"2018596725","method":"account.updateProfile","params":[{"name":"flags","type":"#"},{"name":"first_name","type":"flags.0?string"},{"name":"last_name","type":"flags.1?string"},{"name":"about","type":"flags.2?string"}],"type":"User"},{"id":"1713919532","method":"account.updateStatus","params":[{"name":"offline","type":"Bool"}],"type":"Bool"},{"id":"-1068696894","method":"account.getWallPapers","params":[],"type":"Vector<WallPaper>"},{"id":"-1374118561","method":"account.reportPeer","params":[{"name":"peer","type":"InputPeer"},{"name":"reason","type":"ReportReason"}],"type":"Bool"},{"id":"227648840","method":"users.getUsers","params":[{"name":"id","type":"Vector<InputUser>"}],"type":"Vector<User>"},{"id":"-902781519","method":"users.getFullUser","params":[{"name":"id","type":"InputUser"}],"type":"UserFull"},{"id":"-995929106","method":"contacts.getStatuses","params":[],"type":"Vector<ContactStatus>"},{"id":"583445000","method":"contacts.getContacts","params":[{"name":"hash","type":"string"}],"type":"contacts.Contacts"},{"id":"-634342611","method":"contacts.importContacts","params":[{"name":"contacts","type":"Vector<InputContact>"},{"name":"replace","type":"Bool"}],"type":"contacts.ImportedContacts"},{"id":"-1902823612","method":"contacts.deleteContact","params":[{"name":"id","type":"InputUser"}],"type":"contacts.Link"},{"id":"1504393374","method":"contacts.deleteContacts","params":[{"name":"id","type":"Vector<InputUser>"}],"type":"Bool"},{"id":"858475004","method":"contacts.block","params":[{"name":"id","type":"InputUser"}],"type":"Bool"},{"id":"-448724803","method":"contacts.unblock","params":[{"name":"id","type":"InputUser"}],"type":"Bool"},{"id":"-176409329","method":"contacts.getBlocked","params":[{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"contacts.Blocked"},{"id":"-2065352905","method":"contacts.exportCard","params":[],"type":"Vector<int>"},{"id":"1340184318","method":"contacts.importCard","params":[{"name":"export_card","type":"Vector<int>"}],"type":"User"},{"id":"1109588596","method":"messages.getMessages","params":[{"name":"id","type":"Vector<int>"}],"type":"messages.Messages"},{"id":"1799878989","method":"messages.getDialogs","params":[{"name":"offset_date","type":"int"},{"name":"offset_id","type":"int"},{"name":"offset_peer","type":"InputPeer"},{"name":"limit","type":"int"}],"type":"messages.Dialogs"},{"id":"-1347868602","method":"messages.getHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"offset_id","type":"int"},{"name":"offset_date","type":"int"},{"name":"add_offset","type":"int"},{"name":"limit","type":"int"},{"name":"max_id","type":"int"},{"name":"min_id","type":"int"}],"type":"messages.Messages"},{"id":"-732523960","method":"messages.search","params":[{"name":"flags","type":"#"},{"name":"peer","type":"InputPeer"},{"name":"q","type":"string"},{"name":"filter","type":"MessagesFilter"},{"name":"min_date","type":"int"},{"name":"max_date","type":"int"},{"name":"offset","type":"int"},{"name":"max_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Messages"},{"id":"238054714","method":"messages.readHistory","params":[{"name":"peer","type":"InputPeer"},{"name":"max_id","type":"int"}],"type":"messages.AffectedMessages"},{"id":"469850889","method":"messages.deleteHistory","params":[{"name":"flags","type":"#"},{"name":"just_clear","type":"flags.0?true"},{"name":"peer","type":"InputPeer"},{"name":"max_id","type":"int"}],"type":"messages.AffectedHistory"},{"id":"-1510897371","method":"messages.deleteMessages","params":[{"name":"id","type":"Vector<int>"}],"type":"messages.AffectedMessages"},{"id":"94983360","method":"messages.receivedMessages","params":[{"name":"max_id","type":"int"}],"type":"Vector<ReceivedNotifyMessage>"},{"id":"-1551737264","method":"messages.setTyping","params":[{"name":"peer","type":"InputPeer"},{"name":"action","type":"SendMessageAction"}],"type":"Bool"},{"id":"-91733382","method":"messages.sendMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"clear_draft","type":"flags.7?true"},{"name":"peer","type":"InputPeer"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"message","type":"string"},{"name":"random_id","type":"long"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"},{"name":"entities","type":"flags.3?Vector<MessageEntity>"}],"type":"Updates"},{"id":"-923703407","method":"messages.sendMedia","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"clear_draft","type":"flags.7?true"},{"name":"peer","type":"InputPeer"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"media","type":"InputMedia"},{"name":"random_id","type":"long"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"}],"type":"Updates"},{"id":"1888354709","method":"messages.forwardMessages","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"with_my_score","type":"flags.8?true"},{"name":"from_peer","type":"InputPeer"},{"name":"id","type":"Vector<int>"},{"name":"random_id","type":"Vector<long>"},{"name":"to_peer","type":"InputPeer"}],"type":"Updates"},{"id":"-820669733","method":"messages.reportSpam","params":[{"name":"peer","type":"InputPeer"}],"type":"Bool"},{"id":"-1460572005","method":"messages.hideReportSpam","params":[{"name":"peer","type":"InputPeer"}],"type":"Bool"},{"id":"913498268","method":"messages.getPeerSettings","params":[{"name":"peer","type":"InputPeer"}],"type":"PeerSettings"},{"id":"1013621127","method":"messages.getChats","params":[{"name":"id","type":"Vector<int>"}],"type":"messages.Chats"},{"id":"998448230","method":"messages.getFullChat","params":[{"name":"chat_id","type":"int"}],"type":"messages.ChatFull"},{"id":"-599447467","method":"messages.editChatTitle","params":[{"name":"chat_id","type":"int"},{"name":"title","type":"string"}],"type":"Updates"},{"id":"-900957736","method":"messages.editChatPhoto","params":[{"name":"chat_id","type":"int"},{"name":"photo","type":"InputChatPhoto"}],"type":"Updates"},{"id":"-106911223","method":"messages.addChatUser","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"},{"name":"fwd_limit","type":"int"}],"type":"Updates"},{"id":"-530505962","method":"messages.deleteChatUser","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"}],"type":"Updates"},{"id":"164303470","method":"messages.createChat","params":[{"name":"users","type":"Vector<InputUser>"},{"name":"title","type":"string"}],"type":"Updates"},{"id":"-304838614","method":"updates.getState","params":[],"type":"updates.State"},{"id":"168039573","method":"updates.getDifference","params":[{"name":"pts","type":"int"},{"name":"date","type":"int"},{"name":"qts","type":"int"}],"type":"updates.Difference"},{"id":"-256159406","method":"photos.updateProfilePhoto","params":[{"name":"id","type":"InputPhoto"}],"type":"UserProfilePhoto"},{"id":"1328726168","method":"photos.uploadProfilePhoto","params":[{"name":"file","type":"InputFile"}],"type":"photos.Photo"},{"id":"-2016444625","method":"photos.deletePhotos","params":[{"name":"id","type":"Vector<InputPhoto>"}],"type":"Vector<long>"},{"id":"-1291540959","method":"upload.saveFilePart","params":[{"name":"file_id","type":"long"},{"name":"file_part","type":"int"},{"name":"bytes","type":"bytes"}],"type":"Bool"},{"id":"-475607115","method":"upload.getFile","params":[{"name":"location","type":"InputFileLocation"},{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"upload.File"},{"id":"-990308245","method":"help.getConfig","params":[],"type":"Config"},{"id":"531836966","method":"help.getNearestDc","params":[],"type":"NearestDc"},{"id":"-1372724842","method":"help.getAppUpdate","params":[],"type":"help.AppUpdate"},{"id":"1862465352","method":"help.saveAppLog","params":[{"name":"events","type":"Vector<InputAppEvent>"}],"type":"Bool"},{"id":"1295590211","method":"help.getInviteText","params":[],"type":"help.InviteText"},{"id":"-1848823128","method":"photos.getUserPhotos","params":[{"name":"user_id","type":"InputUser"},{"name":"offset","type":"int"},{"name":"max_id","type":"long"},{"name":"limit","type":"int"}],"type":"photos.Photos"},{"id":"865483769","method":"messages.forwardMessage","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"random_id","type":"long"}],"type":"Updates"},{"id":"651135312","method":"messages.getDhConfig","params":[{"name":"version","type":"int"},{"name":"random_length","type":"int"}],"type":"messages.DhConfig"},{"id":"-162681021","method":"messages.requestEncryption","params":[{"name":"user_id","type":"InputUser"},{"name":"random_id","type":"int"},{"name":"g_a","type":"bytes"}],"type":"EncryptedChat"},{"id":"1035731989","method":"messages.acceptEncryption","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"g_b","type":"bytes"},{"name":"key_fingerprint","type":"long"}],"type":"EncryptedChat"},{"id":"-304536635","method":"messages.discardEncryption","params":[{"name":"chat_id","type":"int"}],"type":"Bool"},{"id":"2031374829","method":"messages.setEncryptedTyping","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"typing","type":"Bool"}],"type":"Bool"},{"id":"2135648522","method":"messages.readEncryptedHistory","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"max_date","type":"int"}],"type":"Bool"},{"id":"-1451792525","method":"messages.sendEncrypted","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"}],"type":"messages.SentEncryptedMessage"},{"id":"-1701831834","method":"messages.sendEncryptedFile","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"},{"name":"file","type":"InputEncryptedFile"}],"type":"messages.SentEncryptedMessage"},{"id":"852769188","method":"messages.sendEncryptedService","params":[{"name":"peer","type":"InputEncryptedChat"},{"name":"random_id","type":"long"},{"name":"data","type":"bytes"}],"type":"messages.SentEncryptedMessage"},{"id":"1436924774","method":"messages.receivedQueue","params":[{"name":"max_qts","type":"int"}],"type":"Vector<long>"},{"id":"-562337987","method":"upload.saveBigFilePart","params":[{"name":"file_id","type":"long"},{"name":"file_part","type":"int"},{"name":"file_total_parts","type":"int"},{"name":"bytes","type":"bytes"}],"type":"Bool"},{"id":"1769565673","method":"initConnection","params":[{"name":"api_id","type":"int"},{"name":"device_model","type":"string"},{"name":"system_version","type":"string"},{"name":"app_version","type":"string"},{"name":"lang_code","type":"string"},{"name":"query","type":"!X"}],"type":"X"},{"id":"-1663104819","method":"help.getSupport","params":[],"type":"help.Support"},{"id":"916930423","method":"messages.readMessageContents","params":[{"name":"id","type":"Vector<int>"}],"type":"messages.AffectedMessages"},{"id":"655677548","method":"account.checkUsername","params":[{"name":"username","type":"string"}],"type":"Bool"},{"id":"1040964988","method":"account.updateUsername","params":[{"name":"username","type":"string"}],"type":"User"},{"id":"301470424","method":"contacts.search","params":[{"name":"q","type":"string"},{"name":"limit","type":"int"}],"type":"contacts.Found"},{"id":"-623130288","method":"account.getPrivacy","params":[{"name":"key","type":"InputPrivacyKey"}],"type":"account.PrivacyRules"},{"id":"-906486552","method":"account.setPrivacy","params":[{"name":"key","type":"InputPrivacyKey"},{"name":"rules","type":"Vector<InputPrivacyRule>"}],"type":"account.PrivacyRules"},{"id":"1099779595","method":"account.deleteAccount","params":[{"name":"reason","type":"string"}],"type":"Bool"},{"id":"150761757","method":"account.getAccountTTL","params":[],"type":"AccountDaysTTL"},{"id":"608323678","method":"account.setAccountTTL","params":[{"name":"ttl","type":"AccountDaysTTL"}],"type":"Bool"},{"id":"-627372787","method":"invokeWithLayer","params":[{"name":"layer","type":"int"},{"name":"query","type":"!X"}],"type":"X"},{"id":"-113456221","method":"contacts.resolveUsername","params":[{"name":"username","type":"string"}],"type":"contacts.ResolvedPeer"},{"id":"149257707","method":"account.sendChangePhoneCode","params":[{"name":"flags","type":"#"},{"name":"allow_flashcall","type":"flags.0?true"},{"name":"phone_number","type":"string"},{"name":"current_number","type":"flags.0?Bool"}],"type":"auth.SentCode"},{"id":"1891839707","method":"account.changePhone","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"User"},{"id":"479598769","method":"messages.getAllStickers","params":[{"name":"hash","type":"int"}],"type":"messages.AllStickers"},{"id":"954152242","method":"account.updateDeviceLocked","params":[{"name":"period","type":"int"}],"type":"Bool"},{"id":"1738800940","method":"auth.importBotAuthorization","params":[{"name":"flags","type":"int"},{"name":"api_id","type":"int"},{"name":"api_hash","type":"string"},{"name":"bot_auth_token","type":"string"}],"type":"auth.Authorization"},{"id":"623001124","method":"messages.getWebPagePreview","params":[{"name":"message","type":"string"}],"type":"MessageMedia"},{"id":"-484392616","method":"account.getAuthorizations","params":[],"type":"account.Authorizations"},{"id":"-545786948","method":"account.resetAuthorization","params":[{"name":"hash","type":"long"}],"type":"Bool"},{"id":"1418342645","method":"account.getPassword","params":[],"type":"account.Password"},{"id":"-1131605573","method":"account.getPasswordSettings","params":[{"name":"current_password_hash","type":"bytes"}],"type":"account.PasswordSettings"},{"id":"-92517498","method":"account.updatePasswordSettings","params":[{"name":"current_password_hash","type":"bytes"},{"name":"new_settings","type":"account.PasswordInputSettings"}],"type":"Bool"},{"id":"174260510","method":"auth.checkPassword","params":[{"name":"password_hash","type":"bytes"}],"type":"auth.Authorization"},{"id":"-661144474","method":"auth.requestPasswordRecovery","params":[],"type":"auth.PasswordRecovery"},{"id":"1319464594","method":"auth.recoverPassword","params":[{"name":"code","type":"string"}],"type":"auth.Authorization"},{"id":"-1080796745","method":"invokeWithoutUpdates","params":[{"name":"query","type":"!X"}],"type":"X"},{"id":"2106086025","method":"messages.exportChatInvite","params":[{"name":"chat_id","type":"int"}],"type":"ExportedChatInvite"},{"id":"1051570619","method":"messages.checkChatInvite","params":[{"name":"hash","type":"string"}],"type":"ChatInvite"},{"id":"1817183516","method":"messages.importChatInvite","params":[{"name":"hash","type":"string"}],"type":"Updates"},{"id":"639215886","method":"messages.getStickerSet","params":[{"name":"stickerset","type":"InputStickerSet"}],"type":"messages.StickerSet"},{"id":"-946871200","method":"messages.installStickerSet","params":[{"name":"stickerset","type":"InputStickerSet"},{"name":"archived","type":"Bool"}],"type":"messages.StickerSetInstallResult"},{"id":"-110209570","method":"messages.uninstallStickerSet","params":[{"name":"stickerset","type":"InputStickerSet"}],"type":"Bool"},{"id":"-421563528","method":"messages.startBot","params":[{"name":"bot","type":"InputUser"},{"name":"peer","type":"InputPeer"},{"name":"random_id","type":"long"},{"name":"start_param","type":"string"}],"type":"Updates"},{"id":"-1189013126","method":"help.getAppChangelog","params":[],"type":"help.AppChangelog"},{"id":"-993483427","method":"messages.getMessagesViews","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"Vector<int>"},{"name":"increment","type":"Bool"}],"type":"Vector<int>"},{"id":"-871347913","method":"channels.readHistory","params":[{"name":"channel","type":"InputChannel"},{"name":"max_id","type":"int"}],"type":"Bool"},{"id":"-2067661490","method":"channels.deleteMessages","params":[{"name":"channel","type":"InputChannel"},{"name":"id","type":"Vector<int>"}],"type":"messages.AffectedMessages"},{"id":"-787622117","method":"channels.deleteUserHistory","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"}],"type":"messages.AffectedHistory"},{"id":"-32999408","method":"channels.reportSpam","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"},{"name":"id","type":"Vector<int>"}],"type":"Bool"},{"id":"-1814580409","method":"channels.getMessages","params":[{"name":"channel","type":"InputChannel"},{"name":"id","type":"Vector<int>"}],"type":"messages.Messages"},{"id":"618237842","method":"channels.getParticipants","params":[{"name":"channel","type":"InputChannel"},{"name":"filter","type":"ChannelParticipantsFilter"},{"name":"offset","type":"int"},{"name":"limit","type":"int"}],"type":"channels.ChannelParticipants"},{"id":"1416484774","method":"channels.getParticipant","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"}],"type":"channels.ChannelParticipant"},{"id":"176122811","method":"channels.getChannels","params":[{"name":"id","type":"Vector<InputChannel>"}],"type":"messages.Chats"},{"id":"141781513","method":"channels.getFullChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"messages.ChatFull"},{"id":"-192332417","method":"channels.createChannel","params":[{"name":"flags","type":"#"},{"name":"broadcast","type":"flags.0?true"},{"name":"megagroup","type":"flags.1?true"},{"name":"title","type":"string"},{"name":"about","type":"string"}],"type":"Updates"},{"id":"333610782","method":"channels.editAbout","params":[{"name":"channel","type":"InputChannel"},{"name":"about","type":"string"}],"type":"Bool"},{"id":"-344583728","method":"channels.editAdmin","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"},{"name":"role","type":"ChannelParticipantRole"}],"type":"Updates"},{"id":"1450044624","method":"channels.editTitle","params":[{"name":"channel","type":"InputChannel"},{"name":"title","type":"string"}],"type":"Updates"},{"id":"-248621111","method":"channels.editPhoto","params":[{"name":"channel","type":"InputChannel"},{"name":"photo","type":"InputChatPhoto"}],"type":"Updates"},{"id":"283557164","method":"channels.checkUsername","params":[{"name":"channel","type":"InputChannel"},{"name":"username","type":"string"}],"type":"Bool"},{"id":"890549214","method":"channels.updateUsername","params":[{"name":"channel","type":"InputChannel"},{"name":"username","type":"string"}],"type":"Bool"},{"id":"615851205","method":"channels.joinChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"Updates"},{"id":"-130635115","method":"channels.leaveChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"Updates"},{"id":"429865580","method":"channels.inviteToChannel","params":[{"name":"channel","type":"InputChannel"},{"name":"users","type":"Vector<InputUser>"}],"type":"Updates"},{"id":"-1502421484","method":"channels.kickFromChannel","params":[{"name":"channel","type":"InputChannel"},{"name":"user_id","type":"InputUser"},{"name":"kicked","type":"Bool"}],"type":"Updates"},{"id":"-950663035","method":"channels.exportInvite","params":[{"name":"channel","type":"InputChannel"}],"type":"ExportedChatInvite"},{"id":"-1072619549","method":"channels.deleteChannel","params":[{"name":"channel","type":"InputChannel"}],"type":"Updates"},{"id":"-1154295872","method":"updates.getChannelDifference","params":[{"name":"channel","type":"InputChannel"},{"name":"filter","type":"ChannelMessagesFilter"},{"name":"pts","type":"int"},{"name":"limit","type":"int"}],"type":"updates.ChannelDifference"},{"id":"-326379039","method":"messages.toggleChatAdmins","params":[{"name":"chat_id","type":"int"},{"name":"enabled","type":"Bool"}],"type":"Updates"},{"id":"-1444503762","method":"messages.editChatAdmin","params":[{"name":"chat_id","type":"int"},{"name":"user_id","type":"InputUser"},{"name":"is_admin","type":"Bool"}],"type":"Bool"},{"id":"363051235","method":"messages.migrateChat","params":[{"name":"chat_id","type":"int"}],"type":"Updates"},{"id":"-1640190800","method":"messages.searchGlobal","params":[{"name":"q","type":"string"},{"name":"offset_date","type":"int"},{"name":"offset_peer","type":"InputPeer"},{"name":"offset_id","type":"int"},{"name":"limit","type":"int"}],"type":"messages.Messages"},{"id":"889286899","method":"help.getTermsOfService","params":[],"type":"help.TermsOfService"},{"id":"2016638777","method":"messages.reorderStickerSets","params":[{"name":"flags","type":"#"},{"name":"masks","type":"flags.0?true"},{"name":"order","type":"Vector<long>"}],"type":"Bool"},{"id":"864953444","method":"messages.getDocumentByHash","params":[{"name":"sha256","type":"bytes"},{"name":"size","type":"int"},{"name":"mime_type","type":"string"}],"type":"Document"},{"id":"-1080395925","method":"messages.searchGifs","params":[{"name":"q","type":"string"},{"name":"offset","type":"int"}],"type":"messages.FoundGifs"},{"id":"-2084618926","method":"messages.getSavedGifs","params":[{"name":"hash","type":"int"}],"type":"messages.SavedGifs"},{"id":"846868683","method":"messages.saveGif","params":[{"name":"id","type":"InputDocument"},{"name":"unsave","type":"Bool"}],"type":"Bool"},{"id":"1364105629","method":"messages.getInlineBotResults","params":[{"name":"flags","type":"#"},{"name":"bot","type":"InputUser"},{"name":"peer","type":"InputPeer"},{"name":"geo_point","type":"flags.0?InputGeoPoint"},{"name":"query","type":"string"},{"name":"offset","type":"string"}],"type":"messages.BotResults"},{"id":"-346119674","method":"messages.setInlineBotResults","params":[{"name":"flags","type":"#"},{"name":"gallery","type":"flags.0?true"},{"name":"private","type":"flags.1?true"},{"name":"query_id","type":"long"},{"name":"results","type":"Vector<InputBotInlineResult>"},{"name":"cache_time","type":"int"},{"name":"next_offset","type":"flags.2?string"},{"name":"switch_pm","type":"flags.3?InlineBotSwitchPM"}],"type":"Bool"},{"id":"-1318189314","method":"messages.sendInlineBotResult","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.5?true"},{"name":"background","type":"flags.6?true"},{"name":"clear_draft","type":"flags.7?true"},{"name":"peer","type":"InputPeer"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"random_id","type":"long"},{"name":"query_id","type":"long"},{"name":"id","type":"string"}],"type":"Updates"},{"id":"1231065863","method":"channels.toggleInvites","params":[{"name":"channel","type":"InputChannel"},{"name":"enabled","type":"Bool"}],"type":"Updates"},{"id":"-934882771","method":"channels.exportMessageLink","params":[{"name":"channel","type":"InputChannel"},{"name":"id","type":"int"}],"type":"ExportedMessageLink"},{"id":"527021574","method":"channels.toggleSignatures","params":[{"name":"channel","type":"InputChannel"},{"name":"enabled","type":"Bool"}],"type":"Updates"},{"id":"-1490162350","method":"channels.updatePinnedMessage","params":[{"name":"flags","type":"#"},{"name":"silent","type":"flags.0?true"},{"name":"channel","type":"InputChannel"},{"name":"id","type":"int"}],"type":"Updates"},{"id":"1056025023","method":"auth.resendCode","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"}],"type":"auth.SentCode"},{"id":"520357240","method":"auth.cancelCode","params":[{"name":"phone_number","type":"string"},{"name":"phone_code_hash","type":"string"}],"type":"Bool"},{"id":"-39416522","method":"messages.getMessageEditData","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"}],"type":"messages.MessageEditData"},{"id":"-829299510","method":"messages.editMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"message","type":"flags.11?string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"},{"name":"entities","type":"flags.3?Vector<MessageEntity>"}],"type":"Updates"},{"id":"319564933","method":"messages.editInlineBotMessage","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"id","type":"InputBotInlineMessageID"},{"name":"message","type":"flags.11?string"},{"name":"reply_markup","type":"flags.2?ReplyMarkup"},{"name":"entities","type":"flags.3?Vector<MessageEntity>"}],"type":"Bool"},{"id":"-2130010132","method":"messages.getBotCallbackAnswer","params":[{"name":"flags","type":"#"},{"name":"game","type":"flags.1?true"},{"name":"peer","type":"InputPeer"},{"name":"msg_id","type":"int"},{"name":"data","type":"flags.0?bytes"}],"type":"messages.BotCallbackAnswer"},{"id":"-920136629","method":"messages.setBotCallbackAnswer","params":[{"name":"flags","type":"#"},{"name":"alert","type":"flags.1?true"},{"name":"query_id","type":"long"},{"name":"message","type":"flags.0?string"},{"name":"url","type":"flags.2?string"}],"type":"Bool"},{"id":"-728224331","method":"contacts.getTopPeers","params":[{"name":"flags","type":"#"},{"name":"correspondents","type":"flags.0?true"},{"name":"bots_pm","type":"flags.1?true"},{"name":"bots_inline","type":"flags.2?true"},{"name":"groups","type":"flags.10?true"},{"name":"channels","type":"flags.15?true"},{"name":"offset","type":"int"},{"name":"limit","type":"int"},{"name":"hash","type":"int"}],"type":"contacts.TopPeers"},{"id":"451113900","method":"contacts.resetTopPeerRating","params":[{"name":"category","type":"TopPeerCategory"},{"name":"peer","type":"InputPeer"}],"type":"Bool"},{"id":"764901049","method":"messages.getPeerDialogs","params":[{"name":"peers","type":"Vector<InputPeer>"}],"type":"messages.PeerDialogs"},{"id":"-1137057461","method":"messages.saveDraft","params":[{"name":"flags","type":"#"},{"name":"no_webpage","type":"flags.1?true"},{"name":"reply_to_msg_id","type":"flags.0?int"},{"name":"peer","type":"InputPeer"},{"name":"message","type":"string"},{"name":"entities","type":"flags.3?Vector<MessageEntity>"}],"type":"Bool"},{"id":"1782549861","method":"messages.getAllDrafts","params":[],"type":"Updates"},{"id":"766298703","method":"messages.getFeaturedStickers","params":[{"name":"hash","type":"int"}],"type":"messages.FeaturedStickers"},{"id":"1527873830","method":"messages.readFeaturedStickers","params":[{"name":"id","type":"Vector<long>"}],"type":"Bool"},{"id":"1587647177","method":"messages.getRecentStickers","params":[{"name":"flags","type":"#"},{"name":"attached","type":"flags.0?true"},{"name":"hash","type":"int"}],"type":"messages.RecentStickers"},{"id":"958863608","method":"messages.saveRecentSticker","params":[{"name":"flags","type":"#"},{"name":"attached","type":"flags.0?true"},{"name":"id","type":"InputDocument"},{"name":"unsave","type":"Bool"}],"type":"Bool"},{"id":"-1986437075","method":"messages.clearRecentStickers","params":[{"name":"flags","type":"#"},{"name":"attached","type":"flags.0?true"}],"type":"Bool"},{"id":"1475442322","method":"messages.getArchivedStickers","params":[{"name":"flags","type":"#"},{"name":"masks","type":"flags.0?true"},{"name":"offset_id","type":"long"},{"name":"limit","type":"int"}],"type":"messages.ArchivedStickers"},{"id":"353818557","method":"account.sendConfirmPhoneCode","params":[{"name":"flags","type":"#"},{"name":"allow_flashcall","type":"flags.0?true"},{"name":"hash","type":"string"},{"name":"current_number","type":"flags.0?Bool"}],"type":"auth.SentCode"},{"id":"1596029123","method":"account.confirmPhone","params":[{"name":"phone_code_hash","type":"string"},{"name":"phone_code","type":"string"}],"type":"Bool"},{"id":"-1920105769","method":"channels.getAdminedPublicChannels","params":[],"type":"messages.Chats"},{"id":"1706608543","method":"messages.getMaskStickers","params":[{"name":"hash","type":"int"}],"type":"messages.AllStickers"},{"id":"-866424884","method":"messages.getAttachedStickers","params":[{"name":"media","type":"InputStickeredMedia"}],"type":"Vector<StickerSetCovered>"},{"id":"-1907842680","method":"auth.dropTempAuthKeys","params":[{"name":"except_auth_keys","type":"Vector<long>"}],"type":"Bool"},{"id":"-1896289088","method":"messages.setGameScore","params":[{"name":"flags","type":"#"},{"name":"edit_message","type":"flags.0?true"},{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"user_id","type":"InputUser"},{"name":"score","type":"int"}],"type":"Updates"},{"id":"363700068","method":"messages.setInlineGameScore","params":[{"name":"flags","type":"#"},{"name":"edit_message","type":"flags.0?true"},{"name":"id","type":"InputBotInlineMessageID"},{"name":"user_id","type":"InputUser"},{"name":"score","type":"int"}],"type":"Bool"},{"id":"-400399203","method":"messages.getGameHighScores","params":[{"name":"peer","type":"InputPeer"},{"name":"id","type":"int"},{"name":"user_id","type":"InputUser"}],"type":"messages.HighScores"},{"id":"258170395","method":"messages.getInlineGameHighScores","params":[{"name":"id","type":"InputBotInlineMessageID"},{"name":"user_id","type":"InputUser"}],"type":"messages.HighScores"}]}<?php /** * Lang module * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Lang { public static $lang = array ( 'it' => array ( 'phpseclib_fork' => 'Per favore installa questo fork di phpseclib: https://github.com/danog/phpseclib', 'inst_dc' => 'Istanziamento dei DataCenter...', 'load_rsa' => 'Caricamento delle chiavi RSA...', 'TL_translation' => 'Translazione degli schemi TL...', 'dh_prime_check_0' => 'Esecuzione dei check dh_prime (0/3)...', 'nearest_dc' => 'Siamo in %s, il DC più vicino è %d.', 'serialization_ofd' => 'La serializzazione non è aggiornata, reistanziamento dell\'oggetto in corso!', 'getupdates_deserialization' => 'Ottenimento aggiornamenti dopo deserializzazione...', 'shutdown_reader_pool' => 'Chiusura pool di lettura, %d thread rimasti', 'threading_on' => 'IL THREADING È ABILITATO', 'socket_reader' => 'Lettore socket su DC %s: ', 'socket_status_1' => 'CREAZIONE', 'socket_status_2' => 'INVIO', 'socket_status_3' => 'ATTESA', 'socket_status_4' => 'PRONTO', 'socket_status_5' => 'AVVIATO', 'api_not_set' => 'Devi specificare una chiave ed un ID API, ottienili su https://my.telegram.org', 'session_corrupted' => 'La sessione si è corrotta!', 'reset_session_seqno' => 'Resettando ID sessione e numero di sequenza sul DC %s...', 'gen_perm_auth_key' => 'Generando chiave di autorizzazione permanente per il DC %s...', 'gen_temp_auth_key' => 'Generando chiave di autorizzazione temporanea per il DC %s...', 'copy_auth_dcs' => 'Copiando autorizzazione dal DC %s al DC %s...', 'write_client_info' => 'Scrittura info sul client (eseguendo nel contempo il metodo %s)...', 'config_updated' => 'La configurazione è stata aggiornata!', 'length_not_4' => 'La lunghezza non è uguale a 4', 'length_not_8' => 'La lunghezza non è uguale a 8', 'value_bigger_than_2147483647' => 'Il valore fornito (%s) è maggiore di 2147483647', 'value_smaller_than_2147483648' => 'Il valore fornito (%s) è minore di -2147483648', 'value_bigger_than_9223372036854775807' => 'Il valore fornito (%s) è maggiore di 9223372036854775807', 'value_smaller_than_9223372036854775808' => 'Il valore fornito (%s) è minore di -9223372036854775808', 'value_bigger_than_4294967296' => 'Il valore fornito (%s) è maggiore di 4294967296', 'value_smaller_than_0' => 'Il valore fornito (%s) è minore di 0', 'encode_double_error' => 'Non sono riuscito a codificare il numero a virgola mobile fornito', 'file_not_exist' => 'Il file specificato non esiste', 'deserialization_error' => 'C\'è stato un errore durante la deserializzazione', 'rsa_init' => 'Istanziamento di \\phpseclib\\Crypt\\RSA in corso...', 'loading_key' => 'Caricamento della chiave in corso...', 'computing_fingerprint' => 'Calcolo del fingerprint in corso...', 'rsa_encrypting' => 'Criptando con chiave RSA...', 'rpc_tg_error' => 'Telegram ha ritornato un errore RPC: %s (%s), causato da %s:%s%sTL trace:', 'v_error' => '506572206661766f726520616767696f726e612071756573746120696e7374616c6c617a696f6e65206469204d6164656c696e6550726f746f20636f6e206769742070756c6c206520636f6d706f73657220757064617465', 'v_tgerror' => '506572206661766f726520616767696f726e61207068702d6c69627467766f6970', 'no_mode_specified' => 'Nessuna modalità di logging è stata specificata!', 'constructor_function_uncalled' => 'Il metodo costruttore non è stato ancora chiamato! Per favore chiama il metodo costruttore prima di usare questo metodo.', 'proxy_class_invalid' => 'È stata specificata una classe proxy errata!', 'socket_con_error' => 'Connessione fallita.', 'protocol_not_implemented' => 'Questo protocollo non è stato ancora implementato.', 'protocol_invalid' => 'È stato fornito un protocollo non valido', 'nothing_in_socket' => 'Non c\'è niente nel socket!', 'wrong_length_read' => 'ATTENZIONE: Non sono stati letti abbastanza byte (dovevo leggere %s, ho letto %s)!', 'no_data_in_socket' => 'Non ci sono dati nel socket!', 'dc_con_start' => 'Connessione al DC %s in corso...', 'dc_con_stop' => 'Disconnessione dal DC %s in corso...', 'dc_con_test_start' => 'Connessione al DC %s (server %s, %s, %s)...', 'script_not_exist' => 'Lo script fornito non esiste', 'apifactory_start' => 'Sto avviando la fabbrica di API...', 'madelineproto_ready' => 'MadelineProto è pronto!', 'logout_error' => 'C\'è stato un errore durante il logout!', 'logout_ok' => 'Il logout è stato eseguito correttamente!', 'already_logged_in' => 'Questa istanza di MadelineProto è già loggata, prima faccio il logout...', 'login_ok' => 'Il login è stato eseguito correttamente!', 'login_user' => 'Sto eseguendo il login come utente normale...', 'login_bot' => 'Sto eseguendo il login come bot...', 'login_code_sending' => 'Sto inviando il codice...', 'login_code_sent' => 'Il codice è stato inviato correttamente! Una volta ricevuto il codice dovrai usare la funzione complete_phone_login.', 'login_code_uncalled' => 'Non sto aspettando il codice! Usa la funzione phone_login.', 'login_2fa_enabled' => 'L\'autenticazione a due fattori è abilitata, dovrai chiamare il metodo complete_2fa_login...', 'login_need_signup' => 'Questo numero non è registrato su telegram, dovrai chiamare la funzione complete_signup...', 'login_auth_key' => 'Sto facendo il login con la chiave di autorizzazione...', 'not_logged_in' => 'Non ho ancora fatto il login!', 'signup_uncalled' => 'Chiama prima le funzioni phone_login e complete_phone_login.', 'signing_up' => 'Mi sto registrando su telegram come utente normale...', 'signup_ok' => 'Mi sono registrato su Telegram!', '2fa_uncalled' => 'Non sto aspettando la password, chiama prima le funzioni phone_login e complete_phone_login!', 'getting_dialogs' => 'Sto ottenendo la lista delle chat...', 'libtgvoip_required' => 'È necessario installare l\'estensione php-libtgvoip per accettare e gestire chiamate vocali, vistate https://docs.madelineproto.xyz per più info.', 'peer_not_in_db' => 'Questo utente/gruppo/canale non è presente nel database interno MadelineProto', 'calling_user' => 'Sto chiamando %s...', 'generating_a' => 'Sto generando a...', 'generating_g_a' => 'Sto generando g_a...', 'call_error_1' => 'Impossibile trovare ed accettare la chiamata %s', 'accepting_call' => 'Sto accettando una chiamata da %s...', 'generating_b' => 'Sto generando b...', 'call_already_accepted' => 'La chiamata %s è già stata accettata.', 'call_already_declined' => 'La chiamata %s è già stata annullata.', 'call_error_2' => 'Impossibile trovare e confermare la chiamata %s', 'call_confirming' => 'Sto confermando una chiamata da %s', 'call_error_3' => 'Impossibile trovare e completare la chiamata %s', 'call_completing' => 'Sto completando una chiamata da %s...', 'invalid_g_a' => 'g_a non valido!', 'fingerprint_invalid' => 'fingerprint della chiave non valido!', 'call_discarding' => 'Sto rifiutando la chiamata %s...', 'call_set_rating' => 'Sto inviando la recensione della chiamata %s...', 'call_debug_saving' => 'Sto inviando i dati di debug della chiamata %s...', 'TL_loading' => 'Sto caricando gli schemi TL...', 'file_parsing' => 'Leggendo %s...', 'crc32_mismatch' => 'CRC32 non valido (%s diverso da %s) per %s', 'src_file_invalid' => 'È stato fornito un file sorgente non valido: ', 'translating_obj' => 'Traducendo gli oggetti...', 'translating_methods' => 'Traducendo i metodi...', 'bool_error' => 'Non sono riuscito ad estrarre un booleano', 'not_numeric' => 'Il valore fornito non è numerico', 'long_not_16' => 'Il valore fornito non è lungo 16 byte', 'long_not_32' => 'Il valore fornito non è lungo 32 byte', 'long_not_64' => 'Il valore fornito non è lungo 64 byte', 'array_invalid' => 'Il valore fornito non è un array', 'predicate_not_set' => 'Il predicato (valore sotto chiave _, esempio [\'_\' => \'inputPeer\']) non è impostato!', 'type_extract_error' => 'Impossibile estrarre il tipo "%s"', 'method_not_found' => 'Impossibile trovare il seguente metodo: ', 'params_missing' => 'Non hai fornito un parametro obbligatorio, rileggi la documentazione API', 'sec_peer_not_in_db' => 'La chat segreta non è presente nel database interno MadelineProto', 'stream_handle_invalid' => 'Il valore fornito non è uno stream', 'length_too_big' => 'Il valore fornito è troppo lungo', 'deserialize_not_str' => 'Il valore generato non è una stringa', 'type_extract_error_id' => 'Non sono riuscito ad estrarre il tipo %s con ID %s', 'vector_invalid' => 'ID vettore non valido: ', 'constructor_not_found' => 'Costruttore non trovato per tipo: ', 'rand_bytes_too_small' => 'random_bytes è troppo corto!', 'botapi_conversion_error' => 'NOn sono risucito a convertire %s in un oggetto bot API', 'non_text_conversion' => 'Non posso ancora convertire messaggi media', 'last_byte_invalid' => 'L\'ultimo byte non è valido', 'file_type_invalid' => 'È stato fornito un tipo file errato', 'recreate_temp_auth_key' => 'Sono stato costretto a rigenerare la chiave di autorizzazione temporanea', 'resetting_auth_key' => 'ATTENZIONE: Sto resettando la chiave temporanea...', 'shutting_down_reader_pool' => 'Chisura pool di lettura', 'shutting_down_handler_pool' => 'Chiusura pool di gestione per DC %s, %d thread rimasti', 'secret_chat_skipping' => 'Non ho la chat segreta %s nel database, ignorando messaggio', 'fingerprint_mismatch' => 'Fingerprint della chiave non valido', 'msg_data_length_too_big' => 'message_data_length è troppo grande', 'length_not_divisible_16' => 'La lunghezza dei dati decifrati non è divisibile per 16', 'msg_key_mismatch' => 'msg_key non valido', 'rand_bytes_too_short' => 'random_bytes è troppo corto!', 'resending_unsupported' => 'IL riinvio di messaggi non è ancora supportato', 'unrecognized_dec_msg' => 'È stato ricevuto un messaggio decifrato sconosciuto: ', 'serializing_madelineproto' => 'Sto serializzando MadelineProto...', 'req_pq' => 'Sto richiedendo pq...', 'done' => 'Fatto!', 'cdn_reupload' => 'Il file non è disponibile sul nostro CDN, richiedo la copia!', 'stored_on_cdn' => 'Il file è scaricabile tramite CDN!', ), 'en' => array ( 'req_pq' => 'Requesting pq...', 'done' => 'Done!', 'cdn_reupload' => 'File is not stored on CDN, requesting reupload!', 'stored_on_cdn' => 'File is stored on CDN!', 'serializing_madelineproto' => 'Serializing MadelineProto...', 'phpseclib_fork' => 'Please install this fork of phpseclib: https://github.com/danog/phpseclib', 'inst_dc' => 'Istantiating DataCenter...', 'load_rsa' => 'Loading RSA keys...', 'TL_translation' => 'Translating TL schemas...', 'dh_prime_check_0' => 'Executing dh_prime checks (0/3)...', 'nearest_dc' => 'We\'re in %s, nearest DC is %d.', 'serialization_ofd' => 'Serialization is out of date, reconstructing object!', 'getupdates_deserialization' => 'Getting updates after deserialization...', 'shutdown_reader_pool' => 'Shutting down reader pool, %d jobs left', 'threading_on' => 'THREADING IS ENABLED', 'socket_reader' => 'Socket reader on DC %s: ', 'socket_status_1' => 'CREATING', 'socket_status_2' => 'SUBMITTING', 'socket_status_3' => 'WAITING', 'socket_status_4' => 'READY', 'socket_status_5' => 'WORKING', 'api_not_set' => 'You must provide an api key and an api id, get your own @ my.telegram.org', 'session_corrupted' => 'The session is corrupted!', 'reset_session_seqno' => 'Resetting session id and seq_no in DC %s...', 'gen_perm_auth_key' => 'Generating permanent authorization key for DC %s...', 'gen_temp_auth_key' => 'Generating temporary authorization key for DC %s...', 'copy_auth_dcs' => 'Copying authorization from DC %s to DC %s...', 'write_client_info' => 'Writing client info (also executing %s)...', 'config_updated' => 'Updated config!', 'length_not_4' => 'Length is not equal to 4', 'length_not_8' => 'Length is not equal to 8', 'value_bigger_than_2147483647' => 'Provided value %s is bigger than 2147483647', 'value_smaller_than_2147483648' => 'Provided value %s is smaller than -2147483648', 'value_bigger_than_9223372036854775807' => 'Provided value %s is bigger than 9223372036854775807', 'value_smaller_than_9223372036854775808' => 'Provided value %s is smaller than -9223372036854775808', 'value_bigger_than_4294967296' => 'Provided value %s is bigger than 4294967296', 'value_smaller_than_0' => 'Provided value %s is smaller than 0', 'encode_double_error' => 'Could not properly encode double', 'file_not_exist' => 'File does not exist', 'deserialization_error' => 'An error occurred on deserialization', 'rsa_init' => 'Istantiating \\phpseclib\\Crypt\\RSA...', 'loading_key' => 'Loading key...', 'computing_fingerprint' => 'Computing fingerprint...', 'rsa_encrypting' => 'Encrypting with rsa key...', 'rpc_tg_error' => 'Telegram ha ritornato un errore RPC: %s (%s), causato da %s:%s%sTL trace:', 'v_error' => '506c656173652075706461746520746f20746865206c61746573742076657273696f6e206f66204d6164656c696e6550726f746f2e', 'v_tgerror' => '506c6561736520757064617465207068702d6c69627467766f6970', 'no_mode_specified' => 'No mode was specified!', 'constructor_function_uncalled' => 'The constructor function wasn\'t called! Please call the constructor function before using this method.', 'proxy_class_invalid' => 'Invalid proxy class provided!', 'socket_con_error' => 'Connection: couldn\'t connect to socket.', 'protocol_not_implemented' => 'Connection: This protocol isn\'t implemented yet.', 'protocol_invalid' => 'Connection: invalid protocol specified.', 'nothing_in_socket' => 'Nothing in the socket!', 'wrong_length_read' => 'WARNING: Wrong length was read (should\'ve read %s, read %s)!', 'no_data_in_socket' => 'No data in the socket!', 'dc_con_start' => 'Connecting to DC %s...', 'dc_con_stop' => 'Disconnecting from DC %s...', 'dc_con_test_start' => 'Connecting to DC %s (%s server, %s, %s)...', 'script_not_exist' => 'Provided script does not exist', 'apifactory_start' => 'Running APIFactory...', 'madelineproto_ready' => 'MadelineProto is ready!', 'logout_error' => 'An error occurred while logging out!', 'logout_ok' => 'Logged out successfully!', 'already_logged_in' => 'This instance of MadelineProto is already logged in. Logging out first...', 'login_ok' => 'Logged in successfully!', 'login_user' => 'Logging in as a normal user...', 'login_bot' => 'Logging in as a bot...', 'login_code_sending' => 'Sending code...', 'login_code_sent' => 'Code sent successfully! Once you receive the code you should use the complete_phone_login function.', 'login_code_uncalled' => 'I\'m not waiting for the code! Please call the phone_login method first', 'login_2fa_enabled' => '2FA enabled, you will have to call the complete_2fa_login function...', 'login_need_signup' => 'An account has not been created for this number, you will have to call the complete_signup function...', 'login_auth_key' => 'Logging in using auth key...', 'not_logged_in' => 'I\'m not logged in!', 'signup_uncalled' => 'I\'m not waiting to signup! Please call the phone_login and the complete_phone_login methods first!', 'signing_up' => 'Signing up as a normal user...', 'signup_ok' => 'Signed up in successfully!', '2fa_uncalled' => 'I\'m not waiting for the password! Please call the phone_login and the complete_phone_login methods first!', 'getting_dialogs' => 'Getting dialogs...', 'libtgvoip_required' => 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'peer_not_in_db' => 'This peer is not present in the internal peer database', 'calling_user' => 'Calling %s...', 'generating_a' => 'Generating a...', 'generating_g_a' => 'Generating g_a...', 'call_error_1' => 'Could not find and accept call %s', 'accepting_call' => 'Accepting call from %s...', 'generating_b' => 'Generating b...', 'call_already_accepted' => 'Call %s already accepted', 'call_already_declined' => 'Call %s already declined', 'call_error_2' => 'Could not find and confirm call %s', 'call_confirming' => 'Confirming call from %s...', 'call_error_3' => 'Could not find and complete call %s', 'call_completing' => 'Completing call from %s...', 'invalid_g_a' => 'Invalid g_a!', 'fingerprint_invalid' => 'Invalid key fingerprint!', 'call_discarding' => 'Discarding call %s...', 'call_set_rating' => 'Setting rating for call %s...', 'call_debug_saving' => 'Saving debug data for call %s...', 'TL_loading' => 'Loading TL schemes...', 'file_parsing' => 'Parsing %s...', 'crc32_mismatch' => 'CRC32 mismatch (%s, %s) for %s', 'src_file_invalid' => 'Invalid source file was provided: ', 'translating_obj' => 'Translating objects...', 'translating_methods' => 'Translating methods...', 'bool_error' => 'Could not extract boolean', 'not_numeric' => 'Given value isn\'t numeric', 'long_not_16' => 'Given value is not 16 bytes long', 'long_not_32' => 'Given value is not 32 bytes long', 'long_not_64' => 'Given value is not 64 bytes long', 'array_invalid' => 'You didn\'t provide a valid array', 'predicate_not_set' => 'Predicate (value under _) was not set!', 'type_extract_error' => 'Could not extract type "%s"', 'method_not_found' => 'Could not find method: ', 'params_missing' => 'Missing required parameter', 'sec_peer_not_in_db' => 'This secret peer is not present in the internal peer database', 'stream_handle_invalid' => 'An invalid stream handle was provided.', 'length_too_big' => 'Length is too big', 'deserialize_not_str' => 'Deserialize: Generated value isn\'t a string', 'type_extract_error_id' => 'Could not extract type: %s with id %s', 'vector_invalid' => 'Invalid vector constructor: ', 'constructor_not_found' => 'Constructor not found for type: ', 'rand_bytes_too_small' => 'Random_bytes is too small!', 'botapi_conversion_error' => 'Can\'t convert %s to a bot API object', 'non_text_conversion' => 'Can\'t convert non text messages yet!', 'last_byte_invalid' => 'Invalid last byte', 'file_type_invalid' => 'Invalid file type detected (%s)', 'recreate_temp_auth_key' => 'I had to recreate the temporary authorization key', 'resetting_auth_key' => 'WARNING: Resetting auth key...', 'shutting_down_reader_pool' => 'Shutting down reader pool ', 'shutting_down_handler_pool' => 'Shutting down handler pool for dc %s, %d jobs left', 'secret_chat_skipping' => 'I do not have the secret chat %s in the database, skipping message...', 'fingerprint_mismatch' => 'Key fingerprint mismatch', 'msg_data_length_too_big' => 'Message_data_length is too big', 'length_not_divisible_16' => 'Length of decrypted data is not divisible by 16', 'msg_key_mismatch' => 'Msg_key mismatch', 'rand_bytes_too_short' => 'Random_bytes is too short!', 'resending_unsupported' => 'Resending of messages is not yet supported', 'unrecognized_dec_msg' => 'Unrecognized decrypted message received: ', 'method_req_pq' => 'Requests PQ for factorization', 'method_req_pq_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_req_pq_multi' => 'Requests PQ for factorization (new version)', 'method_req_pq_multi_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_req_DH_params' => 'Requests Diffie-hellman parameters for key exchange', 'method_req_DH_params_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_req_DH_params_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'method_req_DH_params_param_p_type_bytes' => 'Factorized p from pq', 'method_req_DH_params_param_q_type_bytes' => 'Factorized q from pq', 'method_req_DH_params_param_public_key_fingerprint_type_long' => 'Server RSA fingerprint', 'method_req_DH_params_param_encrypted_data_type_bytes' => 'Encrypted key exchange message', 'method_set_client_DH_params' => 'Sets client diffie-hellman parameters', 'method_set_client_DH_params_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_set_client_DH_params_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'method_set_client_DH_params_param_encrypted_data_type_bytes' => 'Encrypted key exchange message', 'method_rpc_drop_answer' => 'Do not send answer to provided request', 'method_rpc_drop_answer_param_req_msg_id_type_long' => 'The message ID of the request', 'method_get_future_salts' => 'Get future salts', 'method_get_future_salts_param_num_type_int' => 'How many salts should be fetched', 'method_ping' => 'Pings the server', 'method_ping_param_ping_id_type_long' => 'Ping ID', 'method_ping_delay_disconnect' => 'Pings the server and causes disconection if the same method is not called within ping_disconnect_delay', 'method_ping_delay_disconnect_param_ping_id_type_long' => 'Ping ID', 'method_ping_delay_disconnect_param_disconnect_delay_type_int' => 'Disconection delay', 'method_destroy_session' => 'Destroy the current MTProto session', 'method_destroy_session_param_session_id_type_long' => 'The session to destroy', 'method_http_wait' => 'Makes the server send messages waiting in the buffer', 'method_http_wait_param_max_delay_type_int' => 'Denotes the maximum number of milliseconds that has elapsed between the first message for this session and the transmission of an HTTP response', 'method_http_wait_param_wait_after_type_int' => 'After the receipt of the latest message for a particular session, the server waits another wait_after milliseconds in case there are more messages. If there are no additional messages, the result is transmitted (a container with all the messages).', 'method_http_wait_param_max_wait_type_int' => 'If more messages appear, the wait_after timer is reset.', 'method_invokeAfterMsg' => 'Invokes a query after successfull completion of one of the previous queries.', 'method_invokeAfterMsg_param_msg_id_type_long' => 'Message identifier on which a current query depends', 'method_invokeAfterMsg_param_query_type_!X' => 'The query itself', 'method_invokeAfterMsgs' => 'Result type returned by a current query.', 'method_invokeAfterMsgs_param_msg_ids_type_Vector t' => 'List of messages on which a current query depends', 'method_invokeAfterMsgs_param_query_type_!X' => 'The query itself', 'method_initConnection' => 'Initializes connection and save information on the user\'s device and application.', 'method_initConnection_param_api_id_type_int' => 'Application identifier', 'method_initConnection_param_device_model_type_string' => 'Device model', 'method_initConnection_param_system_version_type_string' => 'System version', 'method_initConnection_param_app_version_type_string' => 'App version', 'method_initConnection_param_system_lang_code_type_string' => 'Language code', 'method_initConnection_param_lang_pack_type_string' => 'Language pack to use', 'method_initConnection_param_lang_code_type_string' => 'Language code to set', 'method_initConnection_param_query_type_!X' => 'Nested query', 'method_invokeWithLayer' => 'Invoke this method with layer X', 'method_invokeWithLayer_param_layer_type_int' => 'The layer version', 'method_invokeWithLayer_param_query_type_!X' => 'The query', 'method_invokeWithoutUpdates' => 'Invoke with method without returning updates in the socket', 'method_invokeWithoutUpdates_param_query_type_!X' => 'The query', 'method_auth.checkPhone' => 'Check if this phone number is registered on telegram', 'method_auth.checkPhone_param_phone_number_type_string' => 'The phone number to check', 'method_auth.sendCode' => 'Use phone_login instead', 'method_auth.sendCode_param_allow_flashcall_type_true' => 'Use phone_login instead', 'method_auth.sendCode_param_phone_number_type_string' => 'Use phone_login instead', 'method_auth.sendCode_param_current_number_type_Bool' => 'Use phone_login instead', 'method_auth.sendCode_param_api_id_type_int' => 'Use phone_login instead', 'method_auth.sendCode_param_api_hash_type_string' => 'Use phone_login instead', 'method_auth.signUp' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_phone_number_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_phone_code_hash_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_phone_code_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_first_name_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_last_name_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn_param_phone_number_type_string' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn_param_phone_code_hash_type_string' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn_param_phone_code_type_string' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.logOut' => 'You cannot use this method directly, use the logout method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.resetAuthorizations' => 'Delete all logged-in sessions.', 'method_auth.sendInvites' => 'Invite friends to telegram!', 'method_auth.sendInvites_param_phone_numbers_type_Vector t' => 'Phone numbers to invite', 'method_auth.sendInvites_param_message_type_string' => 'The message to send', 'method_auth.exportAuthorization' => 'You cannot use this method directly, use $MadelineProto->export_authorization() instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.exportAuthorization_param_dc_id_type_int' => 'You cannot use this method directly, use $MadelineProto->export_authorization() instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.importAuthorization' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.importAuthorization_param_id_type_int' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.importAuthorization_param_bytes_type_bytes' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.bindTempAuthKey' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_perm_auth_key_id_type_long' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_nonce_type_long' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_expires_at_type_int' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_encrypted_message_type_bytes' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.importBotAuthorization' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_api_id_type_int' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_api_hash_type_string' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_bot_auth_token_type_string' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.checkPassword' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.checkPassword_param_password_hash_type_bytes' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.requestPasswordRecovery' => 'Send an email to recover the 2FA password', 'method_auth.recoverPassword' => 'Use the code that was emailed to you after running $MadelineProto->auth->requestPasswordRecovery to login to your account', 'method_auth.recoverPassword_param_code_type_string' => 'The code that was emailed to you', 'method_auth.resendCode' => 'Resend the SMS verification code', 'method_auth.resendCode_param_phone_number_type_string' => 'The phone number', 'method_auth.resendCode_param_phone_code_hash_type_string' => 'The phone code hash', 'method_auth.cancelCode' => 'Invalidate sent phone code', 'method_auth.cancelCode_param_phone_number_type_string' => 'Phone number', 'method_auth.cancelCode_param_phone_code_hash_type_string' => 'Phone code hash', 'method_auth.dropTempAuthKeys' => 'Delete all temporary authorization keys except the ones provided', 'method_auth.dropTempAuthKeys_param_except_auth_keys_type_Vector t' => 'The temporary authorization keys to keep', 'method_account.registerDevice' => 'Register device for push notifications', 'method_account.registerDevice_param_token_type_type_int' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone, 6 - Blackberry, and other, see source code of official apps for more info', 'method_account.registerDevice_param_token_type_string' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone,6 - Blackberry, and other, see source code of official apps for more info', 'method_account.registerDevice_param_app_sandbox_type_Bool' => 'Should the app run in a sandbox?', 'method_account.registerDevice_param_other_uids_type_Vector t' => 'Other UIDs', 'method_account.unregisterDevice' => 'Stop sending PUSH notifications to app', 'method_account.unregisterDevice_param_token_type_type_int' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone,6 - Blackberry, and other, see source code of official apps for more info', 'method_account.unregisterDevice_param_token_type_string' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone,6 - Blackberry, and other, see source code of official apps for more info', 'method_account.unregisterDevice_param_other_uids_type_Vector t' => 'Other UIDs', 'method_account.updateNotifySettings' => 'Change notification settings', 'method_account.updateNotifySettings_param_peer_type_InputNotifyPeer' => 'The peers to which the notification settings should be applied', 'method_account.updateNotifySettings_param_settings_type_InputPeerNotifySettings' => 'Notification settings', 'method_account.getNotifySettings' => 'Get notification settings', 'method_account.getNotifySettings_param_peer_type_InputNotifyPeer' => 'Notification source ', 'method_account.resetNotifySettings' => 'Reset all notification settings', 'method_account.updateProfile' => 'Update profile info', 'method_account.updateProfile_param_first_name_type_string' => 'The first name', 'method_account.updateProfile_param_last_name_type_string' => 'The last name', 'method_account.updateProfile_param_about_type_string' => 'The bio/about field', 'method_account.updateStatus' => 'Update online status', 'method_account.updateStatus_param_offline_type_Bool' => 'True to set the status to offline', 'method_account.getWallPapers' => 'Returns a list of available wallpapers.', 'method_account.reportPeer' => 'Report for spam', 'method_account.reportPeer_param_peer_type_InputPeer' => 'The peer to report', 'method_account.reportPeer_param_reason_type_ReportReason' => 'Why are you reporting this peer', 'method_account.checkUsername' => 'Check if this username is available', 'method_account.checkUsername_param_username_type_string' => 'The username to check', 'method_account.updateUsername' => 'Update this user\'s username', 'method_account.updateUsername_param_username_type_string' => 'The new username', 'method_account.getPrivacy' => 'Get privacy settings', 'method_account.getPrivacy_param_key_type_InputPrivacyKey' => 'Privacy setting key', 'method_account.setPrivacy' => 'Set privacy settings', 'method_account.setPrivacy_param_key_type_InputPrivacyKey' => 'Privacy setting', 'method_account.setPrivacy_param_rules_type_Vector t' => 'Privacy settings', 'method_account.deleteAccount' => 'Delete this account', 'method_account.deleteAccount_param_reason_type_string' => 'Why are you going away? :(', 'method_account.getAccountTTL' => 'Get account TTL', 'method_account.setAccountTTL' => 'Set account TTL', 'method_account.setAccountTTL_param_ttl_type_AccountDaysTTL' => 'Time To Live of account', 'method_account.sendChangePhoneCode' => 'Change the phone number', 'method_account.sendChangePhoneCode_param_allow_flashcall_type_true' => 'Can the code be sent using a flash call instead of an SMS?', 'method_account.sendChangePhoneCode_param_phone_number_type_string' => 'New phone number', 'method_account.sendChangePhoneCode_param_current_number_type_Bool' => 'Current phone number', 'method_account.changePhone' => 'Change the phone number associated to this account', 'method_account.changePhone_param_phone_number_type_string' => 'Phone number', 'method_account.changePhone_param_phone_code_hash_type_string' => 'Phone code hash returned by account.sendChangePhoneCode', 'method_account.changePhone_param_phone_code_type_string' => 'The phone code sent by account.sendChangePhoneCode', 'method_account.updateDeviceLocked' => 'Disable all notifications for a certain period', 'method_account.updateDeviceLocked_param_period_type_int' => 'For how long should notifications be disabled', 'method_account.getAuthorizations' => 'Get all logged-in authorizations', 'method_account.resetAuthorization' => 'Delete a certain session', 'method_account.resetAuthorization_param_hash_type_long' => 'The session hash, obtained from $MadelineProto->account->getAuthorizations', 'method_account.getPassword' => 'Get the current password', 'method_account.getPasswordSettings' => 'Get the current 2FA settings', 'method_account.getPasswordSettings_param_current_password_hash_type_bytes' => 'Use only if you have set a 2FA password: `$current_salt = $MadelineProto->account->getPassword()[\'current_salt\']; $current_password_hash = hash(\'sha256\', $current_salt.$password.$current_salt, true);`', 'method_account.updatePasswordSettings' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'method_account.updatePasswordSettings_param_current_password_hash_type_bytes' => 'Use only if you have set a 2FA password: `$current_salt = $MadelineProto->account->getPassword()[\'current_salt\']; $current_password_hash = hash(\'sha256\', $current_salt.$password.$current_salt, true);`', 'method_account.updatePasswordSettings_param_new_settings_type_account.PasswordInputSettings' => 'New 2FA settings', 'method_account.sendConfirmPhoneCode' => 'Send confirmation phone code', 'method_account.sendConfirmPhoneCode_param_allow_flashcall_type_true' => 'Can telegram call you instead of sending an SMS?', 'method_account.sendConfirmPhoneCode_param_hash_type_string' => 'The hash', 'method_account.sendConfirmPhoneCode_param_current_number_type_Bool' => 'The current phone number', 'method_account.confirmPhone' => 'Confirm this phone number is associated to this account, obtain phone_code_hash from sendConfirmPhoneCode', 'method_account.confirmPhone_param_phone_code_hash_type_string' => 'Obtain phone_code_hash from sendConfirmPhoneCode', 'method_account.confirmPhone_param_phone_code_type_string' => 'The code sent by sendConfirmPhoneCode', 'method_account.getTmpPassword' => 'Get temporary password for buying products through bots', 'method_account.getTmpPassword_param_password_hash_type_bytes' => 'The password hash', 'method_account.getTmpPassword_param_period_type_int' => 'The validity period', 'method_account.getWebAuthorizations' => 'Get telegram web login authorizations', 'method_account.resetWebAuthorization' => 'Delete a certain telegram web login authorization', 'method_account.resetWebAuthorization_param_hash_type_long' => 'The authorization\'s hash', 'method_account.resetWebAuthorizations' => 'Reset all telegram web login authorizations', 'method_users.getUsers' => 'Get info about users', 'method_users.getUsers_param_id_type_Vector t' => 'The ids of the users', 'method_users.getFullUser' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_users.getFullUser_param_id_type_InputUser' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_contacts.getStatuses' => 'Get online status of all users', 'method_contacts.getContacts' => 'Get all contacts', 'method_contacts.getContacts_param_hash_type_int' => 'User ids of contacts previously fetched with this method', 'method_contacts.importContacts' => 'Add phone number as contact', 'method_contacts.importContacts_param_contacts_type_Vector t' => 'The numbers to import', 'method_contacts.deleteContact' => 'Delete a contact', 'method_contacts.deleteContact_param_id_type_InputUser' => 'The contact to delete', 'method_contacts.deleteContacts' => 'Delete multiple contacts', 'method_contacts.deleteContacts_param_id_type_Vector t' => 'The contacts to delete', 'method_contacts.block' => 'Block a user', 'method_contacts.block_param_id_type_InputUser' => 'The user to block', 'method_contacts.unblock' => 'Unblock a user', 'method_contacts.unblock_param_id_type_InputUser' => 'The user to unblock', 'method_contacts.getBlocked' => 'Get blocked users', 'method_contacts.getBlocked_param_offset_type_int' => 'Initially 0, then set to the number of blocked contacts previously fetched', 'method_contacts.getBlocked_param_limit_type_int' => 'How many blocked contacts to fetch', 'method_contacts.exportCard' => 'Export contact as card', 'method_contacts.importCard' => 'Import card as contact', 'method_contacts.importCard_param_export_card_type_Vector t' => 'The card', 'method_contacts.search' => 'Search contacts', 'method_contacts.search_param_q_type_string' => 'The search query', 'method_contacts.search_param_limit_type_int' => 'How many results should be returned', 'method_contacts.resolveUsername' => 'You cannot use this method directly, use the resolve_username, get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_contacts.resolveUsername_param_username_type_string' => 'You cannot use this method directly, use the resolve_username, get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_contacts.getTopPeers' => 'Get most used chats', 'method_contacts.getTopPeers_param_correspondents_type_true' => 'Fetch users?', 'method_contacts.getTopPeers_param_bots_pm_type_true' => 'Fetch bots?', 'method_contacts.getTopPeers_param_bots_inline_type_true' => 'Fetch inline bots?', 'method_contacts.getTopPeers_param_phone_calls_type_true' => 'Fetch phone calls?', 'method_contacts.getTopPeers_param_groups_type_true' => 'Fetch groups?', 'method_contacts.getTopPeers_param_channels_type_true' => 'Fetch channels and supergroups?', 'method_contacts.getTopPeers_param_offset_type_int' => 'Initially 0, then `$offset += $contacts_TopPeers[\'categories\'][\'count\'];`', 'method_contacts.getTopPeers_param_limit_type_int' => 'How many results to fetch', 'method_contacts.getTopPeers_param_hash_type_int' => 'Peer ids previously fetched with this method', 'method_contacts.resetTopPeerRating' => 'Reset top peer rating for a certain category/peer', 'method_contacts.resetTopPeerRating_param_category_type_TopPeerCategory' => 'The category ', 'method_contacts.resetTopPeerRating_param_peer_type_InputPeer' => 'The peer', 'method_contacts.resetSaved' => 'Reset saved contacts', 'method_messages.getMessages' => 'Get messages', 'method_messages.getMessages_param_id_type_Vector t' => 'The IDs of messages to fetch (only for users and normal groups)', 'method_messages.getDialogs' => 'Gets list of chats: you should use $MadelineProto->get_dialogs() instead: https://docs.madelineproto.xyz/docs/DIALOGS.html', 'method_messages.getDialogs_param_exclude_pinned_type_true' => 'Do not fetch pinned chats', 'method_messages.getDialogs_param_offset_date_type_int' => 'End($res[\'messages\'])[\'date\'];', 'method_messages.getDialogs_param_offset_id_type_int' => 'End($res[\'messages\'])[\'id\'];', 'method_messages.getDialogs_param_offset_peer_type_InputPeer' => 'End($res[\'dialogs\'])[\'peer\'];', 'method_messages.getDialogs_param_limit_type_int' => 'Number of dialogs to fetch', 'method_messages.getHistory' => 'Get previous messages of a group', 'method_messages.getHistory_param_peer_type_InputPeer' => 'The chat', 'method_messages.getHistory_param_offset_id_type_int' => 'The last fetched message ID, initially 0', 'method_messages.getHistory_param_offset_date_type_int' => 'The date of the last previously fetched message, initially 0', 'method_messages.getHistory_param_add_offset_type_int' => 'Additional offset, can be 0', 'method_messages.getHistory_param_limit_type_int' => 'Number of messages to fetch', 'method_messages.getHistory_param_max_id_type_int' => 'Maximum message ID to fetch', 'method_messages.getHistory_param_min_id_type_int' => 'Minumum message ID to fetch', 'method_messages.getHistory_param_hash_type_int' => 'List of IDs of already parsed messages', 'method_messages.search' => 'Search peers or messages', 'method_messages.search_param_peer_type_InputPeer' => 'Where to search', 'method_messages.search_param_q_type_string' => 'What to search', 'method_messages.search_param_from_id_type_InputUser' => 'Show only messages from a certain user?', 'method_messages.search_param_filter_type_MessagesFilter' => 'Message filter', 'method_messages.search_param_min_date_type_int' => 'Minumum date of results to fetch', 'method_messages.search_param_max_date_type_int' => 'Maximum date of results to fetch', 'method_messages.search_param_offset_id_type_int' => 'Message ID offset', 'method_messages.search_param_add_offset_type_int' => 'Additional offset, can be 0', 'method_messages.search_param_limit_type_int' => 'Number of results to return', 'method_messages.search_param_max_id_type_int' => 'Maximum message id to return', 'method_messages.search_param_min_id_type_int' => 'Minumum message id to return', 'method_messages.readHistory' => 'Mark messages as read', 'method_messages.readHistory_param_peer_type_InputPeer' => 'Where to mark messages as read', 'method_messages.readHistory_param_max_id_type_int' => 'Maximum message ID to mark as read', 'method_messages.deleteHistory' => 'Delete chat history', 'method_messages.deleteHistory_param_just_clear_type_true' => 'Only clear it from your side', 'method_messages.deleteHistory_param_peer_type_InputPeer' => 'Where to clear it', 'method_messages.deleteHistory_param_max_id_type_int' => 'Maximum message id of messages to delete', 'method_messages.deleteMessages' => 'Delete messages', 'method_messages.deleteMessages_param_revoke_type_true' => 'Delete the messages for everyone?', 'method_messages.deleteMessages_param_id_type_Vector t' => 'IDs of messages to delete, use channels->deleteMessages for supergroups', 'method_messages.receivedMessages' => 'Mark messages as read', 'method_messages.receivedMessages_param_max_id_type_int' => 'Maximum message id of messages to mark as read', 'method_messages.setTyping' => 'Change typing status', 'method_messages.setTyping_param_peer_type_InputPeer' => 'Where to change typing status', 'method_messages.setTyping_param_action_type_SendMessageAction' => 'Typing status', 'method_messages.sendMessage' => 'Send a message', 'method_messages.sendMessage_param_no_webpage_type_true' => 'Disable webpage preview?', 'method_messages.sendMessage_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendMessage_param_background_type_true' => 'Disable background notifications?', 'method_messages.sendMessage_param_clear_draft_type_true' => 'Clear the message draft of this chat?', 'method_messages.sendMessage_param_peer_type_InputPeer' => 'The chat where to send this message', 'method_messages.sendMessage_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendMessage_param_message_type_string' => 'The message to send', 'method_messages.sendMessage_param_reply_markup_type_ReplyMarkup' => 'Keyboards to send', 'method_messages.sendMessage_param_entities_type_Vector t' => 'Entities to send (for styled text)', 'method_messages.sendMedia' => 'Send a media', 'method_messages.sendMedia_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendMedia_param_background_type_true' => 'Disable background notifications?', 'method_messages.sendMedia_param_clear_draft_type_true' => 'Clear the message draft of this chat?', 'method_messages.sendMedia_param_peer_type_InputPeer' => 'Where to send the media', 'method_messages.sendMedia_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendMedia_param_media_type_InputMedia' => 'The media to send', 'method_messages.sendMedia_param_message_type_string' => 'The caption', 'method_messages.sendMedia_param_reply_markup_type_ReplyMarkup' => 'Keyboards to send', 'method_messages.sendMedia_param_entities_type_Vector t' => 'Entities for styled text', 'method_messages.forwardMessages' => 'Forward messages', 'method_messages.forwardMessages_param_silent_type_true' => 'Disable notifications', 'method_messages.forwardMessages_param_background_type_true' => 'Disable background notifications', 'method_messages.forwardMessages_param_with_my_score_type_true' => 'If forwarding a game, forward your score, too', 'method_messages.forwardMessages_param_grouped_type_true' => 'Set to true if forwarding albums', 'method_messages.forwardMessages_param_from_peer_type_InputPeer' => 'From where to forward the messages', 'method_messages.forwardMessages_param_id_type_Vector t' => 'The message IDs', 'method_messages.forwardMessages_param_to_peer_type_InputPeer' => 'Where to forward the messages', 'method_messages.reportSpam' => 'Report a peer for spam', 'method_messages.reportSpam_param_peer_type_InputPeer' => 'The peer to report', 'method_messages.hideReportSpam' => 'Hide report spam popup', 'method_messages.hideReportSpam_param_peer_type_InputPeer' => 'Where to hide the popup', 'method_messages.getPeerSettings' => 'Get the settings of apeer', 'method_messages.getPeerSettings_param_peer_type_InputPeer' => 'The peer', 'method_messages.getChats' => 'Get info about chats', 'method_messages.getChats_param_id_type_Vector t' => 'The MTProto IDs of chats to fetch info about', 'method_messages.getFullChat' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_messages.getFullChat_param_chat_id_type_InputPeer' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_messages.editChatTitle' => 'Edit the title of a normal chat (not supergroup)', 'method_messages.editChatTitle_param_chat_id_type_InputPeer' => 'The ID of the chat', 'method_messages.editChatTitle_param_title_type_string' => 'The new title', 'method_messages.editChatPhoto' => 'Edit the photo of a normal chat (not supergroup)', 'method_messages.editChatPhoto_param_chat_id_type_InputPeer' => 'The ID of the chat', 'method_messages.editChatPhoto_param_photo_type_InputChatPhoto' => 'The new phto', 'method_messages.addChatUser' => 'Add a user to a normal chat (use channels->inviteToChannel for supergroups)', 'method_messages.addChatUser_param_chat_id_type_InputPeer' => 'The chat where to invite users', 'method_messages.addChatUser_param_user_id_type_InputUser' => 'The user to invite', 'method_messages.addChatUser_param_fwd_limit_type_int' => 'Number of old messages the user will see', 'method_messages.deleteChatUser' => 'Delete a user from a chat (not supergroup)', 'method_messages.deleteChatUser_param_chat_id_type_InputPeer' => 'The ID of the chat', 'method_messages.deleteChatUser_param_user_id_type_InputUser' => 'The user to delete (pass @me to leave the chat)', 'method_messages.createChat' => 'Create a chat (not supergroup)', 'method_messages.createChat_param_users_type_Vector t' => 'The users to add to the chat', 'method_messages.createChat_param_title_type_string' => 'The new chat\'s title', 'method_messages.getDhConfig' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'method_messages.getDhConfig_param_version_type_int' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'method_messages.getDhConfig_param_random_length_type_int' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'method_messages.requestEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.requestEncryption_param_user_id_type_InputUser' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.requestEncryption_param_g_a_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption_param_peer_type_InputEncryptedChat' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption_param_g_b_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption_param_key_fingerprint_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.discardEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.discardEncryption_param_chat_id_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.setEncryptedTyping' => 'Send typing notification to secret chat', 'method_messages.setEncryptedTyping_param_peer_type_InputEncryptedChat' => 'The secret chat where to send the notification', 'method_messages.setEncryptedTyping_param_typing_type_Bool' => 'Set to true to enable the notification, false to disable it', 'method_messages.readEncryptedHistory' => 'Mark messages as read in secret chats', 'method_messages.readEncryptedHistory_param_peer_type_InputEncryptedChat' => 'The secret chat where to mark messages as read', 'method_messages.readEncryptedHistory_param_max_date_type_int' => 'Maximum date of messages to mark', 'method_messages.sendEncrypted' => 'Send message to secret chat', 'method_messages.sendEncrypted_param_peer_type_InputEncryptedChat' => 'The chat where to send the message', 'method_messages.sendEncrypted_param_message_type_DecryptedMessage' => 'The message to send', 'method_messages.sendEncryptedFile' => 'Send a file to a secret chat', 'method_messages.sendEncryptedFile_param_peer_type_InputEncryptedChat' => 'The chat where to send the file', 'method_messages.sendEncryptedFile_param_message_type_DecryptedMessage' => 'The message with the file', 'method_messages.sendEncryptedFile_param_file_type_InputEncryptedFile' => 'The file (optional)', 'method_messages.sendEncryptedService' => 'Send a service message to a secret chat', 'method_messages.sendEncryptedService_param_peer_type_InputEncryptedChat' => 'The chat where to send the service message', 'method_messages.sendEncryptedService_param_message_type_DecryptedMessage' => 'The service message', 'method_messages.receivedQueue' => 'You cannot use this method directly', 'method_messages.receivedQueue_param_max_qts_type_int' => 'You cannot use this method directly', 'method_messages.reportEncryptedSpam' => 'Report for spam a secret chat', 'method_messages.reportEncryptedSpam_param_peer_type_InputEncryptedChat' => 'The chat to report', 'method_messages.readMessageContents' => 'Mark message as read', 'method_messages.readMessageContents_param_id_type_Vector t' => 'The messages to mark as read (only users and normal chats, not supergroups)', 'method_messages.getStickers' => 'Get stickers', 'method_messages.getStickers_param_emoticon_type_string' => 'Search by emoji', 'method_messages.getStickers_param_hash_type_string' => 'Previously fetched sticker IDs', 'method_messages.getAllStickers' => 'Get all stickerpacks', 'method_messages.getAllStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.getWebPagePreview' => 'Get webpage preview', 'method_messages.getWebPagePreview_param_message_type_string' => 'Extract preview from this message', 'method_messages.getWebPagePreview_param_entities_type_Vector t' => 'Entities for styled text', 'method_messages.exportChatInvite' => 'Export chat invite ', 'method_messages.exportChatInvite_param_chat_id_type_InputPeer' => 'The chat id ', 'method_messages.checkChatInvite' => 'Check if an invitation link is valid', 'method_messages.checkChatInvite_param_hash_type_string' => 'The invite link in t.me/joinchat/aflakf format', 'method_messages.importChatInvite' => 'Import chat invite', 'method_messages.importChatInvite_param_hash_type_string' => 'The invite link in t.me/joinchat/aflakf format', 'method_messages.getStickerSet' => 'Get a stickerset', 'method_messages.getStickerSet_param_stickerset_type_InputStickerSet' => 'The stickerset to get', 'method_messages.installStickerSet' => 'Add a sticker set', 'method_messages.installStickerSet_param_stickerset_type_InputStickerSet' => 'The sticker set to add', 'method_messages.installStickerSet_param_archived_type_Bool' => 'Archive this set?', 'method_messages.uninstallStickerSet' => 'Remove a sticker set', 'method_messages.uninstallStickerSet_param_stickerset_type_InputStickerSet' => 'The sticker set to remove', 'method_messages.startBot' => 'Start a bot', 'method_messages.startBot_param_bot_type_InputUser' => 'The bot\'s ID or username', 'method_messages.startBot_param_peer_type_InputPeer' => 'Where to start the bot (@me or group ID/username)', 'method_messages.startBot_param_start_param_type_string' => 'The bot\'s start parameter', 'method_messages.getMessagesViews' => 'Get and increase message views', 'method_messages.getMessagesViews_param_peer_type_InputPeer' => 'The chat where the message is located', 'method_messages.getMessagesViews_param_id_type_Vector t' => 'The IDs messages to get', 'method_messages.getMessagesViews_param_increment_type_Bool' => 'Increase message views?', 'method_messages.toggleChatAdmins' => 'Enable all users are admins in normal groups (not supergroups)', 'method_messages.toggleChatAdmins_param_chat_id_type_InputPeer' => 'Group ID', 'method_messages.toggleChatAdmins_param_enabled_type_Bool' => 'Enable all users are admins', 'method_messages.editChatAdmin' => 'Edit admin permissions', 'method_messages.editChatAdmin_param_chat_id_type_InputPeer' => 'The chat ID (no supergroups)', 'method_messages.editChatAdmin_param_user_id_type_InputUser' => 'The user ID', 'method_messages.editChatAdmin_param_is_admin_type_Bool' => 'Should the user be admin?', 'method_messages.migrateChat' => 'Convert chat to supergroup', 'method_messages.migrateChat_param_chat_id_type_InputPeer' => 'The chat to convert', 'method_messages.searchGlobal' => 'Global message search', 'method_messages.searchGlobal_param_q_type_string' => 'The query', 'method_messages.searchGlobal_param_offset_date_type_int' => '0 or the date offset', 'method_messages.searchGlobal_param_offset_peer_type_InputPeer' => '0 or the peer offset', 'method_messages.searchGlobal_param_offset_id_type_int' => '0 or the message ID offset', 'method_messages.searchGlobal_param_limit_type_int' => 'The number of results to return', 'method_messages.reorderStickerSets' => 'Reorder sticker sets', 'method_messages.reorderStickerSets_param_masks_type_true' => 'Reorder masks?', 'method_messages.reorderStickerSets_param_order_type_Vector t' => 'The order', 'method_messages.getDocumentByHash' => 'Get document by SHA256 hash', 'method_messages.getDocumentByHash_param_sha256_type_bytes' => '`hash(\'sha256\', $filename, true);`', 'method_messages.getDocumentByHash_param_size_type_int' => 'The file size', 'method_messages.getDocumentByHash_param_mime_type_type_string' => 'The mime type of the file', 'method_messages.searchGifs' => 'Search gifs', 'method_messages.searchGifs_param_q_type_string' => 'The search query', 'method_messages.searchGifs_param_offset_type_int' => 'The offset ', 'method_messages.getSavedGifs' => 'Get saved gifs', 'method_messages.getSavedGifs_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.saveGif' => 'Save a GIF', 'method_messages.saveGif_param_id_type_InputDocument' => 'The GIF to save', 'method_messages.saveGif_param_unsave_type_Bool' => 'Remove the gif?', 'method_messages.getInlineBotResults' => 'Call inline bot', 'method_messages.getInlineBotResults_param_bot_type_InputUser' => 'The bot to call', 'method_messages.getInlineBotResults_param_peer_type_InputPeer' => 'The chat where to call the bot', 'method_messages.getInlineBotResults_param_geo_point_type_InputGeoPoint' => 'The current location', 'method_messages.getInlineBotResults_param_query_type_string' => 'The query to send to the bot', 'method_messages.getInlineBotResults_param_offset_type_string' => 'The offset to send to the bot', 'method_messages.setInlineBotResults' => 'Bots only: set the results of an inline query', 'method_messages.setInlineBotResults_param_gallery_type_true' => 'Is this a gallery?', 'method_messages.setInlineBotResults_param_private_type_true' => 'Is this result private (not cached)?', 'method_messages.setInlineBotResults_param_query_id_type_long' => 'Query ID', 'method_messages.setInlineBotResults_param_results_type_Vector t' => 'Results', 'method_messages.setInlineBotResults_param_cache_time_type_int' => 'Cache time', 'method_messages.setInlineBotResults_param_next_offset_type_string' => 'The next offset', 'method_messages.setInlineBotResults_param_switch_pm_type_InlineBotSwitchPM' => 'Switch to PM?', 'method_messages.sendInlineBotResult' => 'Send inline bot result obtained with messages.getInlineBotResults to the chat', 'method_messages.sendInlineBotResult_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendInlineBotResult_param_background_type_true' => 'Disable background notifications?', 'method_messages.sendInlineBotResult_param_clear_draft_type_true' => 'Clear the message draft?', 'method_messages.sendInlineBotResult_param_peer_type_InputPeer' => 'Where to send the message', 'method_messages.sendInlineBotResult_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendInlineBotResult_param_query_id_type_long' => 'The inline query ID', 'method_messages.sendInlineBotResult_param_id_type_string' => 'The ID of one of the inline results', 'method_messages.getMessageEditData' => 'Check if about to edit a message or a media caption', 'method_messages.getMessageEditData_param_peer_type_InputPeer' => 'The chat', 'method_messages.getMessageEditData_param_id_type_int' => 'The message ID', 'method_messages.editMessage' => 'Edit a message', 'method_messages.editMessage_param_no_webpage_type_true' => 'Disable webpage preview', 'method_messages.editMessage_param_stop_geo_live_type_true' => 'Stop live location', 'method_messages.editMessage_param_peer_type_InputPeer' => 'The chat', 'method_messages.editMessage_param_id_type_int' => 'The message ID', 'method_messages.editMessage_param_message_type_string' => 'The new message', 'method_messages.editMessage_param_reply_markup_type_ReplyMarkup' => 'The new keyboard', 'method_messages.editMessage_param_entities_type_Vector t' => 'The new entities (for styled text)', 'method_messages.editMessage_param_geo_point_type_InputGeoPoint' => 'The new location', 'method_messages.editInlineBotMessage' => 'Edit a sent inline message', 'method_messages.editInlineBotMessage_param_no_webpage_type_true' => 'Disable webpage preview', 'method_messages.editInlineBotMessage_param_stop_geo_live_type_true' => 'Stop live location', 'method_messages.editInlineBotMessage_param_id_type_InputBotInlineMessageID' => 'The message ID', 'method_messages.editInlineBotMessage_param_message_type_string' => 'The new message', 'method_messages.editInlineBotMessage_param_reply_markup_type_ReplyMarkup' => 'The new keyboard', 'method_messages.editInlineBotMessage_param_entities_type_Vector t' => 'The new entities (for styled text)', 'method_messages.editInlineBotMessage_param_geo_point_type_InputGeoPoint' => 'The new location', 'method_messages.getBotCallbackAnswer' => 'Get the callback answer of a bot (after clicking a button)', 'method_messages.getBotCallbackAnswer_param_game_type_true' => 'Is this a game?', 'method_messages.getBotCallbackAnswer_param_peer_type_InputPeer' => 'The chat', 'method_messages.getBotCallbackAnswer_param_msg_id_type_int' => 'The message ID', 'method_messages.getBotCallbackAnswer_param_data_type_bytes' => 'The data to send to the bot', 'method_messages.setBotCallbackAnswer' => 'Bots only: set the callback answer (after a button was clicked)', 'method_messages.setBotCallbackAnswer_param_alert_type_true' => 'Is this an alert?', 'method_messages.setBotCallbackAnswer_param_query_id_type_long' => 'The query ID', 'method_messages.setBotCallbackAnswer_param_message_type_string' => 'The message', 'method_messages.setBotCallbackAnswer_param_url_type_string' => 'The URL', 'method_messages.setBotCallbackAnswer_param_cache_time_type_int' => 'Cache time', 'method_messages.getPeerDialogs' => 'Get dialog info of peers', 'method_messages.getPeerDialogs_param_peers_type_Vector t' => 'The peers', 'method_messages.saveDraft' => 'Save a message draft', 'method_messages.saveDraft_param_no_webpage_type_true' => 'Disable webpage preview', 'method_messages.saveDraft_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.saveDraft_param_peer_type_InputPeer' => 'The chat', 'method_messages.saveDraft_param_message_type_string' => 'The message', 'method_messages.saveDraft_param_entities_type_Vector t' => 'The entities (for styled text)', 'method_messages.getAllDrafts' => 'Get all message drafts', 'method_messages.getFeaturedStickers' => 'Get featured stickers', 'method_messages.getFeaturedStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.readFeaturedStickers' => 'Mark new featured stickers as read', 'method_messages.readFeaturedStickers_param_id_type_Vector t' => 'The stickers to mark as read', 'method_messages.getRecentStickers' => 'Get recent stickers', 'method_messages.getRecentStickers_param_attached_type_true' => 'Get stickers attached to image?', 'method_messages.getRecentStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.saveRecentSticker' => 'Add a sticker to recent stickers', 'method_messages.saveRecentSticker_param_attached_type_true' => 'Get stickers attached to image?', 'method_messages.saveRecentSticker_param_id_type_InputDocument' => 'The sticker', 'method_messages.saveRecentSticker_param_unsave_type_Bool' => 'Remove the sticker from recent stickers?', 'method_messages.clearRecentStickers' => 'Clear all recent stickers', 'method_messages.clearRecentStickers_param_attached_type_true' => 'Clear recent stickers attached to images?', 'method_messages.getArchivedStickers' => 'Get all archived stickers', 'method_messages.getArchivedStickers_param_masks_type_true' => 'Get masks?', 'method_messages.getArchivedStickers_param_offset_id_type_long' => 'Sticker ID offset', 'method_messages.getArchivedStickers_param_limit_type_int' => 'Number of stickers to fetch', 'method_messages.getMaskStickers' => 'Get masks', 'method_messages.getMaskStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.getAttachedStickers' => 'Get stickers attachable to images', 'method_messages.getAttachedStickers_param_media_type_InputStickeredMedia' => 'The stickered media', 'method_messages.setGameScore' => 'Set the game score', 'method_messages.setGameScore_param_edit_message_type_true' => 'Should the message with the game be edited?', 'method_messages.setGameScore_param_force_type_true' => 'Force setting the game score', 'method_messages.setGameScore_param_peer_type_InputPeer' => 'The chat where the game was sent', 'method_messages.setGameScore_param_id_type_int' => 'The message ID', 'method_messages.setGameScore_param_user_id_type_InputUser' => 'The user that set the score', 'method_messages.setGameScore_param_score_type_int' => 'The score', 'method_messages.setInlineGameScore' => 'Set the game score of an inline message', 'method_messages.setInlineGameScore_param_edit_message_type_true' => 'Should the message with the game be edited?', 'method_messages.setInlineGameScore_param_force_type_true' => 'Force setting the game score', 'method_messages.setInlineGameScore_param_id_type_InputBotInlineMessageID' => 'The ID of the inline message', 'method_messages.setInlineGameScore_param_user_id_type_InputUser' => 'The user that set the score', 'method_messages.setInlineGameScore_param_score_type_int' => 'The score', 'method_messages.getGameHighScores' => 'Get high scores of a game', 'method_messages.getGameHighScores_param_peer_type_InputPeer' => 'The chat', 'method_messages.getGameHighScores_param_id_type_int' => 'The message ID', 'method_messages.getGameHighScores_param_user_id_type_InputUser' => 'The user that set the high scores', 'method_messages.getInlineGameHighScores' => 'Get high scores of a game sent in an inline message', 'method_messages.getInlineGameHighScores_param_id_type_InputBotInlineMessageID' => 'The inline message', 'method_messages.getInlineGameHighScores_param_user_id_type_InputUser' => 'The user that set the high scores', 'method_messages.getCommonChats' => 'Get chats in common with a user', 'method_messages.getCommonChats_param_user_id_type_InputUser' => 'The user', 'method_messages.getCommonChats_param_max_id_type_int' => 'The maximum chat ID to fetch', 'method_messages.getCommonChats_param_limit_type_int' => 'Number of results to fetch', 'method_messages.getAllChats' => 'Get all chats (not supergroups or channels)', 'method_messages.getAllChats_param_except_ids_type_Vector t' => 'Do not fetch these chats (MTProto id)', 'method_messages.getWebPage' => 'Get webpage preview', 'method_messages.getWebPage_param_url_type_string' => 'URL', 'method_messages.getWebPage_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.toggleDialogPin' => 'Pin or unpin dialog', 'method_messages.toggleDialogPin_param_pinned_type_true' => 'Pin or unpin the dialog?', 'method_messages.toggleDialogPin_param_peer_type_InputPeer' => 'The peer to pin', 'method_messages.reorderPinnedDialogs' => 'Reorder pinned dialogs', 'method_messages.reorderPinnedDialogs_param_force_type_true' => 'Force reordering', 'method_messages.reorderPinnedDialogs_param_order_type_Vector t' => 'New order', 'method_messages.getPinnedDialogs' => 'Get pinned dialogs', 'method_messages.setBotShippingResults' => 'Bots only: set shipping results', 'method_messages.setBotShippingResults_param_query_id_type_long' => 'Query ID', 'method_messages.setBotShippingResults_param_error_type_string' => 'Error', 'method_messages.setBotShippingResults_param_shipping_options_type_Vector t' => 'Shipping options', 'method_messages.setBotPrecheckoutResults' => 'Bots only: set precheckout results', 'method_messages.setBotPrecheckoutResults_param_success_type_true' => 'Success?', 'method_messages.setBotPrecheckoutResults_param_query_id_type_long' => 'Query ID', 'method_messages.setBotPrecheckoutResults_param_error_type_string' => 'Error', 'method_messages.uploadMedia' => 'Upload a file without sending it to anyone', 'method_messages.uploadMedia_param_peer_type_InputPeer' => 'Nothing', 'method_messages.uploadMedia_param_media_type_InputMedia' => 'The media to upload', 'method_messages.sendScreenshotNotification' => 'Send screenshot notification', 'method_messages.sendScreenshotNotification_param_peer_type_InputPeer' => 'Where to send the notification', 'method_messages.sendScreenshotNotification_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.getFavedStickers' => 'Get favorite stickers', 'method_messages.getFavedStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.faveSticker' => 'Add a sticker to favorites', 'method_messages.faveSticker_param_id_type_InputDocument' => 'The sticker to add to favorites', 'method_messages.faveSticker_param_unfave_type_Bool' => 'Remove it from favorites?', 'method_messages.getUnreadMentions' => 'Get unread mentions', 'method_messages.getUnreadMentions_param_peer_type_InputPeer' => 'The chat where to get unread mentions', 'method_messages.getUnreadMentions_param_offset_id_type_int' => 'The offset', 'method_messages.getUnreadMentions_param_add_offset_type_int' => 'The additional offset', 'method_messages.getUnreadMentions_param_limit_type_int' => 'The number of results to fetch', 'method_messages.getUnreadMentions_param_max_id_type_int' => 'The maximum message ID to fetch', 'method_messages.getUnreadMentions_param_min_id_type_int' => 'The minumum message ID to fetch', 'method_messages.readMentions' => 'Mark mentions as read', 'method_messages.readMentions_param_peer_type_InputPeer' => 'The chat', 'method_messages.getRecentLocations' => 'Get recent locations', 'method_messages.getRecentLocations_param_peer_type_InputPeer' => 'The chat where to search locations', 'method_messages.getRecentLocations_param_limit_type_int' => 'Number of results to return', 'method_messages.sendMultiMedia' => 'Send an album', 'method_messages.sendMultiMedia_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendMultiMedia_param_background_type_true' => 'Disable background notification?', 'method_messages.sendMultiMedia_param_clear_draft_type_true' => 'Clear draft?', 'method_messages.sendMultiMedia_param_peer_type_InputPeer' => 'Where to send the album', 'method_messages.sendMultiMedia_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendMultiMedia_param_multi_media_type_Vector t' => 'The album', 'method_messages.uploadEncryptedFile' => 'Upload a secret chat file without sending it to anyone', 'method_messages.uploadEncryptedFile_param_peer_type_InputEncryptedChat' => 'The chat where to upload the media', 'method_messages.uploadEncryptedFile_param_file_type_InputEncryptedFile' => 'The file', 'method_updates.getState' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_pts_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_pts_total_limit_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_date_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_qts_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_force_type_true' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_channel_type_InputChannel' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_filter_type_ChannelMessagesFilter' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_pts_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_limit_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_photos.updateProfilePhoto' => 'Change the profile photo', 'method_photos.updateProfilePhoto_param_id_type_InputPhoto' => 'The photo to use', 'method_photos.uploadProfilePhoto' => 'Upload profile photo', 'method_photos.uploadProfilePhoto_param_file_type_InputFile' => 'The photo', 'method_photos.deletePhotos' => 'Delete profile photos', 'method_photos.deletePhotos_param_id_type_Vector t' => 'The profile photos to delete', 'method_photos.getUserPhotos' => 'Get the profile photos of a user', 'method_photos.getUserPhotos_param_user_id_type_InputUser' => 'The user', 'method_photos.getUserPhotos_param_offset_type_int' => 'Offset', 'method_photos.getUserPhotos_param_max_id_type_long' => 'Maximum ID of photo to return', 'method_photos.getUserPhotos_param_limit_type_int' => 'Number of photos to return', 'method_upload.saveFilePart' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveFilePart_param_file_id_type_long' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveFilePart_param_file_part_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveFilePart_param_bytes_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile_param_location_type_InputFileLocation' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile_param_offset_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile_param_limit_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_file_id_type_long' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_file_part_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_file_total_parts_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_bytes_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getWebFile' => 'Download a file through telegram', 'method_upload.getWebFile_param_location_type_InputWebFileLocation' => 'The file', 'method_upload.getWebFile_param_offset_type_int' => 'The offset in bytes', 'method_upload.getWebFile_param_limit_type_int' => 'The number of bytes to fetch', 'method_upload.getCdnFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFile_param_file_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFile_param_offset_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFile_param_limit_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.reuploadCdnFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.reuploadCdnFile_param_file_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.reuploadCdnFile_param_request_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFileHashes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFileHashes_param_file_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFileHashes_param_offset_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_help.getConfig' => 'Get server configuration', 'method_help.getNearestDc' => 'Get nearest datacenter', 'method_help.getAppUpdate' => 'Get info about app updates', 'method_help.saveAppLog' => 'Log data for developer of this app', 'method_help.saveAppLog_param_events_type_Vector t' => 'Event list', 'method_help.getInviteText' => 'Get invitation text', 'method_help.getSupport' => 'Get info of support user', 'method_help.getAppChangelog' => 'Get the changelog of this app', 'method_help.getAppChangelog_param_prev_app_version_type_string' => 'Previous app version', 'method_help.getTermsOfService' => 'Get terms of service', 'method_help.setBotUpdatesStatus' => 'Set the update status of webhook', 'method_help.setBotUpdatesStatus_param_pending_updates_count_type_int' => 'Pending update count', 'method_help.setBotUpdatesStatus_param_message_type_string' => 'Message', 'method_help.getCdnConfig' => 'Get CDN configuration', 'method_help.getRecentMeUrls' => 'Get recent t.me URLs', 'method_help.getRecentMeUrls_param_referer_type_string' => 'Referrer', 'method_channels.readHistory' => 'Mark channel/supergroup history as read', 'method_channels.readHistory_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.readHistory_param_max_id_type_int' => 'Maximum message ID to mark as read', 'method_channels.deleteMessages' => 'Delete channel/supergroup messages', 'method_channels.deleteMessages_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.deleteMessages_param_id_type_Vector t' => 'The IDs of messages to delete', 'method_channels.deleteUserHistory' => 'Delete all messages of a user in a channel/supergroup', 'method_channels.deleteUserHistory_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.deleteUserHistory_param_user_id_type_InputUser' => 'The user', 'method_channels.reportSpam' => 'Report a message in a supergroup/channel for spam', 'method_channels.reportSpam_param_channel_type_InputChannel' => 'The channel', 'method_channels.reportSpam_param_user_id_type_InputUser' => 'The user that sent the messages', 'method_channels.reportSpam_param_id_type_Vector t' => 'The IDs of messages to report', 'method_channels.getMessages' => 'Get channel/supergroup messages', 'method_channels.getMessages_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.getMessages_param_id_type_Vector t' => 'The message IDs', 'method_channels.getParticipants' => 'Get channel/supergroup participants (you should use `$MadelineProto->get_pwr_chat($id)` instead)', 'method_channels.getParticipants_param_channel_type_InputChannel' => 'The channel', 'method_channels.getParticipants_param_filter_type_ChannelParticipantsFilter' => 'Member filter', 'method_channels.getParticipants_param_offset_type_int' => 'Offset', 'method_channels.getParticipants_param_limit_type_int' => 'Limit', 'method_channels.getParticipants_param_hash_type_int' => 'Sorted list of IDs of participants you already fetched', 'method_channels.getParticipant' => 'Get info about a certain channel/supergroup participant', 'method_channels.getParticipant_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.getParticipant_param_user_id_type_InputUser' => 'The user to fetch info about', 'method_channels.getChannels' => 'Get info about multiple channels/supergroups', 'method_channels.getChannels_param_id_type_Vector t' => 'The channel/supergroup MTProto IDs', 'method_channels.getFullChannel' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_channels.getFullChannel_param_channel_type_InputChannel' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_channels.createChannel' => 'Create channel/supergroup', 'method_channels.createChannel_param_broadcast_type_true' => 'Set this to true to create a channel', 'method_channels.createChannel_param_megagroup_type_true' => 'Set this to true to create a supergroup', 'method_channels.createChannel_param_title_type_string' => 'Supergroup/channel title', 'method_channels.createChannel_param_about_type_string' => 'About text', 'method_channels.editAbout' => 'Edit the about text of a channel/supergroup', 'method_channels.editAbout_param_channel_type_InputChannel' => 'The channel', 'method_channels.editAbout_param_about_type_string' => 'The new about text', 'method_channels.editAdmin' => 'Edit admin permissions of a user in a channel/supergroup', 'method_channels.editAdmin_param_channel_type_InputChannel' => 'The channel', 'method_channels.editAdmin_param_user_id_type_InputUser' => 'The user', 'method_channels.editAdmin_param_admin_rights_type_ChannelAdminRights' => 'The new admin rights', 'method_channels.editTitle' => 'Edit the title of a supergroup/channel', 'method_channels.editTitle_param_channel_type_InputChannel' => 'The channel', 'method_channels.editTitle_param_title_type_string' => 'The new channel/supergroup title', 'method_channels.editPhoto' => 'Edit the photo of a supergroup/channel', 'method_channels.editPhoto_param_channel_type_InputChannel' => 'The channel', 'method_channels.editPhoto_param_photo_type_InputChatPhoto' => 'The new photo', 'method_channels.checkUsername' => 'Check if this username is free and can be assigned to a channel/supergroup', 'method_channels.checkUsername_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.checkUsername_param_username_type_string' => 'The new username for this channel/supergroup', 'method_channels.updateUsername' => 'Update the username of a supergroup/channel', 'method_channels.updateUsername_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.updateUsername_param_username_type_string' => 'The new username', 'method_channels.joinChannel' => 'Join a channel/supergroup', 'method_channels.joinChannel_param_channel_type_InputChannel' => 'The channel/supergroup to join', 'method_channels.leaveChannel' => 'Leave a channel/supergroup', 'method_channels.leaveChannel_param_channel_type_InputChannel' => 'The channel/supergroup to leave', 'method_channels.inviteToChannel' => 'Add users to channel/supergroup', 'method_channels.inviteToChannel_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.inviteToChannel_param_users_type_Vector t' => 'The users to add', 'method_channels.exportInvite' => 'Export the invite link of a channel', 'method_channels.exportInvite_param_channel_type_InputChannel' => 'The channel', 'method_channels.deleteChannel' => 'Delete a channel/supergroup', 'method_channels.deleteChannel_param_channel_type_InputChannel' => 'The channel/supergroup to delete', 'method_channels.toggleInvites' => 'Allow or disallow any user to invite users to this channel/supergroup', 'method_channels.toggleInvites_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.toggleInvites_param_enabled_type_Bool' => 'Allow or disallow', 'method_channels.exportMessageLink' => 'Get the link of a message in a channel', 'method_channels.exportMessageLink_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.exportMessageLink_param_id_type_int' => 'The ID of the message', 'method_channels.exportMessageLink_param_grouped_type_Bool' => 'Is this an album?', 'method_channels.toggleSignatures' => 'Toggle channel signatures', 'method_channels.toggleSignatures_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.toggleSignatures_param_enabled_type_Bool' => 'Enable or disable channel signatures?', 'method_channels.updatePinnedMessage' => 'Set the pinned message of a channel/supergroup', 'method_channels.updatePinnedMessage_param_silent_type_true' => 'Pin silently', 'method_channels.updatePinnedMessage_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.updatePinnedMessage_param_id_type_int' => 'The ID of the message to pin', 'method_channels.getAdminedPublicChannels' => 'Get all supergroups/channels where you\'re admin', 'method_channels.editBanned' => 'Kick or ban a user from a channel/supergroup', 'method_channels.editBanned_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.editBanned_param_user_id_type_InputUser' => 'The user to kick/ban', 'method_channels.editBanned_param_banned_rights_type_ChannelBannedRights' => 'Banned/kicked permissions', 'method_channels.getAdminLog' => 'Get admin log of a channel/supergroup', 'method_channels.getAdminLog_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.getAdminLog_param_q_type_string' => 'Search query', 'method_channels.getAdminLog_param_events_filter_type_ChannelAdminLogEventsFilter' => 'Event filter', 'method_channels.getAdminLog_param_admins_type_Vector t' => 'Fetch only actions from these admins', 'method_channels.getAdminLog_param_max_id_type_long' => 'Maximum message ID to fetch', 'method_channels.getAdminLog_param_min_id_type_long' => 'Minimum message ID to fetch', 'method_channels.getAdminLog_param_limit_type_int' => 'Number of results to fetch', 'method_channels.setStickers' => 'Set the supergroup/channel stickerpack', 'method_channels.setStickers_param_channel_type_InputChannel' => 'The channel/supergoup', 'method_channels.setStickers_param_stickerset_type_InputStickerSet' => 'The stickerset', 'method_channels.readMessageContents' => 'Mark channel/supergroup messages as read', 'method_channels.readMessageContents_param_channel_type_InputChannel' => 'The channel', 'method_channels.readMessageContents_param_id_type_Vector t' => 'List of message IDs', 'method_channels.deleteHistory' => 'Delete the history of a supergroup/channel', 'method_channels.deleteHistory_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.deleteHistory_param_max_id_type_int' => 'Maximum message ID to delete', 'method_channels.togglePreHistoryHidden' => 'Enable or disable hidden history for new channel/supergroup users', 'method_channels.togglePreHistoryHidden_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.togglePreHistoryHidden_param_enabled_type_Bool' => 'Enable or disable hidden history for new channel/supergroup users', 'method_bots.sendCustomRequest' => 'Send a custom request to the bot API', 'method_bots.sendCustomRequest_param_custom_method_type_string' => 'The method to call', 'method_bots.sendCustomRequest_param_params_type_DataJSON' => 'Method parameters', 'method_bots.answerWebhookJSONQuery' => 'Send webhook request via bot API', 'method_bots.answerWebhookJSONQuery_param_query_id_type_long' => 'The query ID', 'method_bots.answerWebhookJSONQuery_param_data_type_DataJSON' => 'The parameters', 'method_payments.getPaymentForm' => 'Get payment form', 'method_payments.getPaymentForm_param_msg_id_type_int' => 'Message ID', 'method_payments.getPaymentReceipt' => 'Get payment receipt', 'method_payments.getPaymentReceipt_param_msg_id_type_int' => 'The message ID', 'method_payments.validateRequestedInfo' => 'Validate requested payment info', 'method_payments.validateRequestedInfo_param_save_type_true' => 'Save payment info?', 'method_payments.validateRequestedInfo_param_msg_id_type_int' => 'The message ID', 'method_payments.validateRequestedInfo_param_info_type_PaymentRequestedInfo' => 'The requested payment info', 'method_payments.sendPaymentForm' => 'Bots only: send payment form', 'method_payments.sendPaymentForm_param_msg_id_type_int' => 'Message ID', 'method_payments.sendPaymentForm_param_requested_info_id_type_string' => 'ID of requested info', 'method_payments.sendPaymentForm_param_shipping_option_id_type_string' => 'Shipping option ID', 'method_payments.sendPaymentForm_param_credentials_type_InputPaymentCredentials' => 'Payment credentials', 'method_payments.getSavedInfo' => 'Get saved payments info', 'method_payments.clearSavedInfo' => 'Clear saved payments info', 'method_payments.clearSavedInfo_param_credentials_type_true' => 'Clear credentials?', 'method_payments.clearSavedInfo_param_info_type_true' => 'Clear payment info?', 'method_stickers.createStickerSet' => 'Create stickerset', 'method_stickers.createStickerSet_param_masks_type_true' => 'Masks?', 'method_stickers.createStickerSet_param_user_id_type_InputUser' => 'The user ID associated to this stickerset', 'method_stickers.createStickerSet_param_title_type_string' => 'The stickerset title', 'method_stickers.createStickerSet_param_short_name_type_string' => 'The stickerset short name', 'method_stickers.createStickerSet_param_stickers_type_Vector t' => 'The stickers to add', 'method_stickers.removeStickerFromSet' => 'Remove sticker from stickerset', 'method_stickers.removeStickerFromSet_param_sticker_type_InputDocument' => 'The sticker to remove', 'method_stickers.changeStickerPosition' => 'Change sticker position in photo', 'method_stickers.changeStickerPosition_param_sticker_type_InputDocument' => 'The sticker', 'method_stickers.changeStickerPosition_param_position_type_int' => 'New position', 'method_stickers.addStickerToSet' => 'Add sticker to stickerset', 'method_stickers.addStickerToSet_param_stickerset_type_InputStickerSet' => 'The stickerset', 'method_stickers.addStickerToSet_param_sticker_type_InputStickerSetItem' => 'The sticker', 'method_phone.getCallConfig' => 'Get call configuration', 'method_phone.requestCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.requestCall_param_user_id_type_InputUser' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.requestCall_param_g_a_hash_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.requestCall_param_protocol_type_PhoneCallProtocol' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_peer_type_InputPhoneCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_g_b_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_protocol_type_PhoneCallProtocol' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_peer_type_InputPhoneCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_g_a_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_key_fingerprint_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_protocol_type_PhoneCallProtocol' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.receivedCall' => 'Notify server that you received a call (server will refuse all incoming calls until the current call is over)', 'method_phone.receivedCall_param_peer_type_InputPhoneCall' => 'The phone call you received', 'method_phone.discardCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_peer_type_InputPhoneCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_duration_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_reason_type_PhoneCallDiscardReason' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_connection_id_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.setCallRating' => 'Set phone call rating', 'method_phone.setCallRating_param_peer_type_InputPhoneCall' => 'The phone call', 'method_phone.setCallRating_param_rating_type_int' => 'Rating (1-5 stars)', 'method_phone.setCallRating_param_comment_type_string' => 'An optional comment', 'method_phone.saveCallDebug' => 'Save call debugging info', 'method_phone.saveCallDebug_param_peer_type_InputPhoneCall' => 'The call', 'method_phone.saveCallDebug_param_debug_type_DataJSON' => 'Debugging info', 'method_langpack.getLangPack' => 'Get language pack', 'method_langpack.getLangPack_param_lang_code_type_string' => 'Language code', 'method_langpack.getStrings' => 'Get language pack strings', 'method_langpack.getStrings_param_lang_code_type_string' => 'Language code', 'method_langpack.getStrings_param_keys_type_Vector t' => 'Keys', 'method_langpack.getDifference' => 'Get language pack updates', 'method_langpack.getDifference_param_from_version_type_int' => 'Previous version', 'method_langpack.getLanguages' => 'Get available languages', 'method_auth.sendCode_param_sms_type_type_int' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.sendCode_param_lang_code_type_string' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.sendCall' => 'Send verification phone call', 'method_auth.sendCall_param_phone_number_type_string' => 'The phone number', 'method_auth.sendCall_param_phone_code_hash_type_string' => 'The phone code hash', 'method_account.registerDevice_param_device_model_type_string' => 'Device model', 'method_account.registerDevice_param_system_version_type_string' => 'System version', 'method_account.registerDevice_param_app_version_type_string' => 'App version', 'method_account.registerDevice_param_lang_code_type_string' => 'Language code', 'method_contacts.getContacts_param_hash_type_string' => 'List of contact user IDs you already cached', 'method_contacts.importContacts_param_replace_type_Bool' => 'Replace contacts?', 'method_contacts.getSuggested' => 'Get suggested contacts', 'method_contacts.getSuggested_param_limit_type_int' => 'Number of results to return', 'method_messages.getDialogs_param_offset_type_int' => 'Offset', 'method_messages.getDialogs_param_max_id_type_int' => 'Maximum ID of result to return', 'method_messages.getHistory_param_offset_type_int' => 'Message ID offset', 'method_messages.search_param_offset_type_int' => 'Offset ', 'method_messages.readHistory_param_offset_type_int' => 'Offset', 'method_messages.readHistory_param_read_contents_type_Bool' => 'Mark messages as read?', 'method_messages.deleteHistory_param_offset_type_int' => 'Offset', 'method_messages.forwardMessages_param_peer_type_InputPeer' => 'Peer', 'method_photos.updateProfilePhoto_param_crop_type_InputPhotoCrop' => 'Cropping info', 'method_photos.uploadProfilePhoto_param_caption_type_string' => 'Caption type', 'method_photos.uploadProfilePhoto_param_geo_point_type_InputGeoPoint' => 'Location', 'method_photos.uploadProfilePhoto_param_crop_type_InputPhotoCrop' => 'Cropping info', 'method_help.getAppUpdate_param_device_model_type_string' => 'Device model', 'method_help.getAppUpdate_param_system_version_type_string' => 'System version', 'method_help.getAppUpdate_param_app_version_type_string' => 'App version', 'method_help.getAppUpdate_param_lang_code_type_string' => 'Langauge code', 'method_help.getInviteText_param_lang_code_type_string' => 'Language', 'method_photos.getUserPhotos_param_max_id_type_int' => 'Maximum ID of photo to return', 'method_messages.forwardMessage' => 'Forward message', 'method_messages.forwardMessage_param_peer_type_InputPeer' => 'From where to forward the message', 'method_messages.forwardMessage_param_id_type_int' => 'The message ID', 'method_messages.sendBroadcast' => 'Send a message to all users in the chat list', 'method_messages.sendBroadcast_param_contacts_type_Vector t' => 'The users to which send the message', 'method_messages.sendBroadcast_param_message_type_string' => 'The message', 'method_messages.sendBroadcast_param_media_type_InputMedia' => 'The media', 'method_auth.sendSms' => 'Send SMS verification code', 'method_auth.sendSms_param_phone_number_type_string' => 'Phone number', 'method_auth.sendSms_param_phone_code_hash_type_string' => 'Phone code ash', 'method_invokeWithLayer18' => 'Invoke this method with layer 18', 'method_invokeWithLayer18_param_query_type_!X' => 'The method call', 'method_messages.getAllStickers_param_hash_type_string' => 'Previously fetched stickers', 'method_geochats.getLocated' => 'Get nearby geochats', 'method_geochats.getLocated_param_geo_point_type_InputGeoPoint' => 'Current location', 'method_geochats.getLocated_param_radius_type_int' => 'Radius', 'method_geochats.getLocated_param_limit_type_int' => 'Number of results to return', 'method_geochats.getRecents' => 'Get recent geochats', 'method_geochats.getRecents_param_offset_type_int' => 'Offset', 'method_geochats.getRecents_param_limit_type_int' => 'Number of results to return', 'method_geochats.checkin' => 'Join a geochat', 'method_geochats.checkin_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.getFullChat' => 'Get full info about a geochat', 'method_geochats.getFullChat_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.editChatTitle' => 'Edit geochat title', 'method_geochats.editChatTitle_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.editChatTitle_param_title_type_string' => 'The new title', 'method_geochats.editChatTitle_param_address_type_string' => 'The new address', 'method_geochats.editChatPhoto' => 'Edit geochat photo', 'method_geochats.editChatPhoto_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.editChatPhoto_param_photo_type_InputChatPhoto' => 'The new photo', 'method_geochats.search' => 'Search messages in geocha', 'method_geochats.search_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.search_param_q_type_string' => 'The search query', 'method_geochats.search_param_filter_type_MessagesFilter' => 'Search filter', 'method_geochats.search_param_min_date_type_int' => 'Minumum date', 'method_geochats.search_param_max_date_type_int' => 'Maximum date', 'method_geochats.search_param_offset_type_int' => 'Offset', 'method_geochats.search_param_max_id_type_int' => 'Maximum message ID', 'method_geochats.search_param_limit_type_int' => 'Number of results to return', 'method_geochats.getHistory' => 'Get geochat history', 'method_geochats.getHistory_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.getHistory_param_offset_type_int' => 'Offset', 'method_geochats.getHistory_param_max_id_type_int' => 'Maximum message ID', 'method_geochats.getHistory_param_limit_type_int' => 'Number of results to return', 'method_geochats.setTyping' => 'Send typing notification to geochat', 'method_geochats.setTyping_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.setTyping_param_typing_type_Bool' => 'Typing or not typing', 'method_geochats.sendMessage' => 'Send message to geochat', 'method_geochats.sendMessage_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.sendMessage_param_message_type_string' => 'The message', 'method_geochats.sendMedia' => 'Send media to geochat', 'method_geochats.sendMedia_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.sendMedia_param_media_type_InputMedia' => 'The media', 'method_geochats.createGeoChat' => 'Create geochat', 'method_geochats.createGeoChat_param_title_type_string' => 'Geochat title', 'method_geochats.createGeoChat_param_geo_point_type_InputGeoPoint' => 'Geochat location', 'method_geochats.createGeoChat_param_address_type_string' => 'Geochat address', 'method_geochats.createGeoChat_param_venue_type_string' => 'Geochat venue ', 'method_account.setPassword' => 'Set 2FA password', 'method_account.setPassword_param_current_password_hash_type_bytes' => 'Use only if you have set a 2FA password: `$current_salt = $MadelineProto->account->getPassword()[\'current_salt\']; $current_password_hash = hash(\'sha256\', $current_salt.$password.$current_salt, true);`', 'method_account.setPassword_param_new_salt_type_bytes' => 'New salt', 'method_account.setPassword_param_new_password_hash_type_bytes' => '`hash(\'sha256\', $new_salt.$new_password.$new_salt, true)`', 'method_account.setPassword_param_hint_type_string' => 'Hint', 'method_messages.installStickerSet_param_disabled_type_Bool' => 'Disable stickerset?', 'method_messages.startBot_param_chat_id_type_InputPeer' => 'Chat ID', 'method_help.getAppChangelog_param_device_model_type_string' => 'Device model', 'method_help.getAppChangelog_param_system_version_type_string' => 'System version', 'method_help.getAppChangelog_param_app_version_type_string' => 'App version', 'method_help.getAppChangelog_param_lang_code_type_string' => 'Language code', 'method_channels.getDialogs' => 'Get channel dialogs', 'method_channels.getDialogs_param_offset_type_int' => 'Offset', 'method_channels.getDialogs_param_limit_type_int' => 'Number of results to return', 'method_channels.getImportantHistory' => 'Get important channel/supergroup history', 'method_channels.getImportantHistory_param_channel_type_InputChannel' => 'The supergroup/channel', 'method_channels.getImportantHistory_param_offset_id_type_int' => 'Message ID offset', 'method_channels.getImportantHistory_param_add_offset_type_int' => 'Additional offset', 'method_channels.getImportantHistory_param_limit_type_int' => 'Number of results to return', 'method_channels.getImportantHistory_param_max_id_type_int' => 'Maximum message ID', 'method_channels.getImportantHistory_param_min_id_type_int' => 'Minumum message ID', 'method_channels.createChannel_param_users_type_Vector t' => 'Users to add to channel', 'method_channels.editAdmin_param_role_type_ChannelParticipantRole' => 'User role', 'method_channels.toggleComments' => 'Enable channel comments', 'method_channels.toggleComments_param_channel_type_InputChannel' => 'The channel ', 'method_channels.toggleComments_param_enabled_type_Bool' => 'Enable or disable comments', 'method_channels.kickFromChannel' => 'Kick user from channel', 'method_channels.kickFromChannel_param_channel_type_InputChannel' => 'The channel', 'method_channels.kickFromChannel_param_user_id_type_InputUser' => 'The user to kick', 'method_channels.kickFromChannel_param_kicked_type_Bool' => 'Kick or unkick?', 'method_messages.getChannelDialogs' => 'Get channel/supergruop dialogs', 'method_messages.getChannelDialogs_param_offset_type_int' => 'Offset', 'method_messages.getChannelDialogs_param_limit_type_int' => 'Number of results to return', 'method_messages.getImportantHistory' => 'Get important message history', 'method_messages.getImportantHistory_param_peer_type_InputPeer' => 'Peer', 'method_messages.getImportantHistory_param_max_id_type_int' => 'Maximum message ID to fetch', 'method_messages.getImportantHistory_param_min_id_type_int' => 'Minumum message ID to fetch', 'method_messages.getImportantHistory_param_limit_type_int' => 'Number of results to fetch', 'method_messages.readChannelHistory' => 'Mark channel/supergroup history as read', 'method_messages.readChannelHistory_param_peer_type_InputPeer' => 'The channel/supergruop', 'method_messages.readChannelHistory_param_max_id_type_int' => 'Maximum message ID to mark as read', 'method_messages.createChannel' => 'Create channel', 'method_messages.createChannel_param_title_type_string' => 'Channel/supergroup title', 'method_messages.deleteChannelMessages' => 'Delete channel messages', 'method_messages.deleteChannelMessages_param_peer_type_InputPeer' => 'The channel/supergroup', 'method_messages.deleteChannelMessages_param_id_type_Vector t' => 'The IDs of messages to delete', 'method_updates.getChannelDifference_param_peer_type_InputPeer' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_messages.search_param_important_only_type_true' => 'Show only important messages', 'method_messages.sendMessage_param_broadcast_type_true' => 'Broadcast this message', 'method_messages.sendMedia_param_broadcast_type_true' => 'Broadcast this message', 'method_messages.forwardMessages_param_broadcast_type_true' => 'Broadcast this message', 'method_messages.deactivateChat' => 'Deactivate chat', 'method_messages.deactivateChat_param_chat_id_type_InputPeer' => 'The chat to deactivate', 'method_messages.deactivateChat_param_enabled_type_Bool' => 'Activate or deactivate?', 'method_help.getTermsOfService_param_lang_code_type_string' => 'Language code', 'method_messages.sendInlineBotResult_param_broadcast_type_true' => 'Broadcast this message?', 'method_channels.getImportantHistory_param_offset_date_type_int' => 'Date offset', 'method_messages.getUnusedStickers' => 'Get unused stickers', 'method_messages.getUnusedStickers_param_limit_type_int' => 'Number of results to return', 'method_destroy_auth_key' => 'Destroy current authorization key', 'method_phone.requestCall_param_g_a_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_key_fingerprint_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_req_DH_params_param_p_type_string' => 'Factorized p from pq', 'method_req_DH_params_param_q_type_string' => 'Factorized q from pq', 'method_req_DH_params_param_encrypted_data_type_string' => 'Encrypted message', 'method_set_client_DH_params_param_encrypted_data_type_string' => 'Encrypted message', 'method_contest.saveDeveloperInfo' => 'Save developer info for telegram contest', 'method_contest.saveDeveloperInfo_param_vk_id_type_int' => 'VK user ID', 'method_contest.saveDeveloperInfo_param_name_type_string' => 'Name', 'method_contest.saveDeveloperInfo_param_phone_number_type_string' => 'Phone number', 'method_contest.saveDeveloperInfo_param_age_type_int' => 'Age', 'method_contest.saveDeveloperInfo_param_city_type_string' => 'City', 'method_auth.importBotAuthorization_param_a_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_b_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_c_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_d_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'object_vector' => 'Array', 'object_resPQ' => 'Contains pq to factorize', 'object_resPQ_param_nonce_type_int128' => 'Nonce', 'object_resPQ_param_server_nonce_type_int128' => 'Server nonce', 'object_resPQ_param_pq_type_bytes' => 'PQ ', 'object_resPQ_param_server_public_key_fingerprints_type_Vector t' => 'RSA key fingerprints', 'object_p_q_inner_data' => 'PQ inner data', 'object_p_q_inner_data_param_pq_type_bytes' => 'PQ', 'object_p_q_inner_data_param_p_type_bytes' => 'P', 'object_p_q_inner_data_param_q_type_bytes' => 'Q', 'object_p_q_inner_data_param_nonce_type_int128' => 'Nonce', 'object_p_q_inner_data_param_server_nonce_type_int128' => 'Nonce', 'object_p_q_inner_data_param_new_nonce_type_int256' => 'Nonce', 'object_p_q_inner_data_temp' => 'Inner data temp', 'object_p_q_inner_data_temp_param_pq_type_bytes' => 'Pq', 'object_p_q_inner_data_temp_param_p_type_bytes' => 'P', 'object_p_q_inner_data_temp_param_q_type_bytes' => 'Q', 'object_p_q_inner_data_temp_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_p_q_inner_data_temp_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_p_q_inner_data_temp_param_new_nonce_type_int256' => 'New nonce', 'object_p_q_inner_data_temp_param_expires_in_type_int' => 'Expires in', 'object_server_DH_params_fail' => 'Server params fail', 'object_server_DH_params_fail_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_server_DH_params_fail_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_server_DH_params_fail_param_new_nonce_hash_type_int128' => 'New nonce hash', 'object_server_DH_params_ok' => 'Server params ok', 'object_server_DH_params_ok_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_server_DH_params_ok_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_server_DH_params_ok_param_encrypted_answer_type_bytes' => 'Encrypted answer', 'object_server_DH_inner_data' => 'Server inner data', 'object_server_DH_inner_data_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_server_DH_inner_data_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_server_DH_inner_data_param_g_type_int' => 'G', 'object_server_DH_inner_data_param_dh_prime_type_bytes' => 'Dh prime', 'object_server_DH_inner_data_param_g_a_type_bytes' => 'G a', 'object_server_DH_inner_data_param_server_time_type_int' => 'Server time', 'object_client_DH_inner_data' => 'Client inner data', 'object_client_DH_inner_data_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_client_DH_inner_data_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_client_DH_inner_data_param_retry_id_type_long' => 'Retry ID', 'object_client_DH_inner_data_param_g_b_type_bytes' => 'G b', 'object_dh_gen_ok' => 'Dh gen ok', 'object_dh_gen_ok_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_dh_gen_ok_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_dh_gen_ok_param_new_nonce_hash1_type_int128' => 'New nonce hash1', 'object_dh_gen_retry' => 'Dh gen retry', 'object_dh_gen_retry_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_dh_gen_retry_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_dh_gen_retry_param_new_nonce_hash2_type_int128' => 'New nonce hash2', 'object_dh_gen_fail' => 'Dh gen fail', 'object_dh_gen_fail_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_dh_gen_fail_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_dh_gen_fail_param_new_nonce_hash3_type_int128' => 'New nonce hash3', 'object_rpc_result' => 'Rpc result', 'object_rpc_result_param_req_msg_id_type_long' => 'Req msg ID', 'object_rpc_result_param_result_type_Object' => 'Result', 'object_rpc_error' => 'Rpc error', 'object_rpc_error_param_error_code_type_int' => 'Error code', 'object_rpc_error_param_error_message_type_string' => 'Error message', 'object_rpc_answer_unknown' => 'Rpc answer unknown', 'object_rpc_answer_dropped_running' => 'Rpc answer dropped running', 'object_rpc_answer_dropped' => 'Rpc answer dropped', 'object_rpc_answer_dropped_param_msg_id_type_long' => 'Msg ID', 'object_rpc_answer_dropped_param_seq_no_type_int' => 'Seq no', 'object_rpc_answer_dropped_param_bytes_type_int' => 'Bytes', 'object_future_salt' => 'Future salt', 'object_future_salt_param_valid_since_type_int' => 'Valid since', 'object_future_salt_param_valid_until_type_int' => 'Valid until', 'object_future_salt_param_salt_type_long' => 'Salt', 'object_future_salts' => 'Future salts', 'object_future_salts_param_req_msg_id_type_long' => 'Req msg ID', 'object_future_salts_param_now_type_int' => 'Now', 'object_future_salts_param_salts_type_vector' => 'Salts', 'object_pong' => 'Pong', 'object_pong_param_msg_id_type_long' => 'Msg ID', 'object_pong_param_ping_id_type_long' => 'Ping ID', 'object_destroy_session_ok' => 'Destroy session ok', 'object_destroy_session_ok_param_session_id_type_long' => 'Session ID', 'object_destroy_session_none' => 'Destroy session none', 'object_destroy_session_none_param_session_id_type_long' => 'Session ID', 'object_new_session_created' => 'New session created', 'object_new_session_created_param_first_msg_id_type_long' => 'First msg ID', 'object_new_session_created_param_unique_id_type_long' => 'Unique ID', 'object_new_session_created_param_server_salt_type_long' => 'Server salt', 'object_msg_container' => 'Msg container', 'object_msg_container_param_messages_type_vector' => 'Messages', 'object_MTmessage' => 'MTProto message', 'object_MTmessage_param_msg_id_type_long' => 'Message ID', 'object_MTmessage_param_seqno_type_int' => 'Seqno', 'object_MTmessage_param_bytes_type_int' => 'Message body', 'object_MTmessage_param_body_type_Object' => 'Message body', 'object_msg_copy' => 'Msg copy', 'object_msg_copy_param_orig_message_type_MTMessage' => 'Orig message', 'object_gzip_packed' => 'Gzip packed', 'object_gzip_packed_param_packed_data_type_bytes' => 'Packed data', 'object_msgs_ack' => 'Msgs ack', 'object_msgs_ack_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_bad_msg_notification' => 'Bad msg notification', 'object_bad_msg_notification_param_bad_msg_id_type_long' => 'Bad msg ID', 'object_bad_msg_notification_param_bad_msg_seqno_type_int' => 'Bad msg seqno', 'object_bad_msg_notification_param_error_code_type_int' => 'Error code', 'object_bad_server_salt' => 'Bad server salt', 'object_bad_server_salt_param_bad_msg_id_type_long' => 'Bad msg ID', 'object_bad_server_salt_param_bad_msg_seqno_type_int' => 'Bad msg seqno', 'object_bad_server_salt_param_error_code_type_int' => 'Error code', 'object_bad_server_salt_param_new_server_salt_type_long' => 'New server salt', 'object_msg_resend_req' => 'Msg resend req', 'object_msg_resend_req_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_msgs_state_req' => 'Msgs state req', 'object_msgs_state_req_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_msgs_state_info' => 'Msgs state info', 'object_msgs_state_info_param_req_msg_id_type_long' => 'Req msg ID', 'object_msgs_state_info_param_info_type_bytes' => 'Info', 'object_msgs_all_info' => 'Msgs all info', 'object_msgs_all_info_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_msgs_all_info_param_info_type_bytes' => 'Info', 'object_msg_detailed_info' => 'Msg detailed info', 'object_msg_detailed_info_param_msg_id_type_long' => 'Msg ID', 'object_msg_detailed_info_param_answer_msg_id_type_long' => 'Answer msg ID', 'object_msg_detailed_info_param_bytes_type_int' => 'Bytes', 'object_msg_detailed_info_param_status_type_int' => 'Status', 'object_msg_new_detailed_info' => 'Msg new detailed info', 'object_msg_new_detailed_info_param_answer_msg_id_type_long' => 'Answer msg ID', 'object_msg_new_detailed_info_param_bytes_type_int' => 'Bytes', 'object_msg_new_detailed_info_param_status_type_int' => 'Status', 'object_bind_auth_key_inner' => 'Bind auth key inner', 'object_bind_auth_key_inner_param_nonce_type_long' => 'Nonce', 'object_bind_auth_key_inner_param_temp_auth_key_id_type_long' => 'Temp auth key ID', 'object_bind_auth_key_inner_param_perm_auth_key_id_type_long' => 'Perm auth key ID', 'object_bind_auth_key_inner_param_temp_session_id_type_long' => 'Temp session ID', 'object_bind_auth_key_inner_param_expires_at_type_int' => 'Expires at', 'object_boolFalse' => 'Bool false', 'object_boolTrue' => 'Bool true', 'object_true' => 'True', 'object_error' => 'Error', 'object_error_param_code_type_int' => 'Code', 'object_error_param_text_type_string' => 'Text', 'object_null' => 'Null', 'object_inputPeerEmpty' => 'Empty input peer', 'object_inputPeerSelf' => 'Peer self', 'object_inputPeerChat' => 'Peer chat', 'object_inputPeerChat_param_chat_id_type_int' => 'Chat ID', 'object_inputPeerUser' => 'Peer user', 'object_inputPeerUser_param_user_id_type_int' => 'User ID', 'object_inputPeerUser_param_access_hash_type_long' => 'Access hash', 'object_inputPeerChannel' => 'Peer channel', 'object_inputPeerChannel_param_channel_id_type_int' => 'Channel ID', 'object_inputPeerChannel_param_access_hash_type_long' => 'Access hash', 'object_inputUserEmpty' => 'Empty input user', 'object_inputUserSelf' => 'User self', 'object_inputUser' => 'User', 'object_inputUser_param_user_id_type_int' => 'User ID', 'object_inputUser_param_access_hash_type_long' => 'Access hash', 'object_inputPhoneContact' => 'Phone contact', 'object_inputPhoneContact_param_client_id_type_long' => 'Client ID', 'object_inputPhoneContact_param_phone_type_string' => 'Phone', 'object_inputPhoneContact_param_first_name_type_string' => 'First name', 'object_inputPhoneContact_param_last_name_type_string' => 'Last name', 'object_inputFile' => 'File', 'object_inputFile_param_id_type_long' => 'ID', 'object_inputFile_param_parts_type_int' => 'Parts', 'object_inputFile_param_name_type_string' => 'Name', 'object_inputFile_param_md5_checksum_type_string' => 'Md5 checksum', 'object_inputFileBig' => 'File big', 'object_inputFileBig_param_id_type_long' => 'ID', 'object_inputFileBig_param_parts_type_int' => 'Parts', 'object_inputFileBig_param_name_type_string' => 'Name', 'object_inputMediaEmpty' => 'Empty input media', 'object_inputMediaUploadedPhoto' => 'Media uploaded photo', 'object_inputMediaUploadedPhoto_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedPhoto_param_stickers_type_Vector t' => 'Stickers', 'object_inputMediaUploadedPhoto_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaPhoto' => 'Media photo', 'object_inputMediaPhoto_param_id_type_InputPhoto' => 'ID', 'object_inputMediaPhoto_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaGeoPoint' => 'Media geo point', 'object_inputMediaGeoPoint_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputMediaContact' => 'Media contact', 'object_inputMediaContact_param_phone_number_type_string' => 'Phone number', 'object_inputMediaContact_param_first_name_type_string' => 'First name', 'object_inputMediaContact_param_last_name_type_string' => 'Last name', 'object_inputMediaUploadedDocument' => 'Media uploaded document', 'object_inputMediaUploadedDocument_param_nosound_video_type_true' => 'Nosound video?', 'object_inputMediaUploadedDocument_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedDocument_param_thumb_type_InputFile' => 'Thumbnail', 'object_inputMediaUploadedDocument_param_mime_type_type_string' => 'Mime type', 'object_inputMediaUploadedDocument_param_attributes_type_Vector t' => 'Attributes', 'object_inputMediaUploadedDocument_param_stickers_type_Vector t' => 'Stickers', 'object_inputMediaUploadedDocument_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaDocument' => 'Media document', 'object_inputMediaDocument_param_id_type_InputDocument' => 'ID', 'object_inputMediaDocument_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaVenue' => 'Media venue', 'object_inputMediaVenue_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputMediaVenue_param_title_type_string' => 'Title', 'object_inputMediaVenue_param_address_type_string' => 'Address', 'object_inputMediaVenue_param_provider_type_string' => 'Provider', 'object_inputMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_inputMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_inputMediaGifExternal' => 'Media gif external', 'object_inputMediaGifExternal_param_url_type_string' => 'URL', 'object_inputMediaGifExternal_param_q_type_string' => 'Q', 'object_inputMediaPhotoExternal' => 'Media photo external', 'object_inputMediaPhotoExternal_param_url_type_string' => 'URL', 'object_inputMediaPhotoExternal_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaDocumentExternal' => 'Media document external', 'object_inputMediaDocumentExternal_param_url_type_string' => 'URL', 'object_inputMediaDocumentExternal_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaGame' => 'Media game', 'object_inputMediaGame_param_id_type_InputGame' => 'ID', 'object_inputMediaInvoice' => 'Media invoice', 'object_inputMediaInvoice_param_title_type_string' => 'Title', 'object_inputMediaInvoice_param_description_type_string' => 'Description', 'object_inputMediaInvoice_param_photo_type_InputWebDocument' => 'Photo', 'object_inputMediaInvoice_param_invoice_type_Invoice' => 'Invoice', 'object_inputMediaInvoice_param_payload_type_bytes' => 'Payload', 'object_inputMediaInvoice_param_provider_type_string' => 'Provider', 'object_inputMediaInvoice_param_provider_data_type_DataJSON' => 'Provider data', 'object_inputMediaInvoice_param_start_param_type_string' => 'Start param', 'object_inputMediaGeoLive' => 'Media geo live', 'object_inputMediaGeoLive_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputMediaGeoLive_param_period_type_int' => 'Period', 'object_inputChatPhotoEmpty' => 'Empty input chat photo', 'object_inputChatUploadedPhoto' => 'Chat uploaded photo', 'object_inputChatUploadedPhoto_param_file_type_InputFile' => 'File', 'object_inputChatPhoto' => 'Chat photo', 'object_inputChatPhoto_param_id_type_InputPhoto' => 'ID', 'object_inputGeoPointEmpty' => 'Empty input geo point', 'object_inputGeoPoint' => 'Geo point', 'object_inputGeoPoint_param_lat_type_double' => 'Lat', 'object_inputGeoPoint_param_long_type_double' => 'Long', 'object_inputPhotoEmpty' => 'Empty input photo', 'object_inputPhoto' => 'Photo', 'object_inputPhoto_param_id_type_long' => 'ID', 'object_inputPhoto_param_access_hash_type_long' => 'Access hash', 'object_inputFileLocation' => 'File location', 'object_inputFileLocation_param_volume_id_type_long' => 'Volume ID', 'object_inputFileLocation_param_local_id_type_int' => 'Local ID', 'object_inputFileLocation_param_secret_type_long' => 'Secret', 'object_inputEncryptedFileLocation' => 'Encrypted file location', 'object_inputEncryptedFileLocation_param_id_type_long' => 'ID', 'object_inputEncryptedFileLocation_param_access_hash_type_long' => 'Access hash', 'object_inputDocumentFileLocation' => 'Document file location', 'object_inputDocumentFileLocation_param_id_type_long' => 'ID', 'object_inputDocumentFileLocation_param_access_hash_type_long' => 'Access hash', 'object_inputDocumentFileLocation_param_version_type_int' => 'Version', 'object_inputAppEvent' => 'App event', 'object_inputAppEvent_param_time_type_double' => 'Time', 'object_inputAppEvent_param_type_type_string' => 'Type', 'object_inputAppEvent_param_peer_type_long' => 'Peer', 'object_inputAppEvent_param_data_type_string' => 'Data', 'object_peerUser' => 'Peer user', 'object_peerUser_param_user_id_type_int' => 'User ID', 'object_peerChat' => 'Peer chat', 'object_peerChat_param_chat_id_type_int' => 'Chat ID', 'object_peerChannel' => 'Peer channel', 'object_peerChannel_param_channel_id_type_int' => 'Channel ID', 'object_storage.fileUnknown' => 'File unknown', 'object_storage.filePartial' => 'File partial', 'object_storage.fileJpeg' => 'File jpeg', 'object_storage.fileGif' => 'File gif', 'object_storage.filePng' => 'File png', 'object_storage.filePdf' => 'File pdf', 'object_storage.fileMp3' => 'File mp3', 'object_storage.fileMov' => 'File mov', 'object_storage.fileMp4' => 'File mp4', 'object_storage.fileWebp' => 'File webp', 'object_fileLocationUnavailable' => 'File location unavailable', 'object_fileLocationUnavailable_param_volume_id_type_long' => 'Volume ID', 'object_fileLocationUnavailable_param_local_id_type_int' => 'Local ID', 'object_fileLocationUnavailable_param_secret_type_long' => 'Secret', 'object_fileLocation' => 'File location', 'object_fileLocation_param_dc_id_type_int' => 'DC ID', 'object_fileLocation_param_volume_id_type_long' => 'Volume ID', 'object_fileLocation_param_local_id_type_int' => 'Local ID', 'object_fileLocation_param_secret_type_long' => 'Secret', 'object_userEmpty' => 'Empty user', 'object_userEmpty_param_id_type_int' => 'ID', 'object_user' => 'User', 'object_user_param_self_type_true' => 'Self?', 'object_user_param_contact_type_true' => 'Contact?', 'object_user_param_mutual_contact_type_true' => 'Mutual contact?', 'object_user_param_deleted_type_true' => 'Deleted?', 'object_user_param_bot_type_true' => 'Bot?', 'object_user_param_bot_chat_history_type_true' => 'Bot chat history?', 'object_user_param_bot_nochats_type_true' => 'Bot nochats?', 'object_user_param_verified_type_true' => 'Verified?', 'object_user_param_restricted_type_true' => 'Restricted?', 'object_user_param_min_type_true' => 'Min?', 'object_user_param_bot_inline_geo_type_true' => 'Bot inline geo?', 'object_user_param_id_type_int' => 'ID', 'object_user_param_access_hash_type_long' => 'Access hash', 'object_user_param_first_name_type_string' => 'First name', 'object_user_param_last_name_type_string' => 'Last name', 'object_user_param_username_type_string' => 'Username', 'object_user_param_phone_type_string' => 'Phone', 'object_user_param_photo_type_UserProfilePhoto' => 'Photo', 'object_user_param_status_type_UserStatus' => 'Status', 'object_user_param_bot_info_version_type_int' => 'Bot info version', 'object_user_param_restriction_reason_type_string' => 'Restriction reason', 'object_user_param_bot_inline_placeholder_type_string' => 'Bot inline placeholder', 'object_user_param_lang_code_type_string' => 'Lang code', 'object_userProfilePhotoEmpty' => 'Empty user profile photo', 'object_userProfilePhoto' => 'User profile photo', 'object_userProfilePhoto_param_photo_id_type_long' => 'Photo ID', 'object_userProfilePhoto_param_photo_small_type_FileLocation' => 'Photo small', 'object_userProfilePhoto_param_photo_big_type_FileLocation' => 'Photo big', 'object_chatEmpty' => 'Empty chat', 'object_chatEmpty_param_id_type_int' => 'ID', 'object_chat' => 'Chat', 'object_chat_param_creator_type_true' => 'Creator?', 'object_chat_param_kicked_type_true' => 'Kicked?', 'object_chat_param_left_type_true' => 'Left?', 'object_chat_param_admins_enabled_type_true' => 'Admins enabled?', 'object_chat_param_admin_type_true' => 'Admin?', 'object_chat_param_deactivated_type_true' => 'Deactivated?', 'object_chat_param_id_type_int' => 'ID', 'object_chat_param_title_type_string' => 'Title', 'object_chat_param_photo_type_ChatPhoto' => 'Photo', 'object_chat_param_participants_count_type_int' => 'Participants count', 'object_chat_param_date_type_int' => 'Date', 'object_chat_param_version_type_int' => 'Version', 'object_chat_param_migrated_to_type_InputChannel' => 'Migrated to', 'object_chatForbidden' => 'Chat forbidden', 'object_chatForbidden_param_id_type_int' => 'ID', 'object_chatForbidden_param_title_type_string' => 'Title', 'object_channel' => 'Channel', 'object_channel_param_creator_type_true' => 'Creator?', 'object_channel_param_left_type_true' => 'Left?', 'object_channel_param_editor_type_true' => 'Editor?', 'object_channel_param_broadcast_type_true' => 'Broadcast?', 'object_channel_param_verified_type_true' => 'Verified?', 'object_channel_param_megagroup_type_true' => 'Megagroup?', 'object_channel_param_restricted_type_true' => 'Restricted?', 'object_channel_param_democracy_type_true' => 'Democracy?', 'object_channel_param_signatures_type_true' => 'Signatures?', 'object_channel_param_min_type_true' => 'Min?', 'object_channel_param_id_type_int' => 'ID', 'object_channel_param_access_hash_type_long' => 'Access hash', 'object_channel_param_title_type_string' => 'Title', 'object_channel_param_username_type_string' => 'Username', 'object_channel_param_photo_type_ChatPhoto' => 'Photo', 'object_channel_param_date_type_int' => 'Date', 'object_channel_param_version_type_int' => 'Version', 'object_channel_param_restriction_reason_type_string' => 'Restriction reason', 'object_channel_param_admin_rights_type_ChannelAdminRights' => 'Admin rights', 'object_channel_param_banned_rights_type_ChannelBannedRights' => 'Banned rights', 'object_channel_param_participants_count_type_int' => 'Participants count', 'object_channelForbidden' => 'Forbidden channel', 'object_channelForbidden_param_broadcast_type_true' => 'Broadcast?', 'object_channelForbidden_param_megagroup_type_true' => 'Megagroup?', 'object_channelForbidden_param_id_type_int' => 'ID', 'object_channelForbidden_param_access_hash_type_long' => 'Access hash', 'object_channelForbidden_param_title_type_string' => 'Title', 'object_channelForbidden_param_until_date_type_int' => 'Until date', 'object_chatFull' => 'Chat full', 'object_chatFull_param_id_type_int' => 'ID', 'object_chatFull_param_participants_type_ChatParticipants' => 'Participants', 'object_chatFull_param_chat_photo_type_Photo' => 'Chat photo', 'object_chatFull_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_chatFull_param_exported_invite_type_ExportedChatInvite' => 'Exported invite', 'object_chatFull_param_bot_info_type_Vector t' => 'Bot info', 'object_channelFull' => 'Full channel', 'object_channelFull_param_can_view_participants_type_true' => 'Can view participants?', 'object_channelFull_param_can_set_username_type_true' => 'Can set username?', 'object_channelFull_param_can_set_stickers_type_true' => 'Can set group stickerset?', 'object_channelFull_param_hidden_prehistory_type_true' => 'Hidden prehistory?', 'object_channelFull_param_id_type_int' => 'ID', 'object_channelFull_param_about_type_string' => 'About', 'object_channelFull_param_participants_count_type_int' => 'Participants count', 'object_channelFull_param_admins_count_type_int' => 'Admins count', 'object_channelFull_param_kicked_count_type_int' => 'Kicked count', 'object_channelFull_param_banned_count_type_int' => 'Banned count', 'object_channelFull_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_channelFull_param_read_outbox_max_id_type_int' => 'Read outbox max ID', 'object_channelFull_param_unread_count_type_int' => 'Unread count', 'object_channelFull_param_chat_photo_type_Photo' => 'Chat photo', 'object_channelFull_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_channelFull_param_exported_invite_type_ExportedChatInvite' => 'Exported invite', 'object_channelFull_param_bot_info_type_Vector t' => 'Bot info', 'object_channelFull_param_migrated_from_chat_id_type_int' => 'Migrated from chat ID', 'object_channelFull_param_migrated_from_max_id_type_int' => 'Migrated from max ID', 'object_channelFull_param_pinned_msg_id_type_int' => 'Pinned msg ID', 'object_channelFull_param_stickerset_type_StickerSet' => 'Stickerset', 'object_channelFull_param_available_min_id_type_int' => 'Available min ID', 'object_chatParticipant' => 'Chat participant', 'object_chatParticipant_param_user_id_type_int' => 'User ID', 'object_chatParticipant_param_inviter_id_type_int' => 'Inviter ID', 'object_chatParticipant_param_date_type_int' => 'Date', 'object_chatParticipantCreator' => 'Chat participant creator', 'object_chatParticipantCreator_param_user_id_type_int' => 'User ID', 'object_chatParticipantAdmin' => 'Chat participant admin', 'object_chatParticipantAdmin_param_user_id_type_int' => 'User ID', 'object_chatParticipantAdmin_param_inviter_id_type_int' => 'Inviter ID', 'object_chatParticipantAdmin_param_date_type_int' => 'Date', 'object_chatParticipantsForbidden' => 'Chat participants forbidden', 'object_chatParticipantsForbidden_param_chat_id_type_int' => 'Chat ID', 'object_chatParticipantsForbidden_param_self_participant_type_ChatParticipant' => 'Self participant', 'object_chatParticipants' => 'Chat participants', 'object_chatParticipants_param_chat_id_type_int' => 'Chat ID', 'object_chatParticipants_param_participants_type_Vector t' => 'Participants', 'object_chatParticipants_param_version_type_int' => 'Version', 'object_chatPhotoEmpty' => 'Empty chat photo', 'object_chatPhoto' => 'Chat photo', 'object_chatPhoto_param_photo_small_type_FileLocation' => 'Photo small', 'object_chatPhoto_param_photo_big_type_FileLocation' => 'Photo big', 'object_messageEmpty' => 'Empty message', 'object_messageEmpty_param_id_type_int' => 'ID', 'object_message' => 'Message', 'object_message_param_out_type_true' => 'Out?', 'object_message_param_mentioned_type_true' => 'Mentioned?', 'object_message_param_media_unread_type_true' => 'Media unread?', 'object_message_param_silent_type_true' => 'Silent?', 'object_message_param_post_type_true' => 'Post?', 'object_message_param_id_type_int' => 'ID', 'object_message_param_from_id_type_int' => 'From ID', 'object_message_param_to_id_type_Peer' => 'To ID', 'object_message_param_fwd_from_type_MessageFwdHeader' => 'Forwarded from', 'object_message_param_via_bot_id_type_int' => 'Via bot ID', 'object_message_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_message_param_date_type_int' => 'Date', 'object_message_param_message_type_string' => 'Message', 'object_message_param_media_type_MessageMedia' => 'Media', 'object_message_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_message_param_entities_type_Vector t' => 'Entities', 'object_message_param_views_type_int' => 'Views', 'object_message_param_edit_date_type_int' => 'Edit date', 'object_message_param_post_author_type_string' => 'Post author', 'object_message_param_grouped_id_type_long' => 'Grouped ID', 'object_messageService' => 'Message service', 'object_messageService_param_out_type_true' => 'Out?', 'object_messageService_param_mentioned_type_true' => 'Mentioned?', 'object_messageService_param_media_unread_type_true' => 'Media unread?', 'object_messageService_param_silent_type_true' => 'Silent?', 'object_messageService_param_post_type_true' => 'Post?', 'object_messageService_param_id_type_int' => 'ID', 'object_messageService_param_from_id_type_int' => 'From ID', 'object_messageService_param_to_id_type_Peer' => 'To ID', 'object_messageService_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_messageService_param_date_type_int' => 'Date', 'object_messageService_param_action_type_MessageAction' => 'Action', 'object_messageMediaEmpty' => 'Empty message media', 'object_messageMediaPhoto' => 'Message media photo', 'object_messageMediaPhoto_param_photo_type_Photo' => 'Photo', 'object_messageMediaPhoto_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_messageMediaGeo' => 'Message media geo', 'object_messageMediaGeo_param_geo_type_GeoPoint' => 'Geo', 'object_messageMediaContact' => 'Message media contact', 'object_messageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_messageMediaContact_param_first_name_type_string' => 'First name', 'object_messageMediaContact_param_last_name_type_string' => 'Last name', 'object_messageMediaContact_param_user_id_type_int' => 'User ID', 'object_messageMediaUnsupported' => 'Message media unsupported', 'object_messageMediaDocument' => 'Message media document', 'object_messageMediaDocument_param_document_type_Document' => 'Document', 'object_messageMediaDocument_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_messageMediaWebPage' => 'Message media web page', 'object_messageMediaWebPage_param_webpage_type_WebPage' => 'Webpage', 'object_messageMediaVenue' => 'Message media venue', 'object_messageMediaVenue_param_geo_type_GeoPoint' => 'Geo', 'object_messageMediaVenue_param_title_type_string' => 'Title', 'object_messageMediaVenue_param_address_type_string' => 'Address', 'object_messageMediaVenue_param_provider_type_string' => 'Provider', 'object_messageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_messageMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_messageMediaGame' => 'Message media game', 'object_messageMediaGame_param_game_type_Game' => 'Game', 'object_messageMediaInvoice' => 'Message media invoice', 'object_messageMediaInvoice_param_shipping_address_requested_type_true' => 'Shipping address requested?', 'object_messageMediaInvoice_param_test_type_true' => 'Test?', 'object_messageMediaInvoice_param_title_type_string' => 'Title', 'object_messageMediaInvoice_param_description_type_string' => 'Description', 'object_messageMediaInvoice_param_photo_type_WebDocument' => 'Photo', 'object_messageMediaInvoice_param_receipt_msg_id_type_int' => 'Receipt msg ID', 'object_messageMediaInvoice_param_currency_type_string' => 'Currency', 'object_messageMediaInvoice_param_total_amount_type_long' => 'Total amount', 'object_messageMediaInvoice_param_start_param_type_string' => 'Start param', 'object_messageMediaGeoLive' => 'Message media geo live', 'object_messageMediaGeoLive_param_geo_type_GeoPoint' => 'Geo', 'object_messageMediaGeoLive_param_period_type_int' => 'Period', 'object_messageActionEmpty' => 'Empty message action', 'object_messageActionChatCreate' => 'Message action chat create', 'object_messageActionChatCreate_param_title_type_string' => 'Title', 'object_messageActionChatCreate_param_users_type_Vector t' => 'Users', 'object_messageActionChatEditTitle' => 'Message action chat edit title', 'object_messageActionChatEditTitle_param_title_type_string' => 'Title', 'object_messageActionChatEditPhoto' => 'Message action chat edit photo', 'object_messageActionChatEditPhoto_param_photo_type_Photo' => 'Photo', 'object_messageActionChatDeletePhoto' => 'Message action chat delete photo', 'object_messageActionChatAddUser' => 'Message action chat add user', 'object_messageActionChatAddUser_param_users_type_Vector t' => 'Users', 'object_messageActionChatDeleteUser' => 'Message action chat delete user', 'object_messageActionChatDeleteUser_param_user_id_type_int' => 'User ID', 'object_messageActionChatJoinedByLink' => 'Message action chat joined by link', 'object_messageActionChatJoinedByLink_param_inviter_id_type_int' => 'Inviter ID', 'object_messageActionChannelCreate' => 'Message action channel create', 'object_messageActionChannelCreate_param_title_type_string' => 'Title', 'object_messageActionChatMigrateTo' => 'Message action chat migrate to', 'object_messageActionChatMigrateTo_param_channel_id_type_int' => 'Channel ID', 'object_messageActionChannelMigrateFrom' => 'Message action channel migrate from', 'object_messageActionChannelMigrateFrom_param_title_type_string' => 'Title', 'object_messageActionChannelMigrateFrom_param_chat_id_type_int' => 'Chat ID', 'object_messageActionPinMessage' => 'Message action pin message', 'object_messageActionHistoryClear' => 'Message action history clear', 'object_messageActionGameScore' => 'Message action game score', 'object_messageActionGameScore_param_game_id_type_long' => 'Game ID', 'object_messageActionGameScore_param_score_type_int' => 'Score', 'object_messageActionPaymentSentMe' => 'Message action payment sent me', 'object_messageActionPaymentSentMe_param_currency_type_string' => 'Currency', 'object_messageActionPaymentSentMe_param_total_amount_type_long' => 'Total amount', 'object_messageActionPaymentSentMe_param_payload_type_bytes' => 'Payload', 'object_messageActionPaymentSentMe_param_info_type_PaymentRequestedInfo' => 'Info', 'object_messageActionPaymentSentMe_param_shipping_option_id_type_string' => 'Shipping option ID', 'object_messageActionPaymentSentMe_param_charge_type_PaymentCharge' => 'Charge', 'object_messageActionPaymentSent' => 'Message action payment sent', 'object_messageActionPaymentSent_param_currency_type_string' => 'Currency', 'object_messageActionPaymentSent_param_total_amount_type_long' => 'Total amount', 'object_messageActionPhoneCall' => 'Message action phone call', 'object_messageActionPhoneCall_param_call_id_type_long' => 'Call ID', 'object_messageActionPhoneCall_param_reason_type_PhoneCallDiscardReason' => 'Reason', 'object_messageActionPhoneCall_param_duration_type_int' => 'Duration', 'object_messageActionScreenshotTaken' => 'Message action screenshot taken', 'object_messageActionCustomAction' => 'Message action custom action', 'object_messageActionCustomAction_param_message_type_string' => 'Message', 'object_dialog' => 'Dialog', 'object_dialog_param_pinned_type_true' => 'Pinned?', 'object_dialog_param_peer_type_Peer' => 'Peer', 'object_dialog_param_top_message_type_int' => 'Top message', 'object_dialog_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_dialog_param_read_outbox_max_id_type_int' => 'Read outbox max ID', 'object_dialog_param_unread_count_type_int' => 'Unread count', 'object_dialog_param_unread_mentions_count_type_int' => 'Unread mentions count', 'object_dialog_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_dialog_param_pts_type_int' => 'Pts', 'object_dialog_param_draft_type_DraftMessage' => 'Draft', 'object_photoEmpty' => 'Empty photo', 'object_photoEmpty_param_id_type_long' => 'ID', 'object_photo' => 'Photo', 'object_photo_param_has_stickers_type_true' => 'Has stickers?', 'object_photo_param_id_type_long' => 'ID', 'object_photo_param_access_hash_type_long' => 'Access hash', 'object_photo_param_date_type_int' => 'Date', 'object_photo_param_sizes_type_Vector t' => 'Sizes', 'object_photoSizeEmpty' => 'Empty photo size', 'object_photoSizeEmpty_param_type_type_string' => 'Type', 'object_photoSize' => 'Photo size', 'object_photoSize_param_type_type_string' => 'Type', 'object_photoSize_param_location_type_FileLocation' => 'Location', 'object_photoSize_param_w_type_int' => 'Width', 'object_photoSize_param_h_type_int' => 'Height', 'object_photoSize_param_size_type_int' => 'Size', 'object_photoCachedSize' => 'Photo cached size', 'object_photoCachedSize_param_type_type_string' => 'Type', 'object_photoCachedSize_param_location_type_FileLocation' => 'Location', 'object_photoCachedSize_param_w_type_int' => 'Width', 'object_photoCachedSize_param_h_type_int' => 'Height', 'object_photoCachedSize_param_bytes_type_bytes' => 'Bytes', 'object_geoPointEmpty' => 'Empty geo point', 'object_geoPoint' => 'Geo point', 'object_geoPoint_param_long_type_double' => 'Long', 'object_geoPoint_param_lat_type_double' => 'Lat', 'object_auth.checkedPhone' => 'Checked phone', 'object_auth.checkedPhone_param_phone_registered_type_Bool' => 'Phone registered?', 'object_auth.sentCode' => 'Sent code', 'object_auth.sentCode_param_phone_registered_type_true' => 'Phone registered?', 'object_auth.sentCode_param_type_type_auth.SentCodeType' => 'Type', 'object_auth.sentCode_param_phone_code_hash_type_string' => 'Phone code hash', 'object_auth.sentCode_param_next_type_type_auth.CodeType' => 'Next type', 'object_auth.sentCode_param_timeout_type_int' => 'Timeout', 'object_auth.authorization' => 'Authorization', 'object_auth.authorization_param_tmp_sessions_type_int' => 'Temporary sessions', 'object_auth.authorization_param_user_type_User' => 'User', 'object_auth.exportedAuthorization' => 'Exported authorization', 'object_auth.exportedAuthorization_param_id_type_int' => 'ID', 'object_auth.exportedAuthorization_param_bytes_type_bytes' => 'Bytes', 'object_inputNotifyPeer' => 'Notify peer', 'object_inputNotifyPeer_param_peer_type_InputPeer' => 'Peer', 'object_inputNotifyUsers' => 'Notify users', 'object_inputNotifyChats' => 'Notify chats', 'object_inputNotifyAll' => 'Notify all', 'object_inputPeerNotifyEventsEmpty' => 'Empty input peer notify events', 'object_inputPeerNotifyEventsAll' => 'Peer notify events all', 'object_inputPeerNotifySettings' => 'Peer notify settings', 'object_inputPeerNotifySettings_param_show_previews_type_true' => 'Show previews?', 'object_inputPeerNotifySettings_param_silent_type_true' => 'Silent?', 'object_inputPeerNotifySettings_param_mute_until_type_int' => 'Mute until', 'object_inputPeerNotifySettings_param_sound_type_string' => 'Sound', 'object_peerNotifyEventsEmpty' => 'Empty peer notify events', 'object_peerNotifyEventsAll' => 'Peer notify events all', 'object_peerNotifySettingsEmpty' => 'Empty peer notify settings', 'object_peerNotifySettings' => 'Peer notify settings', 'object_peerNotifySettings_param_show_previews_type_true' => 'Show previews?', 'object_peerNotifySettings_param_silent_type_true' => 'Silent?', 'object_peerNotifySettings_param_mute_until_type_int' => 'Mute until', 'object_peerNotifySettings_param_sound_type_string' => 'Sound', 'object_peerSettings' => 'Peer settings', 'object_peerSettings_param_report_spam_type_true' => 'Report spam?', 'object_wallPaper' => 'Wall paper', 'object_wallPaper_param_id_type_int' => 'ID', 'object_wallPaper_param_title_type_string' => 'Title', 'object_wallPaper_param_sizes_type_Vector t' => 'Sizes', 'object_wallPaper_param_color_type_int' => 'Color', 'object_wallPaperSolid' => 'Wall paper solid', 'object_wallPaperSolid_param_id_type_int' => 'ID', 'object_wallPaperSolid_param_title_type_string' => 'Title', 'object_wallPaperSolid_param_bg_color_type_int' => 'Bg color', 'object_wallPaperSolid_param_color_type_int' => 'Color', 'object_inputReportReasonSpam' => 'Report reason spam', 'object_inputReportReasonViolence' => 'Report reason violence', 'object_inputReportReasonPornography' => 'Report reason pornography', 'object_inputReportReasonOther' => 'Report reason other', 'object_inputReportReasonOther_param_text_type_string' => 'Text', 'object_userFull' => 'User full', 'object_userFull_param_blocked_type_true' => 'Blocked?', 'object_userFull_param_phone_calls_available_type_true' => 'Phone calls available?', 'object_userFull_param_phone_calls_private_type_true' => 'Phone calls private?', 'object_userFull_param_user_type_User' => 'User', 'object_userFull_param_about_type_string' => 'About', 'object_userFull_param_link_type_contacts.Link' => 'Link', 'object_userFull_param_profile_photo_type_Photo' => 'Profile photo', 'object_userFull_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_userFull_param_bot_info_type_BotInfo' => 'Bot info', 'object_userFull_param_common_chats_count_type_int' => 'Common chats count', 'object_contact' => 'Contact', 'object_contact_param_user_id_type_int' => 'User ID', 'object_contact_param_mutual_type_Bool' => 'Mutual?', 'object_importedContact' => 'Imported contact', 'object_importedContact_param_user_id_type_int' => 'User ID', 'object_importedContact_param_client_id_type_long' => 'Client ID', 'object_contactBlocked' => 'Contact blocked', 'object_contactBlocked_param_user_id_type_int' => 'User ID', 'object_contactBlocked_param_date_type_int' => 'Date', 'object_contactStatus' => 'Contact status', 'object_contactStatus_param_user_id_type_int' => 'User ID', 'object_contactStatus_param_status_type_UserStatus' => 'Status', 'object_contacts.link' => 'Link', 'object_contacts.link_param_my_link_type_ContactLink' => 'My link', 'object_contacts.link_param_foreign_link_type_ContactLink' => 'Foreign link', 'object_contacts.link_param_user_type_User' => 'User', 'object_contacts.contactsNotModified' => 'Contacts not modified', 'object_contacts.contacts' => 'Contacts', 'object_contacts.contacts_param_contacts_type_Vector t' => 'Contacts', 'object_contacts.contacts_param_saved_count_type_int' => 'Saved count', 'object_contacts.contacts_param_users_type_Vector t' => 'Users', 'object_contacts.importedContacts' => 'Imported contacts', 'object_contacts.importedContacts_param_imported_type_Vector t' => 'Imported', 'object_contacts.importedContacts_param_popular_invites_type_Vector t' => 'Popular invites', 'object_contacts.importedContacts_param_retry_contacts_type_Vector t' => 'Retry importing contacts whose client IDs appear here', 'object_contacts.importedContacts_param_users_type_Vector t' => 'Users', 'object_contacts.blocked' => 'Blocked', 'object_contacts.blocked_param_blocked_type_Vector t' => 'Blocked', 'object_contacts.blocked_param_users_type_Vector t' => 'Users', 'object_contacts.blockedSlice' => 'Blocked slice', 'object_contacts.blockedSlice_param_count_type_int' => 'Count', 'object_contacts.blockedSlice_param_blocked_type_Vector t' => 'Blocked', 'object_contacts.blockedSlice_param_users_type_Vector t' => 'Users', 'object_messages.dialogs' => 'Dialogs', 'object_messages.dialogs_param_dialogs_type_Vector t' => 'Dialogs', 'object_messages.dialogs_param_messages_type_Vector t' => 'Messages', 'object_messages.dialogs_param_chats_type_Vector t' => 'Chats', 'object_messages.dialogs_param_users_type_Vector t' => 'Users', 'object_messages.dialogsSlice' => 'Dialogs slice', 'object_messages.dialogsSlice_param_count_type_int' => 'Count', 'object_messages.dialogsSlice_param_dialogs_type_Vector t' => 'Dialogs', 'object_messages.dialogsSlice_param_messages_type_Vector t' => 'Messages', 'object_messages.dialogsSlice_param_chats_type_Vector t' => 'Chats', 'object_messages.dialogsSlice_param_users_type_Vector t' => 'Users', 'object_messages.messages' => 'Messages', 'object_messages.messages_param_messages_type_Vector t' => 'Messages', 'object_messages.messages_param_chats_type_Vector t' => 'Chats', 'object_messages.messages_param_users_type_Vector t' => 'Users', 'object_messages.messagesSlice' => 'Messages slice', 'object_messages.messagesSlice_param_count_type_int' => 'Count', 'object_messages.messagesSlice_param_messages_type_Vector t' => 'Messages', 'object_messages.messagesSlice_param_chats_type_Vector t' => 'Chats', 'object_messages.messagesSlice_param_users_type_Vector t' => 'Users', 'object_messages.channelMessages' => 'Channel messages', 'object_messages.channelMessages_param_pts_type_int' => 'Pts', 'object_messages.channelMessages_param_count_type_int' => 'Count', 'object_messages.channelMessages_param_messages_type_Vector t' => 'Messages', 'object_messages.channelMessages_param_chats_type_Vector t' => 'Chats', 'object_messages.channelMessages_param_users_type_Vector t' => 'Users', 'object_messages.messagesNotModified' => 'Messages not modified', 'object_messages.messagesNotModified_param_count_type_int' => 'Count', 'object_messages.chats' => 'Chats', 'object_messages.chats_param_chats_type_Vector t' => 'Chats', 'object_messages.chatsSlice' => 'Chats slice', 'object_messages.chatsSlice_param_count_type_int' => 'Count', 'object_messages.chatsSlice_param_chats_type_Vector t' => 'Chats', 'object_messages.chatFull' => 'Chat full', 'object_messages.chatFull_param_full_chat_type_ChatFull' => 'Full chat', 'object_messages.chatFull_param_chats_type_Vector t' => 'Chats', 'object_messages.chatFull_param_users_type_Vector t' => 'Users', 'object_messages.affectedHistory' => 'Affected history', 'object_messages.affectedHistory_param_pts_type_int' => 'Pts', 'object_messages.affectedHistory_param_pts_count_type_int' => 'Pts count', 'object_messages.affectedHistory_param_offset_type_int' => 'Offset', 'object_inputMessagesFilterEmpty' => 'Empty input messages filter', 'object_inputMessagesFilterPhotos' => 'Messages filter photos', 'object_inputMessagesFilterVideo' => 'Messages filter video', 'object_inputMessagesFilterPhotoVideo' => 'Messages filter photo video', 'object_inputMessagesFilterDocument' => 'Messages filter document', 'object_inputMessagesFilterUrl' => 'Messages filter URL', 'object_inputMessagesFilterGif' => 'Messages filter gif', 'object_inputMessagesFilterVoice' => 'Messages filter voice', 'object_inputMessagesFilterMusic' => 'Messages filter music', 'object_inputMessagesFilterChatPhotos' => 'Messages filter chat photos', 'object_inputMessagesFilterPhoneCalls' => 'Messages filter phone calls', 'object_inputMessagesFilterPhoneCalls_param_missed_type_true' => 'Missed?', 'object_inputMessagesFilterRoundVoice' => 'Messages filter round voice', 'object_inputMessagesFilterRoundVideo' => 'Messages filter round video', 'object_inputMessagesFilterMyMentions' => 'Messages filter my mentions', 'object_inputMessagesFilterGeo' => 'Messages filter geo', 'object_inputMessagesFilterContacts' => 'Messages filter contacts', 'object_updateNewMessage' => 'Update new message', 'object_updateNewMessage_param_message_type_Message' => 'Message', 'object_updateNewMessage_param_pts_type_int' => 'Pts', 'object_updateNewMessage_param_pts_count_type_int' => 'Pts count', 'object_updateMessageID' => 'Update message ID', 'object_updateMessageID_param_id_type_int' => 'ID', 'object_updateDeleteMessages' => 'Update delete messages', 'object_updateDeleteMessages_param_messages_type_Vector t' => 'Messages', 'object_updateDeleteMessages_param_pts_type_int' => 'Pts', 'object_updateDeleteMessages_param_pts_count_type_int' => 'Pts count', 'object_updateUserTyping' => 'Update user typing', 'object_updateUserTyping_param_user_id_type_int' => 'User ID', 'object_updateUserTyping_param_action_type_SendMessageAction' => 'Action', 'object_updateChatUserTyping' => 'Update chat user typing', 'object_updateChatUserTyping_param_chat_id_type_int' => 'Chat ID', 'object_updateChatUserTyping_param_user_id_type_int' => 'User ID', 'object_updateChatUserTyping_param_action_type_SendMessageAction' => 'Action', 'object_updateChatParticipants' => 'Update chat participants', 'object_updateChatParticipants_param_participants_type_ChatParticipants' => 'Participants', 'object_updateUserName' => 'Update user name', 'object_updateUserName_param_user_id_type_int' => 'User ID', 'object_updateUserName_param_first_name_type_string' => 'First name', 'object_updateUserName_param_last_name_type_string' => 'Last name', 'object_updateUserName_param_username_type_string' => 'Username', 'object_updateUserPhoto' => 'Update user photo', 'object_updateUserPhoto_param_user_id_type_int' => 'User ID', 'object_updateUserPhoto_param_date_type_int' => 'Date', 'object_updateUserPhoto_param_photo_type_UserProfilePhoto' => 'Photo', 'object_updateUserPhoto_param_previous_type_Bool' => 'Previous?', 'object_updateContactRegistered' => 'Update contact registered', 'object_updateContactRegistered_param_user_id_type_int' => 'User ID', 'object_updateContactRegistered_param_date_type_int' => 'Date', 'object_updateContactLink' => 'Update contact link', 'object_updateContactLink_param_user_id_type_int' => 'User ID', 'object_updateContactLink_param_my_link_type_ContactLink' => 'My link', 'object_updateContactLink_param_foreign_link_type_ContactLink' => 'Foreign link', 'object_updateNewEncryptedMessage' => 'Update new encrypted message', 'object_updateNewEncryptedMessage_param_message_type_EncryptedMessage' => 'Message', 'object_updateNewEncryptedMessage_param_qts_type_int' => 'Qts', 'object_updateEncryptedChatTyping' => 'Update encrypted chat typing', 'object_updateEncryptedChatTyping_param_chat_id_type_int' => 'Chat ID', 'object_updateEncryption' => 'Update encryption', 'object_updateEncryption_param_chat_type_EncryptedChat' => 'Chat', 'object_updateEncryption_param_date_type_int' => 'Date', 'object_updateEncryptedMessagesRead' => 'Update encrypted messages read', 'object_updateEncryptedMessagesRead_param_chat_id_type_int' => 'Chat ID', 'object_updateEncryptedMessagesRead_param_max_date_type_int' => 'Max date', 'object_updateEncryptedMessagesRead_param_date_type_int' => 'Date', 'object_updateChatParticipantAdd' => 'Update chat participant add', 'object_updateChatParticipantAdd_param_chat_id_type_int' => 'Chat ID', 'object_updateChatParticipantAdd_param_user_id_type_int' => 'User ID', 'object_updateChatParticipantAdd_param_inviter_id_type_int' => 'Inviter ID', 'object_updateChatParticipantAdd_param_date_type_int' => 'Date', 'object_updateChatParticipantAdd_param_version_type_int' => 'Version', 'object_updateChatParticipantDelete' => 'Update chat participant delete', 'object_updateChatParticipantDelete_param_chat_id_type_int' => 'Chat ID', 'object_updateChatParticipantDelete_param_user_id_type_int' => 'User ID', 'object_updateChatParticipantDelete_param_version_type_int' => 'Version', 'object_updateDcOptions' => 'Update DC options', 'object_updateDcOptions_param_dc_options_type_Vector t' => 'DC options', 'object_updateUserBlocked' => 'Update user blocked', 'object_updateUserBlocked_param_user_id_type_int' => 'User ID', 'object_updateUserBlocked_param_blocked_type_Bool' => 'Blocked?', 'object_updateNotifySettings' => 'Update notify settings', 'object_updateNotifySettings_param_peer_type_NotifyPeer' => 'Peer', 'object_updateNotifySettings_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_updateServiceNotification' => 'Update service notification', 'object_updateServiceNotification_param_popup_type_true' => 'Popup?', 'object_updateServiceNotification_param_inbox_date_type_int' => 'Inbox date', 'object_updateServiceNotification_param_type_type_string' => 'Type', 'object_updateServiceNotification_param_message_type_string' => 'Message', 'object_updateServiceNotification_param_media_type_MessageMedia' => 'Media', 'object_updateServiceNotification_param_entities_type_Vector t' => 'Entities', 'object_updatePrivacy' => 'Update privacy', 'object_updatePrivacy_param_key_type_PrivacyKey' => 'Key', 'object_updatePrivacy_param_rules_type_Vector t' => 'Rules', 'object_updateUserPhone' => 'Update user phone', 'object_updateUserPhone_param_user_id_type_int' => 'User ID', 'object_updateUserPhone_param_phone_type_string' => 'Phone', 'object_updateReadHistoryInbox' => 'Update read history inbox', 'object_updateReadHistoryInbox_param_peer_type_Peer' => 'Peer', 'object_updateReadHistoryInbox_param_max_id_type_int' => 'Max ID', 'object_updateReadHistoryInbox_param_pts_type_int' => 'Pts', 'object_updateReadHistoryInbox_param_pts_count_type_int' => 'Pts count', 'object_updateReadHistoryOutbox' => 'Update read history outbox', 'object_updateReadHistoryOutbox_param_peer_type_Peer' => 'Peer', 'object_updateReadHistoryOutbox_param_max_id_type_int' => 'Max ID', 'object_updateReadHistoryOutbox_param_pts_type_int' => 'Pts', 'object_updateReadHistoryOutbox_param_pts_count_type_int' => 'Pts count', 'object_updateWebPage' => 'Update web page', 'object_updateWebPage_param_webpage_type_WebPage' => 'Webpage', 'object_updateWebPage_param_pts_type_int' => 'Pts', 'object_updateWebPage_param_pts_count_type_int' => 'Pts count', 'object_updateReadMessagesContents' => 'Update read messages contents', 'object_updateReadMessagesContents_param_messages_type_Vector t' => 'Messages', 'object_updateReadMessagesContents_param_pts_type_int' => 'Pts', 'object_updateReadMessagesContents_param_pts_count_type_int' => 'Pts count', 'object_updateChannelTooLong' => 'Update channel too long', 'object_updateChannelTooLong_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelTooLong_param_pts_type_int' => 'Pts', 'object_updateChannel' => 'Update channel', 'object_updateChannel_param_channel_id_type_int' => 'Channel ID', 'object_updateNewChannelMessage' => 'Update new channel message', 'object_updateNewChannelMessage_param_message_type_Message' => 'Message', 'object_updateNewChannelMessage_param_pts_type_int' => 'Pts', 'object_updateNewChannelMessage_param_pts_count_type_int' => 'Pts count', 'object_updateReadChannelInbox' => 'Update read channel inbox', 'object_updateReadChannelInbox_param_channel_id_type_int' => 'Channel ID', 'object_updateReadChannelInbox_param_max_id_type_int' => 'Max ID', 'object_updateDeleteChannelMessages' => 'Update delete channel messages', 'object_updateDeleteChannelMessages_param_channel_id_type_int' => 'Channel ID', 'object_updateDeleteChannelMessages_param_messages_type_Vector t' => 'Messages', 'object_updateDeleteChannelMessages_param_pts_type_int' => 'Pts', 'object_updateDeleteChannelMessages_param_pts_count_type_int' => 'Pts count', 'object_updateChannelMessageViews' => 'Update channel message views', 'object_updateChannelMessageViews_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelMessageViews_param_id_type_int' => 'ID', 'object_updateChannelMessageViews_param_views_type_int' => 'Views', 'object_updateChatAdmins' => 'Update chat admins', 'object_updateChatAdmins_param_chat_id_type_int' => 'Chat ID', 'object_updateChatAdmins_param_enabled_type_Bool' => 'Enabled?', 'object_updateChatAdmins_param_version_type_int' => 'Version', 'object_updateChatParticipantAdmin' => 'Update chat participant admin', 'object_updateChatParticipantAdmin_param_chat_id_type_int' => 'Chat ID', 'object_updateChatParticipantAdmin_param_user_id_type_int' => 'User ID', 'object_updateChatParticipantAdmin_param_is_admin_type_Bool' => 'Is admin?', 'object_updateChatParticipantAdmin_param_version_type_int' => 'Version', 'object_updateNewStickerSet' => 'Update new sticker set', 'object_updateNewStickerSet_param_stickerset_type_messages.StickerSet' => 'Stickerset', 'object_updateStickerSetsOrder' => 'Update sticker sets order', 'object_updateStickerSetsOrder_param_masks_type_true' => 'Masks?', 'object_updateStickerSetsOrder_param_order_type_Vector t' => 'Order', 'object_updateStickerSets' => 'Update sticker sets', 'object_updateSavedGifs' => 'Update saved gifs', 'object_updateBotInlineQuery' => 'Update bot inline query', 'object_updateBotInlineQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotInlineQuery_param_user_id_type_int' => 'User ID', 'object_updateBotInlineQuery_param_query_type_string' => 'Query', 'object_updateBotInlineQuery_param_geo_type_GeoPoint' => 'Geo', 'object_updateBotInlineQuery_param_offset_type_string' => 'Offset', 'object_updateBotInlineSend' => 'Update bot inline send', 'object_updateBotInlineSend_param_user_id_type_int' => 'User ID', 'object_updateBotInlineSend_param_query_type_string' => 'Query', 'object_updateBotInlineSend_param_geo_type_GeoPoint' => 'Geo', 'object_updateBotInlineSend_param_id_type_string' => 'ID', 'object_updateBotInlineSend_param_msg_id_type_InputBotInlineMessageID' => 'Msg ID', 'object_updateEditChannelMessage' => 'Update edit channel message', 'object_updateEditChannelMessage_param_message_type_Message' => 'Message', 'object_updateEditChannelMessage_param_pts_type_int' => 'Pts', 'object_updateEditChannelMessage_param_pts_count_type_int' => 'Pts count', 'object_updateChannelPinnedMessage' => 'Update channel pinned message', 'object_updateChannelPinnedMessage_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelPinnedMessage_param_id_type_int' => 'ID', 'object_updateBotCallbackQuery' => 'Update bot callback query', 'object_updateBotCallbackQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotCallbackQuery_param_user_id_type_int' => 'User ID', 'object_updateBotCallbackQuery_param_peer_type_Peer' => 'Peer', 'object_updateBotCallbackQuery_param_msg_id_type_int' => 'Msg ID', 'object_updateBotCallbackQuery_param_chat_instance_type_long' => 'Chat instance', 'object_updateBotCallbackQuery_param_data_type_bytes' => 'Data', 'object_updateBotCallbackQuery_param_game_short_name_type_string' => 'Game short name', 'object_updateEditMessage' => 'Update edit message', 'object_updateEditMessage_param_message_type_Message' => 'Message', 'object_updateEditMessage_param_pts_type_int' => 'Pts', 'object_updateEditMessage_param_pts_count_type_int' => 'Pts count', 'object_updateInlineBotCallbackQuery' => 'Update inline bot callback query', 'object_updateInlineBotCallbackQuery_param_query_id_type_long' => 'Query ID', 'object_updateInlineBotCallbackQuery_param_user_id_type_int' => 'User ID', 'object_updateInlineBotCallbackQuery_param_msg_id_type_InputBotInlineMessageID' => 'Msg ID', 'object_updateInlineBotCallbackQuery_param_chat_instance_type_long' => 'Chat instance', 'object_updateInlineBotCallbackQuery_param_data_type_bytes' => 'Data', 'object_updateInlineBotCallbackQuery_param_game_short_name_type_string' => 'Game short name', 'object_updateReadChannelOutbox' => 'Update read channel outbox', 'object_updateReadChannelOutbox_param_channel_id_type_int' => 'Channel ID', 'object_updateReadChannelOutbox_param_max_id_type_int' => 'Max ID', 'object_updateDraftMessage' => 'Update draft message', 'object_updateDraftMessage_param_peer_type_Peer' => 'Peer', 'object_updateDraftMessage_param_draft_type_DraftMessage' => 'Draft', 'object_updateReadFeaturedStickers' => 'Update read featured stickers', 'object_updateRecentStickers' => 'Update recent stickers', 'object_updateConfig' => 'Update config', 'object_updatePtsChanged' => 'Update pts changed', 'object_updateChannelWebPage' => 'Update channel web page', 'object_updateChannelWebPage_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelWebPage_param_webpage_type_WebPage' => 'Webpage', 'object_updateChannelWebPage_param_pts_type_int' => 'Pts', 'object_updateChannelWebPage_param_pts_count_type_int' => 'Pts count', 'object_updateDialogPinned' => 'Update dialog pinned', 'object_updateDialogPinned_param_pinned_type_true' => 'Pinned?', 'object_updateDialogPinned_param_peer_type_Peer' => 'Peer', 'object_updatePinnedDialogs' => 'Update pinned dialogs', 'object_updatePinnedDialogs_param_order_type_Vector t' => 'Order', 'object_updateBotWebhookJSON' => 'Update bot webhook json', 'object_updateBotWebhookJSON_param_data_type_DataJSON' => 'Data', 'object_updateBotWebhookJSONQuery' => 'Update bot webhook json query', 'object_updateBotWebhookJSONQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotWebhookJSONQuery_param_data_type_DataJSON' => 'Data', 'object_updateBotWebhookJSONQuery_param_timeout_type_int' => 'Timeout', 'object_updateBotShippingQuery' => 'Update bot shipping query', 'object_updateBotShippingQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotShippingQuery_param_user_id_type_int' => 'User ID', 'object_updateBotShippingQuery_param_payload_type_bytes' => 'Payload', 'object_updateBotShippingQuery_param_shipping_address_type_PostAddress' => 'Shipping address', 'object_updateBotPrecheckoutQuery' => 'Update bot precheckout query', 'object_updateBotPrecheckoutQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotPrecheckoutQuery_param_user_id_type_int' => 'User ID', 'object_updateBotPrecheckoutQuery_param_payload_type_bytes' => 'Payload', 'object_updateBotPrecheckoutQuery_param_info_type_PaymentRequestedInfo' => 'Info', 'object_updateBotPrecheckoutQuery_param_shipping_option_id_type_string' => 'Shipping option ID', 'object_updateBotPrecheckoutQuery_param_currency_type_string' => 'Currency', 'object_updateBotPrecheckoutQuery_param_total_amount_type_long' => 'Total amount', 'object_updatePhoneCall' => 'Update phone call', 'object_updatePhoneCall_param_phone_call_type_PhoneCall' => 'Phone call', 'object_updateLangPackTooLong' => 'Update lang pack too long', 'object_updateLangPack' => 'Update lang pack', 'object_updateLangPack_param_difference_type_LangPackDifference' => 'Difference', 'object_updateFavedStickers' => 'Update faved stickers', 'object_updateChannelReadMessagesContents' => 'Update channel read messages contents', 'object_updateChannelReadMessagesContents_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelReadMessagesContents_param_messages_type_Vector t' => 'Messages', 'object_updateContactsReset' => 'Update contacts reset', 'object_updateChannelAvailableMessages' => 'Update channel available messages', 'object_updateChannelAvailableMessages_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelAvailableMessages_param_available_min_id_type_int' => 'Available min ID', 'object_updates.state' => 'State', 'object_updates.state_param_pts_type_int' => 'Pts', 'object_updates.state_param_qts_type_int' => 'Qts', 'object_updates.state_param_date_type_int' => 'Date', 'object_updates.state_param_seq_type_int' => 'Seq', 'object_updates.state_param_unread_count_type_int' => 'Unread count', 'object_updates.differenceEmpty' => 'Empty difference', 'object_updates.differenceEmpty_param_date_type_int' => 'Date', 'object_updates.differenceEmpty_param_seq_type_int' => 'Seq', 'object_updates.difference' => 'Difference', 'object_updates.difference_param_new_messages_type_Vector t' => 'New messages', 'object_updates.difference_param_new_encrypted_messages_type_Vector t' => 'New encrypted messages', 'object_updates.difference_param_other_updates_type_Vector t' => 'Other updates', 'object_updates.difference_param_chats_type_Vector t' => 'Chats', 'object_updates.difference_param_users_type_Vector t' => 'Users', 'object_updates.difference_param_state_type_updates.State' => 'State', 'object_updates.differenceSlice' => 'Difference slice', 'object_updates.differenceSlice_param_new_messages_type_Vector t' => 'New messages', 'object_updates.differenceSlice_param_new_encrypted_messages_type_Vector t' => 'New encrypted messages', 'object_updates.differenceSlice_param_other_updates_type_Vector t' => 'Other updates', 'object_updates.differenceSlice_param_chats_type_Vector t' => 'Chats', 'object_updates.differenceSlice_param_users_type_Vector t' => 'Users', 'object_updates.differenceSlice_param_intermediate_state_type_updates.State' => 'Intermediate state', 'object_updates.differenceTooLong' => 'Difference too long', 'object_updates.differenceTooLong_param_pts_type_int' => 'Pts', 'object_updatesTooLong' => 'Updates too long', 'object_updateShortMessage' => 'Update short message', 'object_updateShortMessage_param_out_type_true' => 'Out?', 'object_updateShortMessage_param_mentioned_type_true' => 'Mentioned?', 'object_updateShortMessage_param_media_unread_type_true' => 'Media unread?', 'object_updateShortMessage_param_silent_type_true' => 'Silent?', 'object_updateShortMessage_param_id_type_int' => 'ID', 'object_updateShortMessage_param_user_id_type_int' => 'User ID', 'object_updateShortMessage_param_message_type_string' => 'Message', 'object_updateShortMessage_param_pts_type_int' => 'Pts', 'object_updateShortMessage_param_pts_count_type_int' => 'Pts count', 'object_updateShortMessage_param_date_type_int' => 'Date', 'object_updateShortMessage_param_fwd_from_type_MessageFwdHeader' => 'Fwd from', 'object_updateShortMessage_param_via_bot_id_type_int' => 'Via bot ID', 'object_updateShortMessage_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_updateShortMessage_param_entities_type_Vector t' => 'Entities', 'object_updateShortChatMessage' => 'Update short chat message', 'object_updateShortChatMessage_param_out_type_true' => 'Out?', 'object_updateShortChatMessage_param_mentioned_type_true' => 'Mentioned?', 'object_updateShortChatMessage_param_media_unread_type_true' => 'Media unread?', 'object_updateShortChatMessage_param_silent_type_true' => 'Silent?', 'object_updateShortChatMessage_param_id_type_int' => 'ID', 'object_updateShortChatMessage_param_from_id_type_int' => 'From ID', 'object_updateShortChatMessage_param_chat_id_type_int' => 'Chat ID', 'object_updateShortChatMessage_param_message_type_string' => 'Message', 'object_updateShortChatMessage_param_pts_type_int' => 'Pts', 'object_updateShortChatMessage_param_pts_count_type_int' => 'Pts count', 'object_updateShortChatMessage_param_date_type_int' => 'Date', 'object_updateShortChatMessage_param_fwd_from_type_MessageFwdHeader' => 'Fwd from', 'object_updateShortChatMessage_param_via_bot_id_type_int' => 'Via bot ID', 'object_updateShortChatMessage_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_updateShortChatMessage_param_entities_type_Vector t' => 'Entities', 'object_updateShort' => 'Update short', 'object_updateShort_param_update_type_Update' => 'Update', 'object_updateShort_param_date_type_int' => 'Date', 'object_updatesCombined' => 'Updates combined', 'object_updatesCombined_param_updates_type_Vector t' => 'Updates', 'object_updatesCombined_param_users_type_Vector t' => 'Users', 'object_updatesCombined_param_chats_type_Vector t' => 'Chats', 'object_updatesCombined_param_date_type_int' => 'Date', 'object_updatesCombined_param_seq_start_type_int' => 'Seq start', 'object_updatesCombined_param_seq_type_int' => 'Seq', 'object_updates' => 'Updates', 'object_updates_param_updates_type_Vector t' => 'Updates', 'object_updates_param_users_type_Vector t' => 'Users', 'object_updates_param_chats_type_Vector t' => 'Chats', 'object_updates_param_date_type_int' => 'Date', 'object_updates_param_seq_type_int' => 'Seq', 'object_updateShortSentMessage' => 'Update short sent message', 'object_updateShortSentMessage_param_out_type_true' => 'Out?', 'object_updateShortSentMessage_param_id_type_int' => 'ID', 'object_updateShortSentMessage_param_pts_type_int' => 'Pts', 'object_updateShortSentMessage_param_pts_count_type_int' => 'Pts count', 'object_updateShortSentMessage_param_date_type_int' => 'Date', 'object_updateShortSentMessage_param_media_type_MessageMedia' => 'Media', 'object_updateShortSentMessage_param_entities_type_Vector t' => 'Entities', 'object_photos.photos' => 'Photos', 'object_photos.photos_param_photos_type_Vector t' => 'Photos', 'object_photos.photos_param_users_type_Vector t' => 'Users', 'object_photos.photosSlice' => 'Photos slice', 'object_photos.photosSlice_param_count_type_int' => 'Count', 'object_photos.photosSlice_param_photos_type_Vector t' => 'Photos', 'object_photos.photosSlice_param_users_type_Vector t' => 'Users', 'object_photos.photo' => 'Photo', 'object_photos.photo_param_photo_type_Photo' => 'Photo', 'object_photos.photo_param_users_type_Vector t' => 'Users', 'object_upload.file' => 'File', 'object_upload.file_param_type_type_storage.FileType' => 'Type', 'object_upload.file_param_mtime_type_int' => 'Mtime', 'object_upload.file_param_bytes_type_bytes' => 'Bytes', 'object_upload.fileCdnRedirect' => 'File cdn redirect', 'object_upload.fileCdnRedirect_param_dc_id_type_int' => 'DC ID', 'object_upload.fileCdnRedirect_param_file_token_type_bytes' => 'File token', 'object_upload.fileCdnRedirect_param_encryption_key_type_bytes' => 'Encryption key', 'object_upload.fileCdnRedirect_param_encryption_iv_type_bytes' => 'Encryption iv', 'object_upload.fileCdnRedirect_param_cdn_file_hashes_type_Vector t' => 'Cdn file hashes', 'object_dcOption' => 'DC option', 'object_dcOption_param_ipv6_type_true' => 'Ipv6?', 'object_dcOption_param_media_only_type_true' => 'Media only?', 'object_dcOption_param_tcpo_only_type_true' => 'Tcpo only?', 'object_dcOption_param_cdn_type_true' => 'Cdn?', 'object_dcOption_param_static_type_true' => 'Static?', 'object_dcOption_param_id_type_int' => 'ID', 'object_dcOption_param_ip_address_type_string' => 'Ip address', 'object_dcOption_param_port_type_int' => 'Port', 'object_config' => 'Config', 'object_config_param_phonecalls_enabled_type_true' => 'Phonecalls enabled?', 'object_config_param_default_p2p_contacts_type_true' => 'Default p2p contacts?', 'object_config_param_date_type_int' => 'Date', 'object_config_param_expires_type_int' => 'Expires', 'object_config_param_test_mode_type_Bool' => 'Test mode?', 'object_config_param_this_dc_type_int' => 'This DC', 'object_config_param_dc_options_type_Vector t' => 'DC options', 'object_config_param_chat_size_max_type_int' => 'Chat size max', 'object_config_param_megagroup_size_max_type_int' => 'Megagroup size max', 'object_config_param_forwarded_count_max_type_int' => 'Forwarded count max', 'object_config_param_online_update_period_ms_type_int' => 'Online update period ms', 'object_config_param_offline_blur_timeout_ms_type_int' => 'Offline blur timeout ms', 'object_config_param_offline_idle_timeout_ms_type_int' => 'Offline IDle timeout ms', 'object_config_param_online_cloud_timeout_ms_type_int' => 'Online cloud timeout ms', 'object_config_param_notify_cloud_delay_ms_type_int' => 'Notify cloud delay ms', 'object_config_param_notify_default_delay_ms_type_int' => 'Notify default delay ms', 'object_config_param_chat_big_size_type_int' => 'Chat big size', 'object_config_param_push_chat_period_ms_type_int' => 'Push chat period ms', 'object_config_param_push_chat_limit_type_int' => 'Push chat limit', 'object_config_param_saved_gifs_limit_type_int' => 'Saved gifs limit', 'object_config_param_edit_time_limit_type_int' => 'Edit time limit', 'object_config_param_rating_e_decay_type_int' => 'Rating e decay', 'object_config_param_stickers_recent_limit_type_int' => 'Stickers recent limit', 'object_config_param_stickers_faved_limit_type_int' => 'Stickers faved limit', 'object_config_param_channels_read_media_period_type_int' => 'Channels read media period', 'object_config_param_tmp_sessions_type_int' => 'Tmp sessions', 'object_config_param_pinned_dialogs_count_max_type_int' => 'Pinned dialogs count max', 'object_config_param_call_receive_timeout_ms_type_int' => 'Call receive timeout ms', 'object_config_param_call_ring_timeout_ms_type_int' => 'Call ring timeout ms', 'object_config_param_call_connect_timeout_ms_type_int' => 'Call connect timeout ms', 'object_config_param_call_packet_timeout_ms_type_int' => 'Call packet timeout ms', 'object_config_param_me_url_prefix_type_string' => 'Me URL prefix', 'object_config_param_suggested_lang_code_type_string' => 'Suggested lang code', 'object_config_param_lang_pack_version_type_int' => 'Lang pack version', 'object_config_param_disabled_features_type_Vector t' => 'Disabled features', 'object_nearestDc' => 'Nearest DC', 'object_nearestDc_param_country_type_string' => 'Country', 'object_nearestDc_param_this_dc_type_int' => 'This DC', 'object_nearestDc_param_nearest_dc_type_int' => 'Nearest DC', 'object_help.appUpdate' => 'App update', 'object_help.appUpdate_param_id_type_int' => 'ID', 'object_help.appUpdate_param_critical_type_Bool' => 'Critical?', 'object_help.appUpdate_param_url_type_string' => 'URL', 'object_help.appUpdate_param_text_type_string' => 'Text', 'object_help.noAppUpdate' => 'No app update', 'object_help.inviteText' => 'Invite text', 'object_help.inviteText_param_message_type_string' => 'Message', 'object_encryptedChatEmpty' => 'Empty encrypted chat', 'object_encryptedChatEmpty_param_id_type_int' => 'ID', 'object_encryptedChatWaiting' => 'Encrypted chat waiting', 'object_encryptedChatWaiting_param_id_type_int' => 'ID', 'object_encryptedChatWaiting_param_access_hash_type_long' => 'Access hash', 'object_encryptedChatWaiting_param_date_type_int' => 'Date', 'object_encryptedChatWaiting_param_admin_id_type_int' => 'Admin ID', 'object_encryptedChatWaiting_param_participant_id_type_int' => 'Participant ID', 'object_encryptedChatRequested' => 'Encrypted chat requested', 'object_encryptedChatRequested_param_id_type_int' => 'ID', 'object_encryptedChatRequested_param_access_hash_type_long' => 'Access hash', 'object_encryptedChatRequested_param_date_type_int' => 'Date', 'object_encryptedChatRequested_param_admin_id_type_int' => 'Admin ID', 'object_encryptedChatRequested_param_participant_id_type_int' => 'Participant ID', 'object_encryptedChatRequested_param_g_a_type_bytes' => 'G a', 'object_encryptedChat' => 'Encrypted chat', 'object_encryptedChat_param_id_type_int' => 'ID', 'object_encryptedChat_param_access_hash_type_long' => 'Access hash', 'object_encryptedChat_param_date_type_int' => 'Date', 'object_encryptedChat_param_admin_id_type_int' => 'Admin ID', 'object_encryptedChat_param_participant_id_type_int' => 'Participant ID', 'object_encryptedChat_param_g_a_or_b_type_bytes' => 'G a or b', 'object_encryptedChat_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_encryptedChatDiscarded' => 'Encrypted chat discarded', 'object_encryptedChatDiscarded_param_id_type_int' => 'ID', 'object_inputEncryptedChat' => 'Encrypted chat', 'object_inputEncryptedChat_param_chat_id_type_int' => 'Chat ID', 'object_inputEncryptedChat_param_access_hash_type_long' => 'Access hash', 'object_encryptedFileEmpty' => 'Empty encrypted file', 'object_encryptedFile' => 'Encrypted file', 'object_encryptedFile_param_id_type_long' => 'ID', 'object_encryptedFile_param_access_hash_type_long' => 'Access hash', 'object_encryptedFile_param_size_type_int' => 'Size', 'object_encryptedFile_param_dc_id_type_int' => 'DC ID', 'object_encryptedFile_param_key_fingerprint_type_int' => 'Key fingerprint', 'object_inputEncryptedFileEmpty' => 'Empty input encrypted file', 'object_inputEncryptedFileUploaded' => 'Encrypted file uploaded', 'object_inputEncryptedFileUploaded_param_id_type_long' => 'ID', 'object_inputEncryptedFileUploaded_param_parts_type_int' => 'Parts', 'object_inputEncryptedFileUploaded_param_md5_checksum_type_string' => 'Md5 checksum', 'object_inputEncryptedFileUploaded_param_key_fingerprint_type_int' => 'Key fingerprint', 'object_inputEncryptedFile' => 'Encrypted file', 'object_inputEncryptedFile_param_id_type_long' => 'ID', 'object_inputEncryptedFile_param_access_hash_type_long' => 'Access hash', 'object_inputEncryptedFileBigUploaded' => 'Encrypted file big uploaded', 'object_inputEncryptedFileBigUploaded_param_id_type_long' => 'ID', 'object_inputEncryptedFileBigUploaded_param_parts_type_int' => 'Parts', 'object_inputEncryptedFileBigUploaded_param_key_fingerprint_type_int' => 'Key fingerprint', 'object_encryptedMessage' => 'Encrypted message', 'object_encryptedMessage_param_chat_id_type_int' => 'Chat ID', 'object_encryptedMessage_param_date_type_int' => 'Date', 'object_encryptedMessage_param_decrypted_message_type_DecryptedMessage' => 'Decrypted message', 'object_encryptedMessage_param_file_type_EncryptedFile' => 'File', 'object_encryptedMessageService' => 'Encrypted message service', 'object_encryptedMessageService_param_chat_id_type_int' => 'Chat ID', 'object_encryptedMessageService_param_date_type_int' => 'Date', 'object_encryptedMessageService_param_decrypted_message_type_DecryptedMessage' => 'Decrypted message', 'object_messages.dhConfigNotModified' => 'Dh config not modified', 'object_messages.dhConfigNotModified_param_random_type_bytes' => 'Random', 'object_messages.dhConfig' => 'Dh config', 'object_messages.dhConfig_param_g_type_int' => 'G', 'object_messages.dhConfig_param_p_type_bytes' => 'P', 'object_messages.dhConfig_param_version_type_int' => 'Version', 'object_messages.dhConfig_param_random_type_bytes' => 'Random', 'object_messages.sentEncryptedMessage' => 'Sent encrypted message', 'object_messages.sentEncryptedMessage_param_date_type_int' => 'Date', 'object_messages.sentEncryptedFile' => 'Sent encrypted file', 'object_messages.sentEncryptedFile_param_date_type_int' => 'Date', 'object_messages.sentEncryptedFile_param_file_type_EncryptedFile' => 'File', 'object_inputDocumentEmpty' => 'Empty input document', 'object_inputDocument' => 'Document', 'object_inputDocument_param_id_type_long' => 'ID', 'object_inputDocument_param_access_hash_type_long' => 'Access hash', 'object_documentEmpty' => 'Empty document', 'object_documentEmpty_param_id_type_long' => 'ID', 'object_document' => 'Document', 'object_document_param_id_type_long' => 'ID', 'object_document_param_access_hash_type_long' => 'Access hash', 'object_document_param_date_type_int' => 'Date', 'object_document_param_mime_type_type_string' => 'Mime type', 'object_document_param_size_type_int' => 'Size', 'object_document_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_document_param_dc_id_type_int' => 'DC ID', 'object_document_param_version_type_int' => 'Version', 'object_document_param_attributes_type_Vector t' => 'Attributes', 'object_help.support' => 'Support', 'object_help.support_param_phone_number_type_string' => 'Phone number', 'object_help.support_param_user_type_User' => 'User', 'object_notifyPeer' => 'Notify peer', 'object_notifyPeer_param_peer_type_Peer' => 'Peer', 'object_notifyUsers' => 'Notify users', 'object_notifyChats' => 'Notify chats', 'object_notifyAll' => 'Notify all', 'object_sendMessageTypingAction' => 'Send message typing action', 'object_sendMessageCancelAction' => 'Send message cancel action', 'object_sendMessageRecordVideoAction' => 'Send message record video action', 'object_sendMessageUploadVideoAction' => 'Send message upload video action', 'object_sendMessageUploadVideoAction_param_progress_type_int' => 'Progress', 'object_sendMessageRecordAudioAction' => 'Send message record audio action', 'object_sendMessageUploadAudioAction' => 'Send message upload audio action', 'object_sendMessageUploadAudioAction_param_progress_type_int' => 'Progress', 'object_sendMessageUploadPhotoAction' => 'Send message upload photo action', 'object_sendMessageUploadPhotoAction_param_progress_type_int' => 'Progress', 'object_sendMessageUploadDocumentAction' => 'Send message upload document action', 'object_sendMessageUploadDocumentAction_param_progress_type_int' => 'Progress', 'object_sendMessageGeoLocationAction' => 'Send message geo location action', 'object_sendMessageChooseContactAction' => 'Send message choose contact action', 'object_sendMessageGamePlayAction' => 'Send message game play action', 'object_sendMessageRecordRoundAction' => 'Send message record round action', 'object_sendMessageUploadRoundAction' => 'Send message upload round action', 'object_sendMessageUploadRoundAction_param_progress_type_int' => 'Progress', 'object_contacts.found' => 'Found', 'object_contacts.found_param_my_results_type_Vector t' => 'My results', 'object_contacts.found_param_results_type_Vector t' => 'Results', 'object_contacts.found_param_chats_type_Vector t' => 'Chats', 'object_contacts.found_param_users_type_Vector t' => 'Users', 'object_inputPrivacyKeyStatusTimestamp' => 'Privacy key status timestamp', 'object_inputPrivacyKeyChatInvite' => 'Privacy key chat invite', 'object_inputPrivacyKeyPhoneCall' => 'Privacy key phone call', 'object_privacyKeyStatusTimestamp' => 'Privacy key status timestamp', 'object_privacyKeyPhoneCall' => 'Privacy key phone call', 'object_inputPrivacyValueAllowContacts' => 'Privacy value allow contacts', 'object_inputPrivacyValueAllowAll' => 'Privacy value allow all', 'object_inputPrivacyValueAllowUsers' => 'Privacy value allow users', 'object_inputPrivacyValueAllowUsers_param_users_type_Vector t' => 'Users', 'object_inputPrivacyValueDisallowContacts' => 'Privacy value disallow contacts', 'object_inputPrivacyValueDisallowAll' => 'Privacy value disallow all', 'object_inputPrivacyValueDisallowUsers' => 'Privacy value disallow users', 'object_inputPrivacyValueDisallowUsers_param_users_type_Vector t' => 'Users', 'object_privacyValueAllowContacts' => 'Privacy value allow contacts', 'object_privacyValueAllowAll' => 'Privacy value allow all', 'object_privacyValueAllowUsers' => 'Privacy value allow users', 'object_privacyValueAllowUsers_param_users_type_Vector t' => 'Users', 'object_privacyValueDisallowContacts' => 'Privacy value disallow contacts', 'object_privacyValueDisallowAll' => 'Privacy value disallow all', 'object_privacyValueDisallowUsers' => 'Privacy value disallow users', 'object_privacyValueDisallowUsers_param_users_type_Vector t' => 'Users', 'object_account.privacyRules' => 'Privacy rules', 'object_account.privacyRules_param_rules_type_Vector t' => 'Rules', 'object_account.privacyRules_param_users_type_Vector t' => 'Users', 'object_accountDaysTTL' => 'Account TTL in days', 'object_accountDaysTTL_param_days_type_int' => 'Days', 'object_documentAttributeImageSize' => 'Document attribute image size', 'object_documentAttributeImageSize_param_w_type_int' => 'Width', 'object_documentAttributeImageSize_param_h_type_int' => 'Height', 'object_documentAttributeAnimated' => 'Document attribute animated', 'object_documentAttributeSticker' => 'Document attribute sticker', 'object_documentAttributeSticker_param_mask_type_true' => 'Mask?', 'object_documentAttributeSticker_param_alt_type_string' => 'Alt', 'object_documentAttributeSticker_param_stickerset_type_InputStickerSet' => 'Stickerset', 'object_documentAttributeSticker_param_mask_coords_type_MaskCoords' => 'Mask coords', 'object_documentAttributeVideo' => 'Document attribute video', 'object_documentAttributeVideo_param_round_message_type_true' => 'Round message?', 'object_documentAttributeVideo_param_supports_streaming_type_true' => 'Supports streaming?', 'object_documentAttributeVideo_param_duration_type_int' => 'Duration', 'object_documentAttributeVideo_param_w_type_int' => 'Width', 'object_documentAttributeVideo_param_h_type_int' => 'Height', 'object_documentAttributeAudio' => 'Document attribute audio', 'object_documentAttributeAudio_param_voice_type_true' => 'Voice?', 'object_documentAttributeAudio_param_duration_type_int' => 'Duration', 'object_documentAttributeAudio_param_title_type_string' => 'Title', 'object_documentAttributeAudio_param_performer_type_string' => 'Performer', 'object_documentAttributeAudio_param_waveform_type_bytes' => 'Waveform', 'object_documentAttributeFilename' => 'Document attribute filename', 'object_documentAttributeFilename_param_file_name_type_string' => 'File name', 'object_documentAttributeHasStickers' => 'Document attribute has stickers', 'object_messages.stickersNotModified' => 'Stickers not modified', 'object_messages.stickers' => 'Stickers', 'object_messages.stickers_param_hash_type_string' => 'Hash', 'object_messages.stickers_param_stickers_type_Vector t' => 'Stickers', 'object_stickerPack' => 'Sticker pack', 'object_stickerPack_param_emoticon_type_string' => 'Emoticon', 'object_stickerPack_param_documents_type_Vector t' => 'Documents', 'object_messages.allStickersNotModified' => 'All stickers not modified', 'object_messages.allStickers' => 'All stickers', 'object_messages.allStickers_param_hash_type_int' => 'Hash', 'object_messages.allStickers_param_sets_type_Vector t' => 'Sets', 'object_disabledFeature' => 'Disabled feature', 'object_disabledFeature_param_feature_type_string' => 'Feature', 'object_disabledFeature_param_description_type_string' => 'Description', 'object_messages.affectedMessages' => 'Affected messages', 'object_messages.affectedMessages_param_pts_type_int' => 'Pts', 'object_messages.affectedMessages_param_pts_count_type_int' => 'Pts count', 'object_contactLinkUnknown' => 'Contact link unknown', 'object_contactLinkNone' => 'Contact link none', 'object_contactLinkHasPhone' => 'Contact link has phone', 'object_contactLinkContact' => 'Contact link contact', 'object_webPageEmpty' => 'Empty web page', 'object_webPageEmpty_param_id_type_long' => 'ID', 'object_webPagePending' => 'Web page pending', 'object_webPagePending_param_id_type_long' => 'ID', 'object_webPagePending_param_date_type_int' => 'Date', 'object_webPage' => 'Web page', 'object_webPage_param_id_type_long' => 'ID', 'object_webPage_param_url_type_string' => 'URL', 'object_webPage_param_display_url_type_string' => 'Display URL', 'object_webPage_param_hash_type_int' => 'Hash', 'object_webPage_param_type_type_string' => 'Type', 'object_webPage_param_site_name_type_string' => 'Site name', 'object_webPage_param_title_type_string' => 'Title', 'object_webPage_param_description_type_string' => 'Description', 'object_webPage_param_photo_type_Photo' => 'Photo', 'object_webPage_param_embed_url_type_string' => 'Embed URL', 'object_webPage_param_embed_type_type_string' => 'Embed type', 'object_webPage_param_embed_width_type_int' => 'Embed width', 'object_webPage_param_embed_height_type_int' => 'Embed height', 'object_webPage_param_duration_type_int' => 'Duration', 'object_webPage_param_author_type_string' => 'Author', 'object_webPage_param_document_type_Document' => 'Document', 'object_webPage_param_cached_page_type_Page' => 'Cached page', 'object_webPageNotModified' => 'Web page not modified', 'object_authorization' => 'Authorization', 'object_authorization_param_hash_type_long' => 'Hash', 'object_authorization_param_device_model_type_string' => 'Device model', 'object_authorization_param_platform_type_string' => 'Platform', 'object_authorization_param_system_version_type_string' => 'System version', 'object_authorization_param_api_id_type_int' => 'Api ID', 'object_authorization_param_app_name_type_string' => 'App name', 'object_authorization_param_app_version_type_string' => 'App version', 'object_authorization_param_date_created_type_int' => 'Date created', 'object_authorization_param_date_active_type_int' => 'Date active', 'object_authorization_param_ip_type_string' => 'Ip', 'object_authorization_param_country_type_string' => 'Country', 'object_authorization_param_region_type_string' => 'Region', 'object_account.authorizations' => 'Authorized clients for this account', 'object_account.authorizations_param_authorizations_type_Vector t' => 'Authorizations', 'object_account.noPassword' => 'No password', 'object_account.noPassword_param_new_salt_type_bytes' => 'New salt', 'object_account.noPassword_param_email_unconfirmed_pattern_type_string' => 'Email unconfirmed pattern', 'object_account.password' => 'Password', 'object_account.password_param_current_salt_type_bytes' => 'Current salt', 'object_account.password_param_new_salt_type_bytes' => 'New salt', 'object_account.password_param_hint_type_string' => 'Hint', 'object_account.password_param_has_recovery_type_Bool' => 'Has recovery?', 'object_account.password_param_email_unconfirmed_pattern_type_string' => 'Email unconfirmed pattern', 'object_account.passwordSettings' => 'Password settings', 'object_account.passwordSettings_param_email_type_string' => 'Email', 'object_account.passwordInputSettings' => '2FA password settings', 'object_account.passwordInputSettings_param_new_salt_type_bytes' => '`$new_salt = $MadelineProto->account->getPassword()[\'new_salt\'].$MadelineProto->random(8);`', 'object_account.passwordInputSettings_param_new_password_hash_type_bytes' => '`hash(\'sha256\', $new_salt.$new_password.$new_salt, true)`', 'object_account.passwordInputSettings_param_hint_type_string' => 'Hint', 'object_account.passwordInputSettings_param_email_type_string' => 'Email', 'object_auth.passwordRecovery' => 'Password recovery', 'object_auth.passwordRecovery_param_email_pattern_type_string' => 'Email pattern', 'object_receivedNotifyMessage' => 'Received notify message', 'object_receivedNotifyMessage_param_id_type_int' => 'ID', 'object_chatInviteEmpty' => 'Empty chat invite', 'object_chatInviteExported' => 'Exported chat invite', 'object_chatInviteExported_param_link_type_string' => 'Link', 'object_chatInviteAlready' => 'Invite of a chat of which I am already member ', 'object_chatInviteAlready_param_chat_type_Chat' => 'Chat', 'object_chatInvite' => 'Chat invite', 'object_chatInvite_param_channel_type_true' => 'Channel?', 'object_chatInvite_param_broadcast_type_true' => 'Broadcast?', 'object_chatInvite_param_public_type_true' => 'Public?', 'object_chatInvite_param_megagroup_type_true' => 'Megagroup?', 'object_chatInvite_param_title_type_string' => 'Title', 'object_chatInvite_param_photo_type_ChatPhoto' => 'Photo', 'object_chatInvite_param_participants_count_type_int' => 'Participants count', 'object_chatInvite_param_participants_type_Vector t' => 'Participants', 'object_inputStickerSetEmpty' => 'Empty input sticker set', 'object_inputStickerSetID' => 'Sticker set ID', 'object_inputStickerSetID_param_id_type_long' => 'ID', 'object_inputStickerSetID_param_access_hash_type_long' => 'Access hash', 'object_inputStickerSetShortName' => 'Sticker set short name', 'object_inputStickerSetShortName_param_short_name_type_string' => 'Short name', 'object_stickerSet' => 'Sticker set', 'object_stickerSet_param_installed_type_true' => 'Installed?', 'object_stickerSet_param_archived_type_true' => 'Archived?', 'object_stickerSet_param_official_type_true' => 'Official?', 'object_stickerSet_param_masks_type_true' => 'Masks?', 'object_stickerSet_param_id_type_long' => 'ID', 'object_stickerSet_param_access_hash_type_long' => 'Access hash', 'object_stickerSet_param_title_type_string' => 'Title', 'object_stickerSet_param_short_name_type_string' => 'Short name', 'object_stickerSet_param_count_type_int' => 'Count', 'object_stickerSet_param_hash_type_int' => 'Hash', 'object_messages.stickerSet' => 'Sticker set', 'object_messages.stickerSet_param_set_type_StickerSet' => 'Set', 'object_messages.stickerSet_param_packs_type_Vector t' => 'Packs', 'object_messages.stickerSet_param_documents_type_Vector t' => 'Documents', 'object_botInfo' => 'Bot info', 'object_botInfo_param_user_id_type_int' => 'User ID', 'object_botInfo_param_description_type_string' => 'Description', 'object_botInfo_param_commands_type_Vector t' => 'Commands', 'object_keyboardButton' => 'Keyboard button', 'object_keyboardButton_param_text_type_string' => 'Text', 'object_keyboardButtonUrl' => 'Keyboard button URL', 'object_keyboardButtonUrl_param_text_type_string' => 'Text', 'object_keyboardButtonUrl_param_url_type_string' => 'URL', 'object_keyboardButtonCallback' => 'Keyboard button callback', 'object_keyboardButtonCallback_param_text_type_string' => 'Text', 'object_keyboardButtonCallback_param_data_type_bytes' => 'Data', 'object_keyboardButtonRequestPhone' => 'Keyboard button request phone', 'object_keyboardButtonRequestPhone_param_text_type_string' => 'Text', 'object_keyboardButtonRequestGeoLocation' => 'Keyboard button request geo location', 'object_keyboardButtonRequestGeoLocation_param_text_type_string' => 'Text', 'object_keyboardButtonSwitchInline' => 'Keyboard button switch inline', 'object_keyboardButtonSwitchInline_param_same_peer_type_true' => 'Same peer?', 'object_keyboardButtonSwitchInline_param_text_type_string' => 'Text', 'object_keyboardButtonSwitchInline_param_query_type_string' => 'Query', 'object_keyboardButtonGame' => 'Keyboard button game', 'object_keyboardButtonGame_param_text_type_string' => 'Text', 'object_keyboardButtonBuy' => 'Keyboard button buy', 'object_keyboardButtonBuy_param_text_type_string' => 'Text', 'object_keyboardButtonRow' => 'Keyboard button row', 'object_keyboardButtonRow_param_buttons_type_Vector t' => 'Buttons', 'object_replyKeyboardHide' => 'Reply keyboard hide', 'object_replyKeyboardHide_param_selective_type_true' => 'Selective?', 'object_replyKeyboardForceReply' => 'Reply keyboard force reply', 'object_replyKeyboardForceReply_param_single_use_type_true' => 'Single use?', 'object_replyKeyboardForceReply_param_selective_type_true' => 'Selective?', 'object_replyKeyboardMarkup' => 'Reply keyboard markup', 'object_replyKeyboardMarkup_param_resize_type_true' => 'Resize?', 'object_replyKeyboardMarkup_param_single_use_type_true' => 'Single use?', 'object_replyKeyboardMarkup_param_selective_type_true' => 'Selective?', 'object_replyKeyboardMarkup_param_rows_type_Vector t' => 'Rows', 'object_replyInlineMarkup' => 'Reply inline markup', 'object_replyInlineMarkup_param_rows_type_Vector t' => 'Rows', 'object_messageEntityUnknown' => 'Message entity unknown', 'object_messageEntityUnknown_param_offset_type_int' => 'Offset', 'object_messageEntityUnknown_param_length_type_int' => 'Length', 'object_messageEntityMention' => 'Message entity mention', 'object_messageEntityMention_param_offset_type_int' => 'Offset', 'object_messageEntityMention_param_length_type_int' => 'Length', 'object_messageEntityHashtag' => 'Message entity hashtag', 'object_messageEntityHashtag_param_offset_type_int' => 'Offset', 'object_messageEntityHashtag_param_length_type_int' => 'Length', 'object_messageEntityBotCommand' => 'Message entity bot command', 'object_messageEntityBotCommand_param_offset_type_int' => 'Offset', 'object_messageEntityBotCommand_param_length_type_int' => 'Length', 'object_messageEntityUrl' => 'Message entity URL', 'object_messageEntityUrl_param_offset_type_int' => 'Offset', 'object_messageEntityUrl_param_length_type_int' => 'Length', 'object_messageEntityEmail' => 'Message entity email', 'object_messageEntityEmail_param_offset_type_int' => 'Offset', 'object_messageEntityEmail_param_length_type_int' => 'Length', 'object_messageEntityBold' => 'Message entity bold', 'object_messageEntityBold_param_offset_type_int' => 'Offset', 'object_messageEntityBold_param_length_type_int' => 'Length', 'object_messageEntityItalic' => 'Message entity italic', 'object_messageEntityItalic_param_offset_type_int' => 'Offset', 'object_messageEntityItalic_param_length_type_int' => 'Length', 'object_messageEntityCode' => 'Message entity code', 'object_messageEntityCode_param_offset_type_int' => 'Offset', 'object_messageEntityCode_param_length_type_int' => 'Length', 'object_messageEntityPre' => 'Message entity pre', 'object_messageEntityPre_param_offset_type_int' => 'Offset', 'object_messageEntityPre_param_length_type_int' => 'Length', 'object_messageEntityPre_param_language_type_string' => 'Language', 'object_messageEntityTextUrl' => 'Message entity text URL', 'object_messageEntityTextUrl_param_offset_type_int' => 'Offset', 'object_messageEntityTextUrl_param_length_type_int' => 'Length', 'object_messageEntityTextUrl_param_url_type_string' => 'URL', 'object_messageEntityMentionName' => 'Message entity mention name', 'object_messageEntityMentionName_param_offset_type_int' => 'Offset', 'object_messageEntityMentionName_param_length_type_int' => 'Length', 'object_messageEntityMentionName_param_user_id_type_int' => 'User ID', 'object_inputMessageEntityMentionName' => 'Message entity mention name', 'object_inputMessageEntityMentionName_param_offset_type_int' => 'Offset', 'object_inputMessageEntityMentionName_param_length_type_int' => 'Length', 'object_inputMessageEntityMentionName_param_user_id_type_InputUser' => 'User ID', 'object_inputChannelEmpty' => 'Empty input channel', 'object_inputChannel' => 'Channel', 'object_inputChannel_param_channel_id_type_int' => 'Channel ID', 'object_inputChannel_param_access_hash_type_long' => 'Access hash', 'object_contacts.resolvedPeer' => 'Resolved peer', 'object_contacts.resolvedPeer_param_peer_type_Peer' => 'Peer', 'object_contacts.resolvedPeer_param_chats_type_Vector t' => 'Chats', 'object_contacts.resolvedPeer_param_users_type_Vector t' => 'Users', 'object_messageRange' => 'Message range', 'object_messageRange_param_min_id_type_int' => 'Min ID', 'object_messageRange_param_max_id_type_int' => 'Max ID', 'object_updates.channelDifferenceEmpty' => 'Empty channel difference', 'object_updates.channelDifferenceEmpty_param_final_type_true' => 'Final?', 'object_updates.channelDifferenceEmpty_param_pts_type_int' => 'Pts', 'object_updates.channelDifferenceEmpty_param_timeout_type_int' => 'Timeout', 'object_updates.channelDifferenceTooLong' => 'Channel difference too long', 'object_updates.channelDifferenceTooLong_param_final_type_true' => 'Final?', 'object_updates.channelDifferenceTooLong_param_pts_type_int' => 'Pts', 'object_updates.channelDifferenceTooLong_param_timeout_type_int' => 'Timeout', 'object_updates.channelDifferenceTooLong_param_top_message_type_int' => 'Top message', 'object_updates.channelDifferenceTooLong_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_updates.channelDifferenceTooLong_param_read_outbox_max_id_type_int' => 'Read outbox max ID', 'object_updates.channelDifferenceTooLong_param_unread_count_type_int' => 'Unread count', 'object_updates.channelDifferenceTooLong_param_unread_mentions_count_type_int' => 'Unread mentions count', 'object_updates.channelDifferenceTooLong_param_messages_type_Vector t' => 'Messages', 'object_updates.channelDifferenceTooLong_param_chats_type_Vector t' => 'Chats', 'object_updates.channelDifferenceTooLong_param_users_type_Vector t' => 'Users', 'object_updates.channelDifference' => 'Channel difference', 'object_updates.channelDifference_param_final_type_true' => 'Final?', 'object_updates.channelDifference_param_pts_type_int' => 'Pts', 'object_updates.channelDifference_param_timeout_type_int' => 'Timeout', 'object_updates.channelDifference_param_new_messages_type_Vector t' => 'New messages', 'object_updates.channelDifference_param_other_updates_type_Vector t' => 'Other updates', 'object_updates.channelDifference_param_chats_type_Vector t' => 'Chats', 'object_updates.channelDifference_param_users_type_Vector t' => 'Users', 'object_channelMessagesFilterEmpty' => 'Empty channel messages filter', 'object_channelMessagesFilter' => 'Channel messages filter', 'object_channelMessagesFilter_param_exclude_new_messages_type_true' => 'Exclude new messages?', 'object_channelMessagesFilter_param_ranges_type_Vector t' => 'Ranges', 'object_channelParticipant' => 'Channel participant', 'object_channelParticipant_param_user_id_type_int' => 'User ID', 'object_channelParticipant_param_date_type_int' => 'Date', 'object_channelParticipantSelf' => 'Channel participant self', 'object_channelParticipantSelf_param_user_id_type_int' => 'User ID', 'object_channelParticipantSelf_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantSelf_param_date_type_int' => 'Date', 'object_channelParticipantCreator' => 'Channel participant creator', 'object_channelParticipantCreator_param_user_id_type_int' => 'User ID', 'object_channelParticipantAdmin' => 'Channel participant admin', 'object_channelParticipantAdmin_param_can_edit_type_true' => 'Can edit?', 'object_channelParticipantAdmin_param_user_id_type_int' => 'User ID', 'object_channelParticipantAdmin_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantAdmin_param_promoted_by_type_int' => 'Promoted by', 'object_channelParticipantAdmin_param_date_type_int' => 'Date', 'object_channelParticipantAdmin_param_admin_rights_type_ChannelAdminRights' => 'Admin rights', 'object_channelParticipantBanned' => 'Channel participant banned', 'object_channelParticipantBanned_param_left_type_true' => 'Left?', 'object_channelParticipantBanned_param_user_id_type_int' => 'User ID', 'object_channelParticipantBanned_param_kicked_by_type_int' => 'Kicked by', 'object_channelParticipantBanned_param_date_type_int' => 'Date', 'object_channelParticipantBanned_param_banned_rights_type_ChannelBannedRights' => 'Banned rights', 'object_channelParticipantsRecent' => 'Channel participants recent', 'object_channelParticipantsAdmins' => 'Channel participants admins', 'object_channelParticipantsKicked' => 'Channel participants kicked', 'object_channelParticipantsKicked_param_q_type_string' => 'Query', 'object_channelParticipantsBots' => 'Channel participants bots', 'object_channelParticipantsBanned' => 'Channel participants banned', 'object_channelParticipantsBanned_param_q_type_string' => 'Query', 'object_channelParticipantsSearch' => 'Channel participants search', 'object_channelParticipantsSearch_param_q_type_string' => 'Query', 'object_channels.channelParticipants' => 'Channel participants', 'object_channels.channelParticipants_param_count_type_int' => 'Count', 'object_channels.channelParticipants_param_participants_type_Vector t' => 'Participants', 'object_channels.channelParticipants_param_users_type_Vector t' => 'Users', 'object_channels.channelParticipantsNotModified' => 'Channel participants not modified', 'object_channels.channelParticipant' => 'Channel participant', 'object_channels.channelParticipant_param_participant_type_ChannelParticipant' => 'Participant', 'object_channels.channelParticipant_param_users_type_Vector t' => 'Users', 'object_help.termsOfService' => 'Terms of service', 'object_help.termsOfService_param_text_type_string' => 'Text', 'object_foundGif' => 'Found gif', 'object_foundGif_param_url_type_string' => 'URL', 'object_foundGif_param_thumb_url_type_string' => 'Thumbnail URL', 'object_foundGif_param_content_url_type_string' => 'Content URL', 'object_foundGif_param_content_type_type_string' => 'Content type', 'object_foundGif_param_w_type_int' => 'Width', 'object_foundGif_param_h_type_int' => 'Height', 'object_foundGifCached' => 'Found gif cached', 'object_foundGifCached_param_url_type_string' => 'URL', 'object_foundGifCached_param_photo_type_Photo' => 'Photo', 'object_foundGifCached_param_document_type_Document' => 'Document', 'object_messages.foundGifs' => 'Found gifs', 'object_messages.foundGifs_param_next_offset_type_int' => 'Next offset', 'object_messages.foundGifs_param_results_type_Vector t' => 'Results', 'object_messages.savedGifsNotModified' => 'Saved gifs not modified', 'object_messages.savedGifs' => 'Saved gifs', 'object_messages.savedGifs_param_hash_type_int' => 'Hash', 'object_messages.savedGifs_param_gifs_type_Vector t' => 'Gifs', 'object_inputBotInlineMessageMediaAuto' => 'Bot inline message media auto', 'object_inputBotInlineMessageMediaAuto_param_message_type_string' => 'Message', 'object_inputBotInlineMessageMediaAuto_param_entities_type_Vector t' => 'Entities', 'object_inputBotInlineMessageMediaAuto_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageText' => 'Bot inline message text', 'object_inputBotInlineMessageText_param_no_webpage_type_true' => 'No webpage?', 'object_inputBotInlineMessageText_param_message_type_string' => 'Message', 'object_inputBotInlineMessageText_param_entities_type_Vector t' => 'Entities', 'object_inputBotInlineMessageText_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageMediaGeo' => 'Bot inline message media geo', 'object_inputBotInlineMessageMediaGeo_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputBotInlineMessageMediaGeo_param_period_type_int' => 'Period', 'object_inputBotInlineMessageMediaGeo_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageMediaVenue' => 'Bot inline message media venue', 'object_inputBotInlineMessageMediaVenue_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputBotInlineMessageMediaVenue_param_title_type_string' => 'Title', 'object_inputBotInlineMessageMediaVenue_param_address_type_string' => 'Address', 'object_inputBotInlineMessageMediaVenue_param_provider_type_string' => 'Provider', 'object_inputBotInlineMessageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_inputBotInlineMessageMediaVenue_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageMediaContact' => 'Bot inline message media contact', 'object_inputBotInlineMessageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_inputBotInlineMessageMediaContact_param_first_name_type_string' => 'First name', 'object_inputBotInlineMessageMediaContact_param_last_name_type_string' => 'Last name', 'object_inputBotInlineMessageMediaContact_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageGame' => 'Bot inline message game', 'object_inputBotInlineMessageGame_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineResult' => 'Bot inline result', 'object_inputBotInlineResult_param_id_type_string' => 'ID', 'object_inputBotInlineResult_param_type_type_string' => 'Type', 'object_inputBotInlineResult_param_title_type_string' => 'Title', 'object_inputBotInlineResult_param_description_type_string' => 'Description', 'object_inputBotInlineResult_param_url_type_string' => 'URL', 'object_inputBotInlineResult_param_thumb_url_type_string' => 'Thumbnail URL', 'object_inputBotInlineResult_param_content_url_type_string' => 'Content URL', 'object_inputBotInlineResult_param_content_type_type_string' => 'Content type', 'object_inputBotInlineResult_param_w_type_int' => 'Width', 'object_inputBotInlineResult_param_h_type_int' => 'Height', 'object_inputBotInlineResult_param_duration_type_int' => 'Duration', 'object_inputBotInlineResult_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_inputBotInlineResultPhoto' => 'Bot inline result photo', 'object_inputBotInlineResultPhoto_param_id_type_string' => 'ID', 'object_inputBotInlineResultPhoto_param_type_type_string' => 'Type', 'object_inputBotInlineResultPhoto_param_photo_type_InputPhoto' => 'Photo', 'object_inputBotInlineResultPhoto_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_inputBotInlineResultDocument' => 'Bot inline result document', 'object_inputBotInlineResultDocument_param_id_type_string' => 'ID', 'object_inputBotInlineResultDocument_param_type_type_string' => 'Type', 'object_inputBotInlineResultDocument_param_title_type_string' => 'Title', 'object_inputBotInlineResultDocument_param_description_type_string' => 'Description', 'object_inputBotInlineResultDocument_param_document_type_InputDocument' => 'Document', 'object_inputBotInlineResultDocument_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_inputBotInlineResultGame' => 'Bot inline result game', 'object_inputBotInlineResultGame_param_id_type_string' => 'ID', 'object_inputBotInlineResultGame_param_short_name_type_string' => 'Short name', 'object_inputBotInlineResultGame_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_botInlineMessageMediaAuto' => 'Bot inline message media auto', 'object_botInlineMessageMediaAuto_param_message_type_string' => 'Message', 'object_botInlineMessageMediaAuto_param_entities_type_Vector t' => 'Entities', 'object_botInlineMessageMediaAuto_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageText' => 'Bot inline message text', 'object_botInlineMessageText_param_no_webpage_type_true' => 'No webpage?', 'object_botInlineMessageText_param_message_type_string' => 'Message', 'object_botInlineMessageText_param_entities_type_Vector t' => 'Entities', 'object_botInlineMessageText_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageMediaGeo' => 'Bot inline message media geo', 'object_botInlineMessageMediaGeo_param_geo_type_GeoPoint' => 'Geo', 'object_botInlineMessageMediaGeo_param_period_type_int' => 'Period', 'object_botInlineMessageMediaGeo_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageMediaVenue' => 'Bot inline message media venue', 'object_botInlineMessageMediaVenue_param_geo_type_GeoPoint' => 'Geo', 'object_botInlineMessageMediaVenue_param_title_type_string' => 'Title', 'object_botInlineMessageMediaVenue_param_address_type_string' => 'Address', 'object_botInlineMessageMediaVenue_param_provider_type_string' => 'Provider', 'object_botInlineMessageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_botInlineMessageMediaVenue_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageMediaContact' => 'Bot inline message media contact', 'object_botInlineMessageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_botInlineMessageMediaContact_param_first_name_type_string' => 'First name', 'object_botInlineMessageMediaContact_param_last_name_type_string' => 'Last name', 'object_botInlineMessageMediaContact_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineResult' => 'Bot inline result', 'object_botInlineResult_param_id_type_string' => 'ID', 'object_botInlineResult_param_type_type_string' => 'Type', 'object_botInlineResult_param_title_type_string' => 'Title', 'object_botInlineResult_param_description_type_string' => 'Description', 'object_botInlineResult_param_url_type_string' => 'URL', 'object_botInlineResult_param_thumb_url_type_string' => 'Thumbnail URL', 'object_botInlineResult_param_content_url_type_string' => 'Content URL', 'object_botInlineResult_param_content_type_type_string' => 'Content type', 'object_botInlineResult_param_w_type_int' => 'Width', 'object_botInlineResult_param_h_type_int' => 'Height', 'object_botInlineResult_param_duration_type_int' => 'Duration', 'object_botInlineResult_param_send_message_type_BotInlineMessage' => 'Message to send', 'object_botInlineMediaResult' => 'Bot inline media result', 'object_botInlineMediaResult_param_id_type_string' => 'ID', 'object_botInlineMediaResult_param_type_type_string' => 'Type', 'object_botInlineMediaResult_param_photo_type_Photo' => 'Photo', 'object_botInlineMediaResult_param_document_type_Document' => 'Document', 'object_botInlineMediaResult_param_title_type_string' => 'Title', 'object_botInlineMediaResult_param_description_type_string' => 'Description', 'object_botInlineMediaResult_param_send_message_type_BotInlineMessage' => 'Send message', 'object_messages.botResults' => 'Bot results', 'object_messages.botResults_param_gallery_type_true' => 'Gallery?', 'object_messages.botResults_param_query_id_type_long' => 'Query ID', 'object_messages.botResults_param_next_offset_type_string' => 'Next offset', 'object_messages.botResults_param_switch_pm_type_InlineBotSwitchPM' => 'Switch pm', 'object_messages.botResults_param_results_type_Vector t' => 'Results', 'object_messages.botResults_param_cache_time_type_int' => 'Cache time', 'object_messages.botResults_param_users_type_Vector t' => 'Users', 'object_exportedMessageLink' => 'Exported message link', 'object_exportedMessageLink_param_link_type_string' => 'Link', 'object_exportedMessageLink_param_html_type_string' => 'Html', 'object_messageFwdHeader' => 'Forwarded message info', 'object_messageFwdHeader_param_from_id_type_int' => 'From ID', 'object_messageFwdHeader_param_date_type_int' => 'Date', 'object_messageFwdHeader_param_channel_id_type_int' => 'Channel ID', 'object_messageFwdHeader_param_channel_post_type_int' => 'Channel post', 'object_messageFwdHeader_param_post_author_type_string' => 'Post author', 'object_messageFwdHeader_param_saved_from_peer_type_Peer' => 'Saved from peer', 'object_messageFwdHeader_param_saved_from_msg_id_type_int' => 'Saved from msg ID', 'object_auth.codeTypeSms' => 'Auth code type: SMS', 'object_auth.codeTypeCall' => 'Auth code type: call', 'object_auth.codeTypeFlashCall' => 'Auth code type: flash call', 'object_auth.sentCodeTypeApp' => 'Sent code type app', 'object_auth.sentCodeTypeApp_param_length_type_int' => 'Length', 'object_auth.sentCodeTypeSms' => 'Sent code type sms', 'object_auth.sentCodeTypeSms_param_length_type_int' => 'Length', 'object_auth.sentCodeTypeCall' => 'Sent code type call', 'object_auth.sentCodeTypeCall_param_length_type_int' => 'Length', 'object_auth.sentCodeTypeFlashCall' => 'Sent code type flash call', 'object_auth.sentCodeTypeFlashCall_param_pattern_type_string' => 'Pattern', 'object_messages.botCallbackAnswer' => 'Bot callback answer', 'object_messages.botCallbackAnswer_param_alert_type_true' => 'Alert?', 'object_messages.botCallbackAnswer_param_has_url_type_true' => 'Has URL?', 'object_messages.botCallbackAnswer_param_native_ui_type_true' => 'Native ui?', 'object_messages.botCallbackAnswer_param_message_type_string' => 'Message', 'object_messages.botCallbackAnswer_param_url_type_string' => 'URL', 'object_messages.botCallbackAnswer_param_cache_time_type_int' => 'Cache time', 'object_messages.messageEditData' => 'Message edit data', 'object_messages.messageEditData_param_caption_type_true' => 'Caption?', 'object_inputBotInlineMessageID' => 'Bot inline message ID', 'object_inputBotInlineMessageID_param_dc_id_type_int' => 'DC ID', 'object_inputBotInlineMessageID_param_id_type_long' => 'ID', 'object_inputBotInlineMessageID_param_access_hash_type_long' => 'Access hash', 'object_inlineBotSwitchPM' => 'Inline bot switch pm', 'object_inlineBotSwitchPM_param_text_type_string' => 'Text', 'object_inlineBotSwitchPM_param_start_param_type_string' => 'Start param', 'object_messages.peerDialogs' => 'Peer dialogs', 'object_messages.peerDialogs_param_dialogs_type_Vector t' => 'Dialogs', 'object_messages.peerDialogs_param_messages_type_Vector t' => 'Messages', 'object_messages.peerDialogs_param_chats_type_Vector t' => 'Chats', 'object_messages.peerDialogs_param_users_type_Vector t' => 'Users', 'object_messages.peerDialogs_param_state_type_updates.State' => 'State', 'object_topPeer' => 'Top peer', 'object_topPeer_param_peer_type_Peer' => 'Peer', 'object_topPeer_param_rating_type_double' => 'Rating', 'object_topPeerCategoryBotsPM' => 'Top peer category bots pm', 'object_topPeerCategoryBotsInline' => 'Top peer category bots inline', 'object_topPeerCategoryCorrespondents' => 'Top peer category correspondents', 'object_topPeerCategoryGroups' => 'Top peer category groups', 'object_topPeerCategoryChannels' => 'Top peer category channels', 'object_topPeerCategoryPhoneCalls' => 'Top peer category phone calls', 'object_topPeerCategoryPeers' => 'Top peer category peers', 'object_topPeerCategoryPeers_param_category_type_TopPeerCategory' => 'Category', 'object_topPeerCategoryPeers_param_count_type_int' => 'Count', 'object_topPeerCategoryPeers_param_peers_type_Vector t' => 'Peers', 'object_contacts.topPeersNotModified' => 'Top peers not modified', 'object_contacts.topPeers' => 'Top peers', 'object_contacts.topPeers_param_categories_type_Vector t' => 'Categories', 'object_contacts.topPeers_param_chats_type_Vector t' => 'Chats', 'object_contacts.topPeers_param_users_type_Vector t' => 'Users', 'object_draftMessageEmpty' => 'Empty draft message', 'object_draftMessage' => 'Draft message', 'object_draftMessage_param_no_webpage_type_true' => 'No webpage?', 'object_draftMessage_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_draftMessage_param_message_type_string' => 'Message', 'object_draftMessage_param_entities_type_Vector t' => 'Entities', 'object_draftMessage_param_date_type_int' => 'Date', 'object_messages.featuredStickersNotModified' => 'Featured stickers not modified', 'object_messages.featuredStickers' => 'Featured stickers', 'object_messages.featuredStickers_param_hash_type_int' => 'Hash', 'object_messages.featuredStickers_param_sets_type_Vector t' => 'Sets', 'object_messages.featuredStickers_param_unread_type_Vector t' => 'Unread', 'object_messages.recentStickersNotModified' => 'Recent stickers not modified', 'object_messages.recentStickers' => 'Recent stickers', 'object_messages.recentStickers_param_hash_type_int' => 'Hash', 'object_messages.recentStickers_param_stickers_type_Vector t' => 'Stickers', 'object_messages.archivedStickers' => 'Archived stickers', 'object_messages.archivedStickers_param_count_type_int' => 'Count', 'object_messages.archivedStickers_param_sets_type_Vector t' => 'Sets', 'object_messages.stickerSetInstallResultSuccess' => 'Sticker set install result success', 'object_messages.stickerSetInstallResultArchive' => 'Sticker set install result archive', 'object_messages.stickerSetInstallResultArchive_param_sets_type_Vector t' => 'Sets', 'object_stickerSetCovered' => 'Sticker set covered', 'object_stickerSetCovered_param_set_type_StickerSet' => 'Set', 'object_stickerSetCovered_param_cover_type_Document' => 'Cover', 'object_stickerSetMultiCovered' => 'Sticker set multi covered', 'object_stickerSetMultiCovered_param_set_type_StickerSet' => 'Set', 'object_stickerSetMultiCovered_param_covers_type_Vector t' => 'Covers', 'object_maskCoords' => 'Mask coords', 'object_maskCoords_param_n_type_int' => 'N', 'object_maskCoords_param_x_type_double' => 'X', 'object_maskCoords_param_y_type_double' => 'Y', 'object_maskCoords_param_zoom_type_double' => 'Zoom', 'object_inputStickeredMediaPhoto' => 'Stickered media photo', 'object_inputStickeredMediaPhoto_param_id_type_InputPhoto' => 'ID', 'object_inputStickeredMediaDocument' => 'Stickered media document', 'object_inputStickeredMediaDocument_param_id_type_InputDocument' => 'ID', 'object_game' => 'Game', 'object_game_param_id_type_long' => 'ID', 'object_game_param_access_hash_type_long' => 'Access hash', 'object_game_param_short_name_type_string' => 'Short name', 'object_game_param_title_type_string' => 'Title', 'object_game_param_description_type_string' => 'Description', 'object_game_param_photo_type_Photo' => 'Photo', 'object_game_param_document_type_Document' => 'Document', 'object_inputGameID' => 'Game ID', 'object_inputGameID_param_id_type_long' => 'ID', 'object_inputGameID_param_access_hash_type_long' => 'Access hash', 'object_inputGameShortName' => 'Game short name', 'object_inputGameShortName_param_bot_id_type_InputUser' => 'Bot ID', 'object_inputGameShortName_param_short_name_type_string' => 'Short name', 'object_highScore' => 'High score', 'object_highScore_param_pos_type_int' => 'Pos', 'object_highScore_param_user_id_type_int' => 'User ID', 'object_highScore_param_score_type_int' => 'Score', 'object_messages.highScores' => 'High scores', 'object_messages.highScores_param_scores_type_Vector t' => 'Scores', 'object_messages.highScores_param_users_type_Vector t' => 'Users', 'object_textEmpty' => 'Empty text', 'object_textPlain' => 'Text plain', 'object_textPlain_param_text_type_string' => 'Text', 'object_textBold' => 'Text bold', 'object_textBold_param_text_type_RichText' => 'Text', 'object_textItalic' => 'Text italic', 'object_textItalic_param_text_type_RichText' => 'Text', 'object_textUnderline' => 'Text underline', 'object_textUnderline_param_text_type_RichText' => 'Text', 'object_textStrike' => 'Text strike', 'object_textStrike_param_text_type_RichText' => 'Text', 'object_textFixed' => 'Text fixed', 'object_textFixed_param_text_type_RichText' => 'Text', 'object_textUrl' => 'Text URL', 'object_textUrl_param_text_type_RichText' => 'Text', 'object_textUrl_param_url_type_string' => 'URL', 'object_textUrl_param_webpage_id_type_long' => 'Webpage ID', 'object_textEmail' => 'Text email', 'object_textEmail_param_text_type_RichText' => 'Text', 'object_textEmail_param_email_type_string' => 'Email', 'object_textConcat' => 'Text concat', 'object_textConcat_param_texts_type_Vector t' => 'Texts', 'object_pageBlockUnsupported' => 'Page block unsupported', 'object_pageBlockTitle' => 'Page block title', 'object_pageBlockTitle_param_text_type_RichText' => 'Text', 'object_pageBlockSubtitle' => 'Page block subtitle', 'object_pageBlockSubtitle_param_text_type_RichText' => 'Text', 'object_pageBlockAuthorDate' => 'Page block author date', 'object_pageBlockAuthorDate_param_author_type_RichText' => 'Author', 'object_pageBlockAuthorDate_param_published_date_type_int' => 'Published date', 'object_pageBlockHeader' => 'Page block header', 'object_pageBlockHeader_param_text_type_RichText' => 'Text', 'object_pageBlockSubheader' => 'Page block subheader', 'object_pageBlockSubheader_param_text_type_RichText' => 'Text', 'object_pageBlockFooter' => 'Page block footer', 'object_pageBlockFooter_param_text_type_RichText' => 'Text', 'object_pageBlockList' => 'Page block list', 'object_pageBlockList_param_ordered_type_Bool' => 'Ordered?', 'object_pageBlockList_param_items_type_Vector t' => 'Items', 'object_pageBlockBlockquote' => 'Page block blockquote', 'object_pageBlockBlockquote_param_text_type_RichText' => 'Text', 'object_pageBlockBlockquote_param_caption_type_RichText' => 'Caption', 'object_pageBlockPullquote' => 'Page block pullquote', 'object_pageBlockPullquote_param_text_type_RichText' => 'Text', 'object_pageBlockPullquote_param_caption_type_RichText' => 'Caption', 'object_pageBlockPhoto' => 'Page block photo', 'object_pageBlockPhoto_param_photo_id_type_long' => 'Photo ID', 'object_pageBlockPhoto_param_caption_type_RichText' => 'Caption', 'object_pageBlockVideo' => 'Page block video', 'object_pageBlockVideo_param_autoplay_type_true' => 'Autoplay?', 'object_pageBlockVideo_param_loop_type_true' => 'Loop?', 'object_pageBlockVideo_param_video_id_type_long' => 'Video ID', 'object_pageBlockVideo_param_caption_type_RichText' => 'Caption', 'object_pageBlockEmbed' => 'Page block embed', 'object_pageBlockEmbed_param_full_width_type_true' => 'Full width?', 'object_pageBlockEmbed_param_allow_scrolling_type_true' => 'Allow scrolling?', 'object_pageBlockEmbed_param_url_type_string' => 'URL', 'object_pageBlockEmbed_param_html_type_string' => 'Html', 'object_pageBlockEmbed_param_poster_photo_id_type_long' => 'Poster photo ID', 'object_pageBlockEmbed_param_w_type_int' => 'Width', 'object_pageBlockEmbed_param_h_type_int' => 'Height', 'object_pageBlockEmbed_param_caption_type_RichText' => 'Caption', 'object_pageBlockEmbedPost' => 'Page block embed post', 'object_pageBlockEmbedPost_param_url_type_string' => 'URL', 'object_pageBlockEmbedPost_param_webpage_id_type_long' => 'Webpage ID', 'object_pageBlockEmbedPost_param_author_photo_id_type_long' => 'Author photo ID', 'object_pageBlockEmbedPost_param_author_type_string' => 'Author', 'object_pageBlockEmbedPost_param_date_type_int' => 'Date', 'object_pageBlockEmbedPost_param_blocks_type_Vector t' => 'Blocks', 'object_pageBlockEmbedPost_param_caption_type_RichText' => 'Caption', 'object_pageBlockCollage' => 'Page block collage', 'object_pageBlockCollage_param_items_type_Vector t' => 'Items', 'object_pageBlockCollage_param_caption_type_RichText' => 'Caption', 'object_pageBlockSlideshow' => 'Page block slideshow', 'object_pageBlockSlideshow_param_items_type_Vector t' => 'Items', 'object_pageBlockSlideshow_param_caption_type_RichText' => 'Caption', 'object_pageBlockChannel' => 'Page block channel', 'object_pageBlockChannel_param_channel_type_Chat' => 'Channel', 'object_pageBlockAudio' => 'Page block audio', 'object_pageBlockAudio_param_audio_id_type_long' => 'Audio ID', 'object_pageBlockAudio_param_caption_type_RichText' => 'Caption', 'object_pagePart' => 'Page part', 'object_pagePart_param_blocks_type_Vector t' => 'Blocks', 'object_pagePart_param_photos_type_Vector t' => 'Photos', 'object_pagePart_param_documents_type_Vector t' => 'Documents', 'object_pageFull' => 'Page full', 'object_pageFull_param_blocks_type_Vector t' => 'Blocks', 'object_pageFull_param_photos_type_Vector t' => 'Photos', 'object_pageFull_param_documents_type_Vector t' => 'Documents', 'object_phoneCallDiscardReasonMissed' => 'Phone call discard reason missed', 'object_phoneCallDiscardReasonDisconnect' => 'Phone call discard reason disconnect', 'object_phoneCallDiscardReasonHangup' => 'Phone call discard reason hangup', 'object_phoneCallDiscardReasonBusy' => 'Phone call discard reason busy', 'object_dataJSON' => 'Data json', 'object_dataJSON_param_data_type_string' => 'Data', 'object_labeledPrice' => 'Labeled price', 'object_labeledPrice_param_label_type_string' => 'Label', 'object_labeledPrice_param_amount_type_long' => 'Amount', 'object_invoice' => 'Invoice', 'object_invoice_param_test_type_true' => 'Test?', 'object_invoice_param_name_requested_type_true' => 'Name requested?', 'object_invoice_param_phone_requested_type_true' => 'Phone requested?', 'object_invoice_param_email_requested_type_true' => 'Email requested?', 'object_invoice_param_shipping_address_requested_type_true' => 'Shipping address requested?', 'object_invoice_param_flexible_type_true' => 'Flexible?', 'object_invoice_param_phone_to_provider_type_true' => 'Phone to provider?', 'object_invoice_param_email_to_provider_type_true' => 'Email to provider?', 'object_invoice_param_currency_type_string' => 'Currency', 'object_invoice_param_prices_type_Vector t' => 'Prices', 'object_paymentCharge' => 'Payment charge', 'object_paymentCharge_param_id_type_string' => 'ID', 'object_paymentCharge_param_provider_charge_id_type_string' => 'Provider charge ID', 'object_postAddress' => 'Post address', 'object_postAddress_param_street_line1_type_string' => 'Street line1', 'object_postAddress_param_street_line2_type_string' => 'Street line2', 'object_postAddress_param_city_type_string' => 'City', 'object_postAddress_param_state_type_string' => 'State', 'object_postAddress_param_country_iso2_type_string' => 'Country iso2', 'object_postAddress_param_post_code_type_string' => 'Post code', 'object_paymentRequestedInfo' => 'Payment requested info', 'object_paymentRequestedInfo_param_name_type_string' => 'Name', 'object_paymentRequestedInfo_param_phone_type_string' => 'Phone', 'object_paymentRequestedInfo_param_email_type_string' => 'Email', 'object_paymentRequestedInfo_param_shipping_address_type_PostAddress' => 'Shipping address', 'object_paymentSavedCredentialsCard' => 'Payment saved credentials card', 'object_paymentSavedCredentialsCard_param_id_type_string' => 'ID', 'object_paymentSavedCredentialsCard_param_title_type_string' => 'Title', 'object_webDocument' => 'Web document', 'object_webDocument_param_url_type_string' => 'URL', 'object_webDocument_param_access_hash_type_long' => 'Access hash', 'object_webDocument_param_size_type_int' => 'Size', 'object_webDocument_param_mime_type_type_string' => 'Mime type', 'object_webDocument_param_attributes_type_Vector t' => 'Attributes', 'object_webDocument_param_dc_id_type_int' => 'DC ID', 'object_inputWebDocument' => 'Web document', 'object_inputWebDocument_param_url_type_string' => 'URL', 'object_inputWebDocument_param_size_type_int' => 'Size', 'object_inputWebDocument_param_mime_type_type_string' => 'Mime type', 'object_inputWebDocument_param_attributes_type_Vector t' => 'Attributes', 'object_inputWebFileLocation' => 'Web file location', 'object_inputWebFileLocation_param_url_type_string' => 'URL', 'object_inputWebFileLocation_param_access_hash_type_long' => 'Access hash', 'object_upload.webFile' => 'Web file', 'object_upload.webFile_param_size_type_int' => 'Size', 'object_upload.webFile_param_mime_type_type_string' => 'Mime type', 'object_upload.webFile_param_file_type_type_storage.FileType' => 'File type', 'object_upload.webFile_param_mtime_type_int' => 'Mtime', 'object_upload.webFile_param_bytes_type_bytes' => 'Bytes', 'object_payments.paymentForm' => 'Payment form', 'object_payments.paymentForm_param_can_save_credentials_type_true' => 'Can save credentials?', 'object_payments.paymentForm_param_password_missing_type_true' => 'Password missing?', 'object_payments.paymentForm_param_bot_id_type_int' => 'Bot ID', 'object_payments.paymentForm_param_invoice_type_Invoice' => 'Invoice', 'object_payments.paymentForm_param_provider_id_type_int' => 'Provider ID', 'object_payments.paymentForm_param_url_type_string' => 'URL', 'object_payments.paymentForm_param_native_provider_type_string' => 'Native provider', 'object_payments.paymentForm_param_native_params_type_DataJSON' => 'Native params', 'object_payments.paymentForm_param_saved_info_type_PaymentRequestedInfo' => 'Saved info', 'object_payments.paymentForm_param_saved_credentials_type_PaymentSavedCredentials' => 'Saved credentials', 'object_payments.paymentForm_param_users_type_Vector t' => 'Users', 'object_payments.validatedRequestedInfo' => 'Validated requested info', 'object_payments.validatedRequestedInfo_param_id_type_string' => 'ID', 'object_payments.validatedRequestedInfo_param_shipping_options_type_Vector t' => 'Shipping options', 'object_payments.paymentResult' => 'Payment result', 'object_payments.paymentResult_param_updates_type_Updates' => 'Updates', 'object_payments.paymentVerficationNeeded' => 'Payment verfication needed', 'object_payments.paymentVerficationNeeded_param_url_type_string' => 'URL', 'object_payments.paymentReceipt' => 'Payment receipt', 'object_payments.paymentReceipt_param_date_type_int' => 'Date', 'object_payments.paymentReceipt_param_bot_id_type_int' => 'Bot ID', 'object_payments.paymentReceipt_param_invoice_type_Invoice' => 'Invoice', 'object_payments.paymentReceipt_param_provider_id_type_int' => 'Provider ID', 'object_payments.paymentReceipt_param_info_type_PaymentRequestedInfo' => 'Info', 'object_payments.paymentReceipt_param_shipping_type_ShippingOption' => 'Shipping', 'object_payments.paymentReceipt_param_currency_type_string' => 'Currency', 'object_payments.paymentReceipt_param_total_amount_type_long' => 'Total amount', 'object_payments.paymentReceipt_param_credentials_title_type_string' => 'Credentials title', 'object_payments.paymentReceipt_param_users_type_Vector t' => 'Users', 'object_payments.savedInfo' => 'Saved info', 'object_payments.savedInfo_param_has_saved_credentials_type_true' => 'Has saved credentials?', 'object_payments.savedInfo_param_saved_info_type_PaymentRequestedInfo' => 'Saved info', 'object_inputPaymentCredentialsSaved' => 'Payment credentials saved', 'object_inputPaymentCredentialsSaved_param_id_type_string' => 'ID', 'object_inputPaymentCredentialsSaved_param_tmp_password_type_bytes' => 'Tmp password', 'object_inputPaymentCredentials' => 'Payment credentials', 'object_inputPaymentCredentials_param_save_type_true' => 'Save?', 'object_inputPaymentCredentials_param_data_type_DataJSON' => 'Data', 'object_inputPaymentCredentialsApplePay' => 'Payment credentials apple pay', 'object_inputPaymentCredentialsApplePay_param_payment_data_type_DataJSON' => 'Payment data', 'object_inputPaymentCredentialsAndroidPay' => 'Payment credentials android pay', 'object_inputPaymentCredentialsAndroidPay_param_payment_token_type_DataJSON' => 'Payment token', 'object_inputPaymentCredentialsAndroidPay_param_google_transaction_id_type_string' => 'Google transaction ID', 'object_account.tmpPassword' => 'Tmp password', 'object_account.tmpPassword_param_tmp_password_type_bytes' => 'Tmp password', 'object_account.tmpPassword_param_valid_until_type_int' => 'Valid until', 'object_shippingOption' => 'Shipping option', 'object_shippingOption_param_id_type_string' => 'ID', 'object_shippingOption_param_title_type_string' => 'Title', 'object_shippingOption_param_prices_type_Vector t' => 'Prices', 'object_inputStickerSetItem' => 'Sticker set item', 'object_inputStickerSetItem_param_document_type_InputDocument' => 'Document', 'object_inputStickerSetItem_param_emoji_type_string' => 'Emoji', 'object_inputStickerSetItem_param_mask_coords_type_MaskCoords' => 'Mask coords', 'object_inputPhoneCall' => 'Phone call', 'object_inputPhoneCall_param_id_type_long' => 'ID', 'object_inputPhoneCall_param_access_hash_type_long' => 'Access hash', 'object_phoneCallEmpty' => 'Empty phone call', 'object_phoneCallEmpty_param_id_type_long' => 'ID', 'object_phoneCallWaiting' => 'Phone call waiting', 'object_phoneCallWaiting_param_id_type_long' => 'ID', 'object_phoneCallWaiting_param_access_hash_type_long' => 'Access hash', 'object_phoneCallWaiting_param_date_type_int' => 'Date', 'object_phoneCallWaiting_param_admin_id_type_int' => 'Admin ID', 'object_phoneCallWaiting_param_participant_id_type_int' => 'Participant ID', 'object_phoneCallWaiting_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCallWaiting_param_receive_date_type_int' => 'Receive date', 'object_phoneCallRequested' => 'Phone call requested', 'object_phoneCallRequested_param_id_type_long' => 'ID', 'object_phoneCallRequested_param_access_hash_type_long' => 'Access hash', 'object_phoneCallRequested_param_date_type_int' => 'Date', 'object_phoneCallRequested_param_admin_id_type_int' => 'Admin ID', 'object_phoneCallRequested_param_participant_id_type_int' => 'Participant ID', 'object_phoneCallRequested_param_g_a_hash_type_bytes' => 'G a hash', 'object_phoneCallRequested_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCallAccepted' => 'Phone call accepted', 'object_phoneCallAccepted_param_id_type_long' => 'ID', 'object_phoneCallAccepted_param_access_hash_type_long' => 'Access hash', 'object_phoneCallAccepted_param_date_type_int' => 'Date', 'object_phoneCallAccepted_param_admin_id_type_int' => 'Admin ID', 'object_phoneCallAccepted_param_participant_id_type_int' => 'Participant ID', 'object_phoneCallAccepted_param_g_b_type_bytes' => 'G b', 'object_phoneCallAccepted_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCall' => 'Phone call', 'object_phoneCall_param_id_type_long' => 'ID', 'object_phoneCall_param_access_hash_type_long' => 'Access hash', 'object_phoneCall_param_date_type_int' => 'Date', 'object_phoneCall_param_admin_id_type_int' => 'Admin ID', 'object_phoneCall_param_participant_id_type_int' => 'Participant ID', 'object_phoneCall_param_g_a_or_b_type_bytes' => 'G a or b', 'object_phoneCall_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_phoneCall_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCall_param_connection_type_PhoneConnection' => 'Connection', 'object_phoneCall_param_alternative_connections_type_Vector t' => 'Alternative connections', 'object_phoneCall_param_start_date_type_int' => 'Start date', 'object_phoneCallDiscarded' => 'Phone call discarded', 'object_phoneCallDiscarded_param_need_rating_type_true' => 'Need rating?', 'object_phoneCallDiscarded_param_need_debug_type_true' => 'Need debug?', 'object_phoneCallDiscarded_param_id_type_long' => 'ID', 'object_phoneCallDiscarded_param_reason_type_PhoneCallDiscardReason' => 'Reason', 'object_phoneCallDiscarded_param_duration_type_int' => 'Duration', 'object_phoneConnection' => 'Phone connection', 'object_phoneConnection_param_id_type_long' => 'ID', 'object_phoneConnection_param_ip_type_string' => 'Ip', 'object_phoneConnection_param_ipv6_type_string' => 'Ipv6', 'object_phoneConnection_param_port_type_int' => 'Port', 'object_phoneConnection_param_peer_tag_type_bytes' => 'Peer tag', 'object_phoneCallProtocol' => 'Phone call protocol', 'object_phoneCallProtocol_param_udp_p2p_type_true' => 'Udp p2p?', 'object_phoneCallProtocol_param_udp_reflector_type_true' => 'Udp reflector?', 'object_phoneCallProtocol_param_min_layer_type_int' => 'Min layer', 'object_phoneCallProtocol_param_max_layer_type_int' => 'Max layer', 'object_phone.phoneCall' => 'Phone call', 'object_phone.phoneCall_param_phone_call_type_PhoneCall' => 'Phone call', 'object_phone.phoneCall_param_users_type_Vector t' => 'Users', 'object_upload.cdnFileReuploadNeeded' => 'Cdn file reupload needed', 'object_upload.cdnFileReuploadNeeded_param_request_token_type_bytes' => 'Request token', 'object_upload.cdnFile' => 'Cdn file', 'object_upload.cdnFile_param_bytes_type_bytes' => 'Bytes', 'object_cdnPublicKey' => 'Cdn public key', 'object_cdnPublicKey_param_dc_id_type_int' => 'DC ID', 'object_cdnPublicKey_param_public_key_type_string' => 'Public key', 'object_cdnConfig' => 'CDN configuration', 'object_cdnConfig_param_public_keys_type_Vector t' => 'Public keys', 'object_langPackString' => 'Lang pack string', 'object_langPackString_param_key_type_string' => 'Key', 'object_langPackString_param_value_type_string' => 'Value', 'object_langPackStringPluralized' => 'Lang pack string pluralized', 'object_langPackStringPluralized_param_key_type_string' => 'Key', 'object_langPackStringPluralized_param_zero_value_type_string' => 'Zero value', 'object_langPackStringPluralized_param_one_value_type_string' => 'One value', 'object_langPackStringPluralized_param_two_value_type_string' => 'Two value', 'object_langPackStringPluralized_param_few_value_type_string' => 'Few value', 'object_langPackStringPluralized_param_many_value_type_string' => 'Many value', 'object_langPackStringPluralized_param_other_value_type_string' => 'Other value', 'object_langPackStringDeleted' => 'Lang pack string deleted', 'object_langPackStringDeleted_param_key_type_string' => 'Key', 'object_langPackDifference' => 'Lang pack difference', 'object_langPackDifference_param_lang_code_type_string' => 'Lang code', 'object_langPackDifference_param_from_version_type_int' => 'From version', 'object_langPackDifference_param_version_type_int' => 'Version', 'object_langPackDifference_param_strings_type_Vector t' => 'Strings', 'object_langPackLanguage' => 'Lang pack language', 'object_langPackLanguage_param_name_type_string' => 'Name', 'object_langPackLanguage_param_native_name_type_string' => 'Native name', 'object_langPackLanguage_param_lang_code_type_string' => 'Lang code', 'object_channelAdminRights' => 'Admin rights', 'object_channelAdminRights_param_change_info_type_true' => 'Change info', 'object_channelAdminRights_param_post_messages_type_true' => 'Post messages', 'object_channelAdminRights_param_edit_messages_type_true' => 'Edit messages', 'object_channelAdminRights_param_delete_messages_type_true' => 'Delete messages', 'object_channelAdminRights_param_ban_users_type_true' => 'Ban users', 'object_channelAdminRights_param_invite_users_type_true' => 'Invite users', 'object_channelAdminRights_param_invite_link_type_true' => 'Generate an invite link', 'object_channelAdminRights_param_pin_messages_type_true' => 'Pin messages', 'object_channelAdminRights_param_add_admins_type_true' => 'Add other admins', 'object_channelBannedRights' => 'Banned user rights (when true, the user will NOT be able to do that thing)', 'object_channelBannedRights_param_view_messages_type_true' => 'Disallow viewing messages', 'object_channelBannedRights_param_send_messages_type_true' => 'Disallow sending messages', 'object_channelBannedRights_param_send_media_type_true' => 'Disallow sending media', 'object_channelBannedRights_param_send_stickers_type_true' => 'Disallow sending stickers', 'object_channelBannedRights_param_send_gifs_type_true' => 'Disallow sending gifs', 'object_channelBannedRights_param_send_games_type_true' => 'Disallow sending games', 'object_channelBannedRights_param_send_inline_type_true' => 'Disallow sending inline keyboards', 'object_channelBannedRights_param_embed_links_type_true' => 'Disallow embedding links', 'object_channelBannedRights_param_until_date_type_int' => 'Until date', 'object_channelAdminLogEventActionChangeTitle' => 'Change title', 'object_channelAdminLogEventActionChangeTitle_param_prev_value_type_string' => 'Previous value', 'object_channelAdminLogEventActionChangeTitle_param_new_value_type_string' => 'New value', 'object_channelAdminLogEventActionChangeAbout' => 'Change about text', 'object_channelAdminLogEventActionChangeAbout_param_prev_value_type_string' => 'Previous value', 'object_channelAdminLogEventActionChangeAbout_param_new_value_type_string' => 'New value', 'object_channelAdminLogEventActionChangeUsername' => 'Change username', 'object_channelAdminLogEventActionChangeUsername_param_prev_value_type_string' => 'Prev value', 'object_channelAdminLogEventActionChangeUsername_param_new_value_type_string' => 'New value', 'object_channelAdminLogEventActionChangePhoto' => 'Change photo', 'object_channelAdminLogEventActionChangePhoto_param_prev_photo_type_ChatPhoto' => 'Previous photo', 'object_channelAdminLogEventActionChangePhoto_param_new_photo_type_ChatPhoto' => 'New photo', 'object_channelAdminLogEventActionToggleInvites' => 'Invite setting toggled', 'object_channelAdminLogEventActionToggleInvites_param_new_value_type_Bool' => 'New value', 'object_channelAdminLogEventActionToggleSignatures' => 'Toggle channel signatures', 'object_channelAdminLogEventActionToggleSignatures_param_new_value_type_Bool' => 'New value?', 'object_channelAdminLogEventActionUpdatePinned' => 'Message pinned', 'object_channelAdminLogEventActionUpdatePinned_param_message_type_Message' => 'Message', 'object_channelAdminLogEventActionEditMessage' => 'Edit message', 'object_channelAdminLogEventActionEditMessage_param_prev_message_type_Message' => 'Prev message', 'object_channelAdminLogEventActionEditMessage_param_new_message_type_Message' => 'New message', 'object_channelAdminLogEventActionDeleteMessage' => 'Delete message', 'object_channelAdminLogEventActionDeleteMessage_param_message_type_Message' => 'Message', 'object_channelAdminLogEventActionParticipantJoin' => 'Joined participant', 'object_channelAdminLogEventActionParticipantLeave' => 'Left participant', 'object_channelAdminLogEventActionParticipantInvite' => 'Invite participant', 'object_channelAdminLogEventActionParticipantInvite_param_participant_type_ChannelParticipant' => 'Participant', 'object_channelAdminLogEventActionParticipantToggleBan' => 'User banned', 'object_channelAdminLogEventActionParticipantToggleBan_param_prev_participant_type_ChannelParticipant' => 'Prev participant', 'object_channelAdminLogEventActionParticipantToggleBan_param_new_participant_type_ChannelParticipant' => 'New participant', 'object_channelAdminLogEventActionParticipantToggleAdmin' => 'Admin toggled', 'object_channelAdminLogEventActionParticipantToggleAdmin_param_prev_participant_type_ChannelParticipant' => 'Prev participant', 'object_channelAdminLogEventActionParticipantToggleAdmin_param_new_participant_type_ChannelParticipant' => 'New participant', 'object_channelAdminLogEventActionChangeStickerSet' => 'Change stickerset', 'object_channelAdminLogEventActionChangeStickerSet_param_prev_stickerset_type_InputStickerSet' => 'Previous stickerset', 'object_channelAdminLogEventActionChangeStickerSet_param_new_stickerset_type_InputStickerSet' => 'New stickerset', 'object_channelAdminLogEventActionTogglePreHistoryHidden' => 'Previous history hidden', 'object_channelAdminLogEventActionTogglePreHistoryHidden_param_new_value_type_Bool' => 'New value', 'object_channelAdminLogEvent' => 'Channel admin log event', 'object_channelAdminLogEvent_param_id_type_long' => 'ID', 'object_channelAdminLogEvent_param_date_type_int' => 'Date', 'object_channelAdminLogEvent_param_user_id_type_int' => 'User ID', 'object_channelAdminLogEvent_param_action_type_ChannelAdminLogEventAction' => 'Action', 'object_channels.adminLogResults' => 'Admin log results', 'object_channels.adminLogResults_param_events_type_Vector t' => 'Events', 'object_channels.adminLogResults_param_chats_type_Vector t' => 'Chats', 'object_channels.adminLogResults_param_users_type_Vector t' => 'Users', 'object_channelAdminLogEventsFilter' => 'Event filter', 'object_channelAdminLogEventsFilter_param_join_type_true' => 'Join users events', 'object_channelAdminLogEventsFilter_param_leave_type_true' => 'Left users events', 'object_channelAdminLogEventsFilter_param_invite_type_true' => 'Invite users events', 'object_channelAdminLogEventsFilter_param_ban_type_true' => 'Ban events', 'object_channelAdminLogEventsFilter_param_unban_type_true' => 'Unban events', 'object_channelAdminLogEventsFilter_param_kick_type_true' => 'Kicked users events', 'object_channelAdminLogEventsFilter_param_unkick_type_true' => 'Unkick events', 'object_channelAdminLogEventsFilter_param_promote_type_true' => 'Admin promotion events', 'object_channelAdminLogEventsFilter_param_demote_type_true' => 'Demote admin events', 'object_channelAdminLogEventsFilter_param_info_type_true' => 'Change info events', 'object_channelAdminLogEventsFilter_param_settings_type_true' => 'Setting changes', 'object_channelAdminLogEventsFilter_param_pinned_type_true' => 'Pinned message events', 'object_channelAdminLogEventsFilter_param_edit_type_true' => 'Edit message events', 'object_channelAdminLogEventsFilter_param_delete_type_true' => 'Delete message events', 'object_popularContact' => 'Popular contact', 'object_popularContact_param_client_id_type_long' => 'Client ID', 'object_popularContact_param_importers_type_int' => 'Importers', 'object_cdnFileHash' => 'CDN file hash', 'object_cdnFileHash_param_offset_type_int' => 'Offset', 'object_cdnFileHash_param_limit_type_int' => 'Limit', 'object_cdnFileHash_param_hash_type_bytes' => 'Hash', 'object_messages.favedStickersNotModified' => 'Faved stickers not modified', 'object_messages.favedStickers' => 'Faved stickers', 'object_messages.favedStickers_param_hash_type_int' => 'Hash', 'object_messages.favedStickers_param_packs_type_Vector t' => 'Packs', 'object_messages.favedStickers_param_stickers_type_Vector t' => 'Stickers', 'object_recentMeUrlUnknown' => 'Recent me URL unknown', 'object_recentMeUrlUnknown_param_url_type_string' => 'URL', 'object_recentMeUrlUser' => 'Recent me URL user', 'object_recentMeUrlUser_param_url_type_string' => 'URL', 'object_recentMeUrlUser_param_user_id_type_int' => 'User ID', 'object_recentMeUrlChat' => 'Recent me URL chat', 'object_recentMeUrlChat_param_url_type_string' => 'URL', 'object_recentMeUrlChat_param_chat_id_type_int' => 'Chat ID', 'object_recentMeUrlChatInvite' => 'Recent me URL chat invite', 'object_recentMeUrlChatInvite_param_url_type_string' => 'URL', 'object_recentMeUrlChatInvite_param_chat_invite_type_ChatInvite' => 'Chat invite', 'object_recentMeUrlStickerSet' => 'Recent me URL sticker set', 'object_recentMeUrlStickerSet_param_url_type_string' => 'URL', 'object_recentMeUrlStickerSet_param_set_type_StickerSetCovered' => 'Set', 'object_help.recentMeUrls' => 'Recent me URLs', 'object_help.recentMeUrls_param_urls_type_Vector t' => 'URLs', 'object_help.recentMeUrls_param_chats_type_Vector t' => 'Chats', 'object_help.recentMeUrls_param_users_type_Vector t' => 'Users', 'object_inputSingleMedia' => 'Single media', 'object_inputSingleMedia_param_media_type_InputMedia' => 'Media', 'object_inputSingleMedia_param_message_type_string' => 'Message', 'object_inputSingleMedia_param_entities_type_Vector t' => 'Entities', 'object_webAuthorization' => 'Web authorization', 'object_webAuthorization_param_hash_type_long' => 'Hash', 'object_webAuthorization_param_bot_id_type_int' => 'Bot ID', 'object_webAuthorization_param_domain_type_string' => 'Domain', 'object_webAuthorization_param_browser_type_string' => 'Browser', 'object_webAuthorization_param_platform_type_string' => 'Platform', 'object_webAuthorization_param_date_created_type_int' => 'Date created', 'object_webAuthorization_param_date_active_type_int' => 'Date active', 'object_webAuthorization_param_ip_type_string' => 'Ip', 'object_webAuthorization_param_region_type_string' => 'Region', 'object_account.webAuthorizations' => 'Telegram login authorizations', 'object_account.webAuthorizations_param_authorizations_type_Vector t' => 'Authorizations', 'object_account.webAuthorizations_param_users_type_Vector t' => 'Users', 'object_inputMessageID' => 'Message ID', 'object_inputMessageID_param_id_type_int' => 'ID', 'object_inputMessageReplyTo' => 'Message reply to', 'object_inputMessageReplyTo_param_id_type_int' => 'ID', 'object_inputMessagePinned' => 'Message pinned', 'object_decryptedDataBlock' => 'Decrypted data block', 'object_decryptedDataBlock_param_voice_call_id_type_int128' => 'Voice call ID', 'object_decryptedDataBlock_param_in_seq_no_type_int' => 'In seq no', 'object_decryptedDataBlock_param_out_seq_no_type_int' => 'Out seq no', 'object_decryptedDataBlock_param_recent_received_mask_type_int' => 'Recent received mask', 'object_decryptedDataBlock_param_proto_type_int' => 'Proto', 'object_decryptedDataBlock_param_extra_type_string' => 'Extra', 'object_decryptedDataBlock_param_raw_data_type_string' => 'Raw data', 'object_simpleDataBlock' => 'Simple data block', 'object_simpleDataBlock_param_raw_data_type_string' => 'Raw data', 'object_decryptedMessage' => 'Decrypted message', 'object_decryptedMessage_param_message_type_string' => 'Message', 'object_decryptedMessage_param_media_type_DecryptedMessageMedia' => 'Media', 'object_decryptedMessageService' => 'Decrypted message service', 'object_decryptedMessageService_param_action_type_DecryptedMessageAction' => 'Action', 'object_decryptedMessageMediaEmpty' => 'Empty decrypted message media', 'object_decryptedMessageMediaPhoto' => 'Decrypted message media photo', 'object_decryptedMessageMediaPhoto_param_thumb_type_bytes' => 'Thumbnail', 'object_decryptedMessageMediaPhoto_param_thumb_w_type_int' => 'Thumbnail width', 'object_decryptedMessageMediaPhoto_param_thumb_h_type_int' => 'Thumbnail height', 'object_decryptedMessageMediaPhoto_param_w_type_int' => 'Width', 'object_decryptedMessageMediaPhoto_param_h_type_int' => 'Height', 'object_decryptedMessageMediaPhoto_param_size_type_int' => 'Size', 'object_decryptedMessageMediaPhoto_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaPhoto_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageMediaVideo' => 'Decrypted message media video', 'object_decryptedMessageMediaVideo_param_thumb_type_bytes' => 'Thumbnail', 'object_decryptedMessageMediaVideo_param_thumb_w_type_int' => 'Thumbnail width', 'object_decryptedMessageMediaVideo_param_thumb_h_type_int' => 'Thumbnail height', 'object_decryptedMessageMediaVideo_param_duration_type_int' => 'Duration', 'object_decryptedMessageMediaVideo_param_w_type_int' => 'Width', 'object_decryptedMessageMediaVideo_param_h_type_int' => 'Height', 'object_decryptedMessageMediaVideo_param_size_type_int' => 'Size', 'object_decryptedMessageMediaVideo_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaVideo_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageMediaGeoPoint' => 'Decrypted message media geo point', 'object_decryptedMessageMediaGeoPoint_param_lat_type_double' => 'Lat', 'object_decryptedMessageMediaGeoPoint_param_long_type_double' => 'Long', 'object_decryptedMessageMediaContact' => 'Decrypted message media contact', 'object_decryptedMessageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_decryptedMessageMediaContact_param_first_name_type_string' => 'First name', 'object_decryptedMessageMediaContact_param_last_name_type_string' => 'Last name', 'object_decryptedMessageMediaContact_param_user_id_type_int' => 'User ID', 'object_decryptedMessageActionSetMessageTTL' => 'Decrypted message action set message ttl', 'object_decryptedMessageActionSetMessageTTL_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_decryptedMessageMediaDocument' => 'Decrypted message media document', 'object_decryptedMessageMediaDocument_param_thumb_type_bytes' => 'Thumbnail', 'object_decryptedMessageMediaDocument_param_thumb_w_type_int' => 'Thumbnail w', 'object_decryptedMessageMediaDocument_param_thumb_h_type_int' => 'Thumbnail h', 'object_decryptedMessageMediaDocument_param_file_name_type_string' => 'File name', 'object_decryptedMessageMediaDocument_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageMediaDocument_param_size_type_int' => 'Size', 'object_decryptedMessageMediaDocument_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaDocument_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageMediaAudio' => 'Decrypted message media audio', 'object_decryptedMessageMediaAudio_param_duration_type_int' => 'Duration', 'object_decryptedMessageMediaAudio_param_size_type_int' => 'Size', 'object_decryptedMessageMediaAudio_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaAudio_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageActionReadMessages' => 'Decrypted message action read messages', 'object_decryptedMessageActionReadMessages_param_random_ids_type_Vector t' => 'Random IDs', 'object_decryptedMessageActionDeleteMessages' => 'Decrypted message action delete messages', 'object_decryptedMessageActionDeleteMessages_param_random_ids_type_Vector t' => 'Random IDs', 'object_decryptedMessageActionScreenshotMessages' => 'Decrypted message action screenshot messages', 'object_decryptedMessageActionScreenshotMessages_param_random_ids_type_Vector t' => 'Random IDs', 'object_decryptedMessageActionFlushHistory' => 'Decrypted message action flush history', 'object_decryptedMessage_param_ttl_type_int' => 'Ttl', 'object_decryptedMessageMediaVideo_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageMediaAudio_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageLayer' => 'Decrypted message layer', 'object_decryptedMessageLayer_param_layer_type_int' => 'Layer', 'object_decryptedMessageLayer_param_in_seq_no_type_int' => 'In seq no', 'object_decryptedMessageLayer_param_out_seq_no_type_int' => 'Out seq no', 'object_decryptedMessageLayer_param_message_type_DecryptedMessage' => 'Message', 'object_decryptedMessageActionResend' => 'Decrypted message action resend', 'object_decryptedMessageActionResend_param_start_seq_no_type_int' => 'Start seq no', 'object_decryptedMessageActionResend_param_end_seq_no_type_int' => 'End seq no', 'object_decryptedMessageActionNotifyLayer' => 'Decrypted message action notify layer', 'object_decryptedMessageActionNotifyLayer_param_layer_type_int' => 'Layer', 'object_decryptedMessageActionTyping' => 'Decrypted message action typing', 'object_decryptedMessageActionTyping_param_action_type_SendMessageAction' => 'Action', 'object_decryptedMessageActionRequestKey' => 'Decrypted message action request key', 'object_decryptedMessageActionRequestKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionRequestKey_param_g_a_type_bytes' => 'G a', 'object_decryptedMessageActionAcceptKey' => 'Decrypted message action accept key', 'object_decryptedMessageActionAcceptKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionAcceptKey_param_g_b_type_bytes' => 'G b', 'object_decryptedMessageActionAcceptKey_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_decryptedMessageActionAbortKey' => 'Decrypted message action abort key', 'object_decryptedMessageActionAbortKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionCommitKey' => 'Decrypted message action commit key', 'object_decryptedMessageActionCommitKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionCommitKey_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_decryptedMessageActionNoop' => 'Decrypted message action noop', 'object_decryptedMessageMediaExternalDocument' => 'Decrypted message media external document', 'object_decryptedMessageMediaExternalDocument_param_id_type_long' => 'ID', 'object_decryptedMessageMediaExternalDocument_param_access_hash_type_long' => 'Access hash', 'object_decryptedMessageMediaExternalDocument_param_date_type_int' => 'Date', 'object_decryptedMessageMediaExternalDocument_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageMediaExternalDocument_param_size_type_int' => 'Size', 'object_decryptedMessageMediaExternalDocument_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_decryptedMessageMediaExternalDocument_param_dc_id_type_int' => 'DC ID', 'object_decryptedMessageMediaExternalDocument_param_attributes_type_Vector t' => 'Attributes', 'object_decryptedMessage_param_entities_type_Vector t' => 'Entities', 'object_decryptedMessage_param_via_bot_name_type_string' => 'Via bot name', 'object_decryptedMessage_param_reply_to_random_id_type_long' => 'Reply to random ID', 'object_decryptedMessageMediaPhoto_param_caption_type_string' => 'Caption', 'object_decryptedMessageMediaVideo_param_caption_type_string' => 'Caption', 'object_decryptedMessageMediaDocument_param_attributes_type_Vector t' => 'Attributes', 'object_decryptedMessageMediaDocument_param_caption_type_string' => 'Caption', 'object_decryptedMessageMediaVenue' => 'Decrypted message media venue', 'object_decryptedMessageMediaVenue_param_lat_type_double' => 'Lat', 'object_decryptedMessageMediaVenue_param_long_type_double' => 'Long', 'object_decryptedMessageMediaVenue_param_title_type_string' => 'Title', 'object_decryptedMessageMediaVenue_param_address_type_string' => 'Address', 'object_decryptedMessageMediaVenue_param_provider_type_string' => 'Provider', 'object_decryptedMessageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_decryptedMessageMediaWebPage' => 'Decrypted message media web page', 'object_decryptedMessageMediaWebPage_param_url_type_string' => 'URL', 'object_decryptedMessage_param_grouped_id_type_long' => 'Grouped ID', 'object_inputPeerContact' => 'Peer contact', 'object_inputPeerContact_param_user_id_type_int' => 'User ID', 'object_inputPeerForeign' => 'Peer foreign', 'object_inputPeerForeign_param_user_id_type_int' => 'User ID', 'object_inputPeerForeign_param_access_hash_type_long' => 'Access hash', 'object_inputUserContact' => 'User contact', 'object_inputUserContact_param_user_id_type_int' => 'User ID', 'object_inputUserForeign' => 'User foreign', 'object_inputUserForeign_param_user_id_type_int' => 'User ID', 'object_inputUserForeign_param_access_hash_type_long' => 'Access hash', 'object_inputMediaUploadedVideo' => 'Media uploaded video', 'object_inputMediaUploadedVideo_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedVideo_param_duration_type_int' => 'Duration', 'object_inputMediaUploadedVideo_param_w_type_int' => 'Width', 'object_inputMediaUploadedVideo_param_h_type_int' => 'Height', 'object_inputMediaUploadedVideo_param_mime_type_type_string' => 'Mime type', 'object_inputMediaUploadedThumbVideo' => 'Media uploaded thumb video', 'object_inputMediaUploadedThumbVideo_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedThumbVideo_param_thumb_type_InputFile' => 'Thumbnail', 'object_inputMediaUploadedThumbVideo_param_duration_type_int' => 'Duration', 'object_inputMediaUploadedThumbVideo_param_w_type_int' => 'Width', 'object_inputMediaUploadedThumbVideo_param_h_type_int' => 'Height', 'object_inputMediaUploadedThumbVideo_param_mime_type_type_string' => 'Mime type', 'object_inputMediaVideo' => 'Media video', 'object_inputMediaVideo_param_id_type_InputVideo' => 'ID', 'object_inputChatUploadedPhoto_param_crop_type_InputPhotoCrop' => 'Crop', 'object_inputChatPhoto_param_crop_type_InputPhotoCrop' => 'Crop', 'object_inputVideoEmpty' => 'Empty input video', 'object_inputVideo' => 'Video', 'object_inputVideo_param_id_type_long' => 'ID', 'object_inputVideo_param_access_hash_type_long' => 'Access hash', 'object_inputVideoFileLocation' => 'Video file location', 'object_inputVideoFileLocation_param_id_type_long' => 'ID', 'object_inputVideoFileLocation_param_access_hash_type_long' => 'Access hash', 'object_inputPhotoCropAuto' => 'Photo crop auto', 'object_inputPhotoCrop' => 'Photo crop', 'object_inputPhotoCrop_param_crop_left_type_double' => 'Crop left', 'object_inputPhotoCrop_param_crop_top_type_double' => 'Crop top', 'object_inputPhotoCrop_param_crop_width_type_double' => 'Crop width', 'object_userSelf' => 'User self', 'object_userSelf_param_id_type_int' => 'ID', 'object_userSelf_param_first_name_type_string' => 'First name', 'object_userSelf_param_last_name_type_string' => 'Last name', 'object_userSelf_param_username_type_string' => 'Username', 'object_userSelf_param_phone_type_string' => 'Phone', 'object_userSelf_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userSelf_param_status_type_UserStatus' => 'Status', 'object_userSelf_param_inactive_type_Bool' => 'Inactive?', 'object_userContact' => 'User contact', 'object_userContact_param_id_type_int' => 'ID', 'object_userContact_param_first_name_type_string' => 'First name', 'object_userContact_param_last_name_type_string' => 'Last name', 'object_userContact_param_username_type_string' => 'Username', 'object_userContact_param_access_hash_type_long' => 'Access hash', 'object_userContact_param_phone_type_string' => 'Phone', 'object_userContact_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userContact_param_status_type_UserStatus' => 'Status', 'object_userRequest' => 'User request', 'object_userRequest_param_id_type_int' => 'ID', 'object_userRequest_param_first_name_type_string' => 'First name', 'object_userRequest_param_last_name_type_string' => 'Last name', 'object_userRequest_param_username_type_string' => 'Username', 'object_userRequest_param_access_hash_type_long' => 'Access hash', 'object_userRequest_param_phone_type_string' => 'Phone', 'object_userRequest_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userRequest_param_status_type_UserStatus' => 'Status', 'object_userForeign' => 'User foreign', 'object_userForeign_param_id_type_int' => 'ID', 'object_userForeign_param_first_name_type_string' => 'First name', 'object_userForeign_param_last_name_type_string' => 'Last name', 'object_userForeign_param_username_type_string' => 'Username', 'object_userForeign_param_access_hash_type_long' => 'Access hash', 'object_userForeign_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userForeign_param_status_type_UserStatus' => 'Status', 'object_userDeleted' => 'User deleted', 'object_userDeleted_param_id_type_int' => 'ID', 'object_userDeleted_param_first_name_type_string' => 'First name', 'object_userDeleted_param_last_name_type_string' => 'Last name', 'object_userDeleted_param_username_type_string' => 'Username', 'object_userStatusEmpty' => 'Empty user status', 'object_userStatusOnline' => 'User status online', 'object_userStatusOnline_param_expires_type_int' => 'Expires', 'object_userStatusOffline' => 'User status offline', 'object_userStatusOffline_param_was_online_type_int' => 'Was online', 'object_chat_param_left_type_Bool' => 'Left?', 'object_chatForbidden_param_date_type_int' => 'Date', 'object_chatParticipants_param_admin_id_type_int' => 'Admin ID', 'object_messageForwarded' => 'Message forwarded', 'object_messageForwarded_param_id_type_int' => 'ID', 'object_messageForwarded_param_fwd_from_id_type_int' => 'Forwarded from ID', 'object_messageForwarded_param_fwd_date_type_int' => 'Forwarded date', 'object_messageForwarded_param_from_id_type_int' => 'From ID', 'object_messageForwarded_param_to_id_type_Peer' => 'To ID', 'object_messageForwarded_param_date_type_int' => 'Date', 'object_messageForwarded_param_message_type_string' => 'Message', 'object_messageForwarded_param_media_type_MessageMedia' => 'Media', 'object_messageMediaVideo' => 'Message media video', 'object_messageMediaVideo_param_video_type_Video' => 'Video', 'object_messageMediaUnsupported_param_bytes_type_bytes' => 'Bytes', 'object_messageActionChatAddUser_param_user_id_type_int' => 'User ID', 'object_photo_param_user_id_type_int' => 'User ID', 'object_photo_param_caption_type_string' => 'Caption', 'object_photo_param_geo_type_GeoPoint' => 'Geo', 'object_videoEmpty' => 'Empty video', 'object_videoEmpty_param_id_type_long' => 'ID', 'object_video' => 'Video', 'object_video_param_id_type_long' => 'ID', 'object_video_param_access_hash_type_long' => 'Access hash', 'object_video_param_user_id_type_int' => 'User ID', 'object_video_param_date_type_int' => 'Date', 'object_video_param_caption_type_string' => 'Caption', 'object_video_param_duration_type_int' => 'Duration', 'object_video_param_mime_type_type_string' => 'Mime type', 'object_video_param_size_type_int' => 'Size', 'object_video_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_video_param_dc_id_type_int' => 'DC ID', 'object_video_param_w_type_int' => 'Width', 'object_video_param_h_type_int' => 'Height', 'object_auth.checkedPhone_param_phone_invited_type_Bool' => 'Phone invited?', 'object_auth.sentCode_param_phone_registered_type_Bool' => 'Phone registered?', 'object_auth.sentCode_param_send_call_timeout_type_int' => 'Send call timeout', 'object_auth.sentCode_param_is_password_type_Bool' => 'Is password?', 'object_auth.authorization_param_expires_type_int' => 'Expiration date', 'object_inputPeerNotifySettings_param_show_previews_type_Bool' => 'Show previews?', 'object_inputPeerNotifySettings_param_events_mask_type_int' => 'Events mask', 'object_peerNotifySettings_param_show_previews_type_Bool' => 'Show previews?', 'object_peerNotifySettings_param_events_mask_type_int' => 'Events mask', 'object_userFull_param_blocked_type_Bool' => 'Blocked?', 'object_userFull_param_real_first_name_type_string' => 'Real first name', 'object_userFull_param_real_last_name_type_string' => 'Real last name', 'object_contactSuggested' => 'Contact suggested', 'object_contactSuggested_param_user_id_type_int' => 'User ID', 'object_contactSuggested_param_mutual_contacts_type_int' => 'Mutual contacts', 'object_contactStatus_param_expires_type_int' => 'Expires', 'object_contacts.foreignLinkUnknown' => 'Foreign link unknown', 'object_contacts.foreignLinkRequested' => 'Foreign link requested', 'object_contacts.foreignLinkRequested_param_has_phone_type_Bool' => 'Has phone?', 'object_contacts.foreignLinkMutual' => 'Foreign link mutual', 'object_contacts.myLinkEmpty' => 'Empty my link', 'object_contacts.myLinkRequested' => 'My link requested', 'object_contacts.myLinkRequested_param_contact_type_Bool' => 'Contact?', 'object_contacts.myLinkContact' => 'My link contact', 'object_contacts.link_param_my_link_type_contacts.MyLink' => 'My link', 'object_contacts.link_param_foreign_link_type_contacts.ForeignLink' => 'Foreign link', 'object_contacts.suggested' => 'Suggested', 'object_contacts.suggested_param_results_type_Vector t' => 'Results', 'object_contacts.suggested_param_users_type_Vector t' => 'Users', 'object_messages.statedMessages' => 'Stated messages', 'object_messages.statedMessages_param_messages_type_Vector t' => 'Messages', 'object_messages.statedMessages_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessages_param_users_type_Vector t' => 'Users', 'object_messages.statedMessages_param_pts_type_int' => 'Pts', 'object_messages.statedMessages_param_seq_type_int' => 'Seq', 'object_messages.statedMessage' => 'Stated message', 'object_messages.statedMessage_param_message_type_Message' => 'Message', 'object_messages.statedMessage_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessage_param_users_type_Vector t' => 'Users', 'object_messages.statedMessage_param_pts_type_int' => 'Pts', 'object_messages.statedMessage_param_seq_type_int' => 'Seq', 'object_messages.sentMessage' => 'Sent message', 'object_messages.sentMessage_param_id_type_int' => 'ID', 'object_messages.sentMessage_param_date_type_int' => 'Date', 'object_messages.sentMessage_param_pts_type_int' => 'Pts', 'object_messages.sentMessage_param_seq_type_int' => 'Seq', 'object_messages.chats_param_users_type_Vector t' => 'Users', 'object_messages.affectedHistory_param_seq_type_int' => 'Seq', 'object_inputMessagesFilterPhotoVideoDocuments' => 'Messages filter photo video documents', 'object_inputMessagesFilterAudio' => 'Messages filter audio', 'object_inputMessagesFilterAudioDocuments' => 'Messages filter audio documents', 'object_updateReadMessages' => 'Update read messages', 'object_updateReadMessages_param_messages_type_Vector t' => 'Messages', 'object_updateReadMessages_param_pts_type_int' => 'Pts', 'object_updateUserStatus' => 'Update user status', 'object_updateUserStatus_param_user_id_type_int' => 'User ID', 'object_updateUserStatus_param_status_type_UserStatus' => 'Status', 'object_updateContactLink_param_my_link_type_contacts.MyLink' => 'My link', 'object_updateContactLink_param_foreign_link_type_contacts.ForeignLink' => 'Foreign link', 'object_updateNewAuthorization' => 'Update new authorization', 'object_updateNewAuthorization_param_auth_key_id_type_long' => 'Auth key ID', 'object_updateNewAuthorization_param_date_type_int' => 'Date', 'object_updateNewAuthorization_param_device_type_string' => 'Device', 'object_updateNewAuthorization_param_location_type_string' => 'Location', 'object_updateShortMessage_param_from_id_type_int' => 'From ID', 'object_updateShortMessage_param_seq_type_int' => 'Seq', 'object_updateShortChatMessage_param_seq_type_int' => 'Seq', 'object_dcOption_param_hostname_type_string' => 'Hostname', 'object_config_param_broadcast_size_max_type_int' => 'Broadcast size max', 'object_messages.statedMessagesLinks' => 'Stated messages links', 'object_messages.statedMessagesLinks_param_messages_type_Vector t' => 'Messages', 'object_messages.statedMessagesLinks_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessagesLinks_param_users_type_Vector t' => 'Users', 'object_messages.statedMessagesLinks_param_links_type_Vector t' => 'Links', 'object_messages.statedMessagesLinks_param_pts_type_int' => 'Pts', 'object_messages.statedMessagesLinks_param_seq_type_int' => 'Seq', 'object_messages.statedMessageLink' => 'Stated message link', 'object_messages.statedMessageLink_param_message_type_Message' => 'Message', 'object_messages.statedMessageLink_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessageLink_param_users_type_Vector t' => 'Users', 'object_messages.statedMessageLink_param_links_type_Vector t' => 'Links', 'object_messages.statedMessageLink_param_pts_type_int' => 'Pts', 'object_messages.statedMessageLink_param_seq_type_int' => 'Seq', 'object_messages.sentMessageLink' => 'Sent message link', 'object_messages.sentMessageLink_param_id_type_int' => 'ID', 'object_messages.sentMessageLink_param_date_type_int' => 'Date', 'object_messages.sentMessageLink_param_pts_type_int' => 'Pts', 'object_messages.sentMessageLink_param_seq_type_int' => 'Seq', 'object_messages.sentMessageLink_param_links_type_Vector t' => 'Links', 'object_inputMediaUploadedAudio' => 'Media uploaded audio', 'object_inputMediaUploadedAudio_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedAudio_param_duration_type_int' => 'Duration', 'object_inputMediaUploadedAudio_param_mime_type_type_string' => 'Mime type', 'object_inputMediaAudio' => 'Media audio', 'object_inputMediaAudio_param_id_type_InputAudio' => 'ID', 'object_inputMediaUploadedDocument_param_file_name_type_string' => 'File name', 'object_inputMediaUploadedThumbDocument' => 'Media uploaded thumb document', 'object_inputMediaUploadedThumbDocument_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedThumbDocument_param_thumb_type_InputFile' => 'Thumbnail', 'object_inputMediaUploadedThumbDocument_param_file_name_type_string' => 'File name', 'object_inputMediaUploadedThumbDocument_param_mime_type_type_string' => 'Mime type', 'object_messageMediaAudio' => 'Message media audio', 'object_messageMediaAudio_param_audio_type_Audio' => 'Audio', 'object_inputAudioEmpty' => 'Empty input audio', 'object_inputAudio' => 'Audio', 'object_inputAudio_param_id_type_long' => 'ID', 'object_inputAudio_param_access_hash_type_long' => 'Access hash', 'object_inputAudioFileLocation' => 'Audio file location', 'object_inputAudioFileLocation_param_id_type_long' => 'ID', 'object_inputAudioFileLocation_param_access_hash_type_long' => 'Access hash', 'object_audioEmpty' => 'Empty audio', 'object_audioEmpty_param_id_type_long' => 'ID', 'object_audio' => 'Audio', 'object_audio_param_id_type_long' => 'ID', 'object_audio_param_access_hash_type_long' => 'Access hash', 'object_audio_param_user_id_type_int' => 'User ID', 'object_audio_param_date_type_int' => 'Date', 'object_audio_param_duration_type_int' => 'Duration', 'object_audio_param_mime_type_type_string' => 'Mime type', 'object_audio_param_size_type_int' => 'Size', 'object_audio_param_dc_id_type_int' => 'DC ID', 'object_document_param_user_id_type_int' => 'User ID', 'object_document_param_file_name_type_string' => 'File name', 'object_auth.sentAppCode' => 'Sent app code', 'object_auth.sentAppCode_param_phone_registered_type_Bool' => 'Phone registered?', 'object_auth.sentAppCode_param_phone_code_hash_type_string' => 'Phone code hash', 'object_auth.sentAppCode_param_send_call_timeout_type_int' => 'Send call timeout', 'object_auth.sentAppCode_param_is_password_type_Bool' => 'Is password?', 'object_contactFound' => 'Contact found', 'object_contactFound_param_user_id_type_int' => 'User ID', 'object_updateServiceNotification_param_popup_type_Bool' => 'Popup?', 'object_inputMediaUploadedThumbDocument_param_attributes_type_Vector t' => 'Attributes', 'object_userStatusRecently' => 'User status recently', 'object_userStatusLastWeek' => 'User status last week', 'object_userStatusLastMonth' => 'User status last month', 'object_account.sentChangePhoneCode' => 'Sent change phone code', 'object_account.sentChangePhoneCode_param_phone_code_hash_type_string' => 'Phone code hash', 'object_account.sentChangePhoneCode_param_send_call_timeout_type_int' => 'Send call timeout', 'object_messages.allStickers_param_hash_type_string' => 'Hash', 'object_messages.allStickers_param_packs_type_Vector t' => 'Packs', 'object_messages.allStickers_param_documents_type_Vector t' => 'Documents', 'object_message_param_fwd_from_id_type_int' => 'Forwarded from ID', 'object_message_param_fwd_date_type_int' => 'Forwarded date', 'object_chatLocated' => 'Chat located', 'object_chatLocated_param_chat_id_type_int' => 'Chat ID', 'object_chatLocated_param_distance_type_int' => 'Distance', 'object_messages.messageEmpty' => 'Empty message', 'object_messages.statedMessages_param_pts_count_type_int' => 'Pts count', 'object_messages.statedMessage_param_pts_count_type_int' => 'Pts count', 'object_messages.sentMessage_param_pts_count_type_int' => 'Pts count', 'object_updateReadMessages_param_pts_count_type_int' => 'Pts count', 'object_updateShortMessage_param_fwd_from_id_type_int' => 'Fwd from ID', 'object_updateShortMessage_param_fwd_date_type_int' => 'Fwd date', 'object_updateShortChatMessage_param_fwd_from_id_type_int' => 'Fwd from ID', 'object_updateShortChatMessage_param_fwd_date_type_int' => 'Fwd date', 'object_messages.statedMessagesLinks_param_pts_count_type_int' => 'Pts count', 'object_messages.statedMessageLink_param_pts_count_type_int' => 'Pts count', 'object_messages.sentMessageLink_param_pts_count_type_int' => 'Pts count', 'object_inputGeoChat' => 'Geo chat', 'object_inputGeoChat_param_chat_id_type_int' => 'Chat ID', 'object_inputGeoChat_param_access_hash_type_long' => 'Access hash', 'object_inputNotifyGeoChatPeer' => 'Notify geo chat peer', 'object_inputNotifyGeoChatPeer_param_peer_type_InputGeoChat' => 'Peer', 'object_geoChat' => 'Geo chat', 'object_geoChat_param_id_type_int' => 'ID', 'object_geoChat_param_access_hash_type_long' => 'Access hash', 'object_geoChat_param_title_type_string' => 'Title', 'object_geoChat_param_address_type_string' => 'Address', 'object_geoChat_param_venue_type_string' => 'Venue', 'object_geoChat_param_geo_type_GeoPoint' => 'Geo', 'object_geoChat_param_photo_type_ChatPhoto' => 'Photo', 'object_geoChat_param_participants_count_type_int' => 'Participants count', 'object_geoChat_param_date_type_int' => 'Date', 'object_geoChat_param_checked_in_type_Bool' => 'Checked in?', 'object_geoChat_param_version_type_int' => 'Version', 'object_geoChatMessageEmpty' => 'Empty geo chat message', 'object_geoChatMessageEmpty_param_chat_id_type_int' => 'Chat ID', 'object_geoChatMessageEmpty_param_id_type_int' => 'ID', 'object_geoChatMessage' => 'Geo chat message', 'object_geoChatMessage_param_chat_id_type_int' => 'Chat ID', 'object_geoChatMessage_param_id_type_int' => 'ID', 'object_geoChatMessage_param_from_id_type_int' => 'From ID', 'object_geoChatMessage_param_date_type_int' => 'Date', 'object_geoChatMessage_param_message_type_string' => 'Message', 'object_geoChatMessage_param_media_type_MessageMedia' => 'Media', 'object_geoChatMessageService' => 'Geo chat message service', 'object_geoChatMessageService_param_chat_id_type_int' => 'Chat ID', 'object_geoChatMessageService_param_id_type_int' => 'ID', 'object_geoChatMessageService_param_from_id_type_int' => 'From ID', 'object_geoChatMessageService_param_date_type_int' => 'Date', 'object_geoChatMessageService_param_action_type_MessageAction' => 'Action', 'object_geochats.statedMessage' => 'Stated message', 'object_geochats.statedMessage_param_message_type_GeoChatMessage' => 'Message', 'object_geochats.statedMessage_param_chats_type_Vector t' => 'Chats', 'object_geochats.statedMessage_param_users_type_Vector t' => 'Users', 'object_geochats.statedMessage_param_seq_type_int' => 'Seq', 'object_geochats.located' => 'Located', 'object_geochats.located_param_results_type_Vector t' => 'Results', 'object_geochats.located_param_messages_type_Vector t' => 'Messages', 'object_geochats.located_param_chats_type_Vector t' => 'Chats', 'object_geochats.located_param_users_type_Vector t' => 'Users', 'object_geochats.messages' => 'Messages', 'object_geochats.messages_param_messages_type_Vector t' => 'Messages', 'object_geochats.messages_param_chats_type_Vector t' => 'Chats', 'object_geochats.messages_param_users_type_Vector t' => 'Users', 'object_geochats.messagesSlice' => 'Messages slice', 'object_geochats.messagesSlice_param_count_type_int' => 'Count', 'object_geochats.messagesSlice_param_messages_type_Vector t' => 'Messages', 'object_geochats.messagesSlice_param_chats_type_Vector t' => 'Chats', 'object_geochats.messagesSlice_param_users_type_Vector t' => 'Users', 'object_messageActionGeoChatCreate' => 'Message action geo chat create', 'object_messageActionGeoChatCreate_param_title_type_string' => 'Title', 'object_messageActionGeoChatCreate_param_address_type_string' => 'Address', 'object_messageActionGeoChatCheckin' => 'Message action geo chat checkin', 'object_updateNewGeoChatMessage' => 'Update new geo chat message', 'object_updateNewGeoChatMessage_param_message_type_GeoChatMessage' => 'Message', 'object_messages.sentMessage_param_media_type_MessageMedia' => 'Media', 'object_messages.sentMessageLink_param_media_type_MessageMedia' => 'Media', 'object_inputMediaUploadedPhoto_param_caption_type_string' => 'Caption', 'object_inputMediaPhoto_param_caption_type_string' => 'Caption', 'object_inputMediaUploadedVideo_param_caption_type_string' => 'Caption', 'object_inputMediaUploadedThumbVideo_param_caption_type_string' => 'Caption', 'object_inputMediaVideo_param_caption_type_string' => 'Caption', 'object_messageMediaPhoto_param_caption_type_string' => 'Caption', 'object_messageMediaVideo_param_caption_type_string' => 'Caption', 'object_botCommand' => 'Bot command', 'object_botCommand_param_command_type_string' => 'Command', 'object_botCommand_param_description_type_string' => 'Description', 'object_botInfoEmpty' => 'Empty bot info', 'object_botInfo_param_version_type_int' => 'Version', 'object_botInfo_param_share_text_type_string' => 'Share text', 'object_help.appChangelogEmpty' => 'Empty app changelog', 'object_help.appChangelog' => 'App changelog', 'object_help.appChangelog_param_text_type_string' => 'Text', 'object_message_param_fwd_from_id_type_Peer' => 'Forwarded from ID', 'object_updateShortMessage_param_fwd_from_id_type_Peer' => 'Fwd from ID', 'object_updateShortChatMessage_param_fwd_from_id_type_Peer' => 'Fwd from ID', 'object_channelFull_param_unread_important_count_type_int' => 'Unread important count', 'object_dialogChannel' => 'Dialog channel', 'object_dialogChannel_param_peer_type_Peer' => 'Peer', 'object_dialogChannel_param_top_message_type_int' => 'Top message', 'object_dialogChannel_param_top_important_message_type_int' => 'Top important message', 'object_dialogChannel_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_dialogChannel_param_unread_count_type_int' => 'Unread count', 'object_dialogChannel_param_unread_important_count_type_int' => 'Unread important count', 'object_dialogChannel_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_dialogChannel_param_pts_type_int' => 'Pts', 'object_messageGroup' => 'Message group', 'object_messageGroup_param_min_id_type_int' => 'Min ID', 'object_messageGroup_param_max_id_type_int' => 'Max ID', 'object_messageGroup_param_count_type_int' => 'Count', 'object_messageGroup_param_date_type_int' => 'Date', 'object_messages.channelMessages_param_collapsed_type_Vector t' => 'Collapsed', 'object_updateChannelGroup' => 'Update channel group', 'object_updateChannelGroup_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelGroup_param_group_type_MessageGroup' => 'Group', 'object_updates.channelDifferenceTooLong_param_top_important_message_type_int' => 'Top important message', 'object_updates.channelDifferenceTooLong_param_unread_important_count_type_int' => 'Unread important count', 'object_channelMessagesFilterCollapsed' => 'Channel messages filter collapsed', 'object_channelParticipantModerator' => 'Channel participant moderator', 'object_channelParticipantModerator_param_user_id_type_int' => 'User ID', 'object_channelParticipantModerator_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantModerator_param_date_type_int' => 'Date', 'object_channelParticipantEditor' => 'Channel participant editor', 'object_channelParticipantEditor_param_user_id_type_int' => 'User ID', 'object_channelParticipantEditor_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantEditor_param_date_type_int' => 'Date', 'object_channelParticipantKicked' => 'Channel participant kicked', 'object_channelParticipantKicked_param_user_id_type_int' => 'User ID', 'object_channelParticipantKicked_param_kicked_by_type_int' => 'Kicked by', 'object_channelParticipantKicked_param_date_type_int' => 'Date', 'object_channelRoleEmpty' => 'Empty channel role', 'object_channelRoleModerator' => 'Channel role moderator', 'object_channelRoleEditor' => 'Channel role editor', 'object_inputChatEmpty' => 'Empty input chat', 'object_inputChat' => 'Chat', 'object_inputChat_param_chat_id_type_int' => 'Chat ID', 'object_updateReadChannelInbox_param_peer_type_Peer' => 'Peer', 'object_updateDeleteChannelMessages_param_peer_type_Peer' => 'Peer', 'object_message_param_unread_type_true' => 'Unread?', 'object_messageService_param_unread_type_true' => 'Unread?', 'object_updateShortMessage_param_unread_type_true' => 'Unread?', 'object_updateShortChatMessage_param_unread_type_true' => 'Unread?', 'object_stickerSet_param_disabled_type_true' => 'Disabled?', 'object_updateShortSentMessage_param_unread_type_true' => 'Unread?', 'object_channel_param_kicked_type_true' => 'Kicked?', 'object_channel_param_moderator_type_true' => 'Moderator?', 'object_channelMessagesFilter_param_important_only_type_true' => 'Important only?', 'object_messageActionChatDeactivate' => 'Message action chat deactivate', 'object_messageActionChatActivate' => 'Message action chat activate', 'object_user_param_restiction_reason_type_string' => 'Restiction reason', 'object_channel_param_restiction_reason_type_string' => 'Restiction reason', 'object_webPageExternal' => 'Web page external', 'object_webPageExternal_param_url_type_string' => 'URL', 'object_webPageExternal_param_display_url_type_string' => 'Display URL', 'object_webPageExternal_param_type_type_string' => 'Type', 'object_webPageExternal_param_title_type_string' => 'Title', 'object_webPageExternal_param_description_type_string' => 'Description', 'object_webPageExternal_param_thumb_url_type_string' => 'Thumbnail URL', 'object_webPageExternal_param_content_url_type_string' => 'Content URL', 'object_webPageExternal_param_w_type_int' => 'Width', 'object_webPageExternal_param_h_type_int' => 'Height', 'object_webPageExternal_param_duration_type_int' => 'Duration', 'object_foundGif_param_webpage_type_WebPage' => 'Webpage', 'object_inputMediaUploadedDocument_param_caption_type_string' => 'Caption', 'object_inputMediaUploadedThumbDocument_param_caption_type_string' => 'Caption', 'object_inputMediaDocument_param_caption_type_string' => 'Caption', 'object_messageMediaDocument_param_caption_type_string' => 'Caption', 'object_inputBotInlineMessageMediaAuto_param_caption_type_string' => 'Caption', 'object_botInlineMessageMediaAuto_param_caption_type_string' => 'Caption', 'object_botInlineMediaResultDocument' => 'Bot inline media result document', 'object_botInlineMediaResultDocument_param_id_type_string' => 'ID', 'object_botInlineMediaResultDocument_param_type_type_string' => 'Type', 'object_botInlineMediaResultDocument_param_document_type_Document' => 'Document', 'object_botInlineMediaResultDocument_param_send_message_type_BotInlineMessage' => 'Send message', 'object_botInlineMediaResultPhoto' => 'Bot inline media result photo', 'object_botInlineMediaResultPhoto_param_id_type_string' => 'ID', 'object_botInlineMediaResultPhoto_param_type_type_string' => 'Type', 'object_botInlineMediaResultPhoto_param_photo_type_Photo' => 'Photo', 'object_botInlineMediaResultPhoto_param_send_message_type_BotInlineMessage' => 'Send message', 'object_inputMediaVideo_param_video_type_InputVideo' => 'Video', 'object_inputMediaAudio_param_audio_type_InputAudio' => 'Audio', 'object_inputMediaDocument_param_document_id_type_InputDocument' => 'Document ID', 'object_inputGeoPoint_param_latitude_type_double' => 'Latitude', 'object_inputGeoPoint_param_longitude_type_double' => 'Longitude', 'object_geoPoint_param_longitude_type_double' => 'Longitude', 'object_geoPoint_param_latitude_type_double' => 'Latitude', 'object_updateNewEncryptedMessage_param_encr_message_type_EncryptedMessage' => 'Encr message', 'object_updateEncryption_param_encr_chat_type_EncryptedChat' => 'Encr chat', 'object_updateNotifySettings_param_notify_peer_type_NotifyPeer' => 'Notify peer', 'object_updateServiceNotification_param_message_text_type_string' => 'Message text', 'object_updateNewChannelMessage_param_channel_pts_type_int' => 'Channel pts', 'object_updateNewChannelMessage_param_channel_pts_count_type_int' => 'Channel pts count', 'object_updateDeleteChannelMessages_param_channel_pts_type_int' => 'Channel pts', 'object_updateDeleteChannelMessages_param_channel_pts_count_type_int' => 'Channel pts count', 'object_updates.channelDifferenceEmpty_param_channel_pts_type_int' => 'Channel pts', 'object_updates.channelDifferenceTooLong_param_channel_pts_type_int' => 'Channel pts', 'object_updates.channelDifference_param_channel_pts_type_int' => 'Channel pts', 'object_privacyKeyChatInvite' => 'Privacy key chat invite', 'object_inputMediaUploadedThumbDocument_param_stickers_type_Vector t' => 'Stickers', 'object_inputMediaPhotoExternal_param_caption_type_string' => 'Caption', 'object_inputMediaDocumentExternal_param_caption_type_string' => 'Caption', 'object_destroy_auth_key_ok' => 'Destroy auth key ok', 'object_destroy_auth_key_none' => 'Destroy auth key none', 'object_destroy_auth_key_fail' => 'Destroy auth key fail', 'object_help.appChangelog_param_message_type_string' => 'Message', 'object_help.appChangelog_param_media_type_MessageMedia' => 'Media', 'object_help.appChangelog_param_entities_type_Vector t' => 'Entities', 'object_pageBlockParagraph' => 'Page block paragraph', 'object_pageBlockParagraph_param_text_type_RichText' => 'Text', 'object_pageBlockPreformatted' => 'Page block preformatted', 'object_pageBlockPreformatted_param_text_type_RichText' => 'Text', 'object_pageBlockPreformatted_param_language_type_string' => 'Language', 'object_pageBlockDivider' => 'Page block divider', 'object_pageBlockAnchor' => 'Page block anchor', 'object_pageBlockAnchor_param_name_type_string' => 'Name', 'object_pageBlockCover' => 'Page block cover', 'object_pageBlockCover_param_cover_type_PageBlock' => 'Cover', 'object_pagePart_param_videos_type_Vector t' => 'Videos', 'object_pageFull_param_videos_type_Vector t' => 'Videos', 'object_phoneCallRequested_param_g_a_type_bytes' => 'G a', 'object_resPQ_param_pq_type_string' => 'Pq', 'object_p_q_inner_data_param_pq_type_string' => 'Pq', 'object_p_q_inner_data_param_p_type_string' => 'P', 'object_p_q_inner_data_param_q_type_string' => 'Q', 'object_server_DH_params_ok_param_encrypted_answer_type_string' => 'Encrypted answer', 'object_server_DH_inner_data_param_dh_prime_type_string' => 'Dh prime', 'object_server_DH_inner_data_param_g_a_type_string' => 'G a', 'object_client_DH_inner_data_param_g_b_type_string' => 'G b', 'object_msgs_state_info_param_info_type_string' => 'Info', 'object_msgs_all_info_param_info_type_string' => 'Info', 'object_http_wait' => 'Http wait', 'object_http_wait_param_max_delay_type_int' => 'Max delay', 'object_http_wait_param_wait_after_type_int' => 'Wait after', 'object_http_wait_param_max_wait_type_int' => 'Max wait', 'object_ipPort' => 'Ip port', 'object_ipPort_param_ipv4_type_int' => 'Ipv4', 'object_ipPort_param_port_type_int' => 'Port', 'object_help.configSimple' => 'Config simple', 'object_help.configSimple_param_date_type_int' => 'Date', 'object_help.configSimple_param_expires_type_int' => 'Expires', 'object_help.configSimple_param_dc_id_type_int' => 'DC ID', 'object_help.configSimple_param_ip_port_list_type_Vector t' => 'Ip port list', 'object_inputMessagesFilterMyMentionsUnread' => 'Messages filter my mentions unread', 'method_initConnection_param_proxy_type_InputClientProxy' => 'The current proxy', 'method_account.registerDevice_param_secret_type_bytes' => 'Secret', 'method_account.getAllSecureValues' => 'Get all secure telegram passport values', 'method_account.getSecureValue' => 'Get secure value for telegram passport', 'method_account.getSecureValue_param_types_type_Vector t' => 'Get telegram passport secure parameters', 'method_account.saveSecureValue' => 'Save telegram passport secure value', 'method_account.saveSecureValue_param_value_type_InputSecureValue' => 'Encrypted value', 'method_account.saveSecureValue_param_secure_secret_id_type_long' => 'Secret', 'method_account.deleteSecureValue' => 'Delete secure telegram passport value', 'method_account.deleteSecureValue_param_types_type_Vector t' => 'The values to delete', 'method_account.getAuthorizationForm' => 'Bots only: get telegram passport authorization form', 'method_account.getAuthorizationForm_param_bot_id_type_int' => 'Bot ID', 'method_account.getAuthorizationForm_param_scope_type_string' => 'Scope', 'method_account.getAuthorizationForm_param_public_key_type_string' => 'Bot\'s public key', 'method_account.acceptAuthorization' => 'Accept telegram passport authorization', 'method_account.acceptAuthorization_param_bot_id_type_int' => 'Bot ID', 'method_account.acceptAuthorization_param_scope_type_string' => 'Scope', 'method_account.acceptAuthorization_param_public_key_type_string' => 'The bot\'s RSA public key', 'method_account.acceptAuthorization_param_value_hashes_type_Vector t' => 'Hashes of the encrypted credentials', 'method_account.acceptAuthorization_param_credentials_type_SecureCredentialsEncrypted' => 'Encrypted secure credentials', 'method_account.sendVerifyPhoneCode' => 'Send phone verification code', 'method_account.sendVerifyPhoneCode_param_allow_flashcall_type_true' => 'Allow phone calls?', 'method_account.sendVerifyPhoneCode_param_phone_number_type_string' => 'The phone number', 'method_account.sendVerifyPhoneCode_param_current_number_type_Bool' => 'Is this the current number?', 'method_account.verifyPhone' => 'Verify phone number', 'method_account.verifyPhone_param_phone_number_type_string' => 'The phone number', 'method_account.verifyPhone_param_phone_code_hash_type_string' => 'The phone code hash returned by account.sendVerifyPhoneCode', 'method_account.verifyPhone_param_phone_code_type_string' => 'The phone code type returned by account.sendVerifyPhoneCode', 'method_account.sendVerifyEmailCode' => 'Send email verification code', 'method_account.sendVerifyEmailCode_param_email_type_string' => 'Email', 'method_account.verifyEmail' => 'Verify email address', 'method_account.verifyEmail_param_email_type_string' => 'The email address', 'method_account.verifyEmail_param_code_type_string' => 'The received code', 'method_users.setSecureValueErrors' => 'Set secure value error for telegram passport', 'method_users.setSecureValueErrors_param_id_type_InputUser' => 'The user ID', 'method_users.setSecureValueErrors_param_errors_type_Vector t' => 'The errors', 'method_messages.search_param_hash_type_int' => 'IDs of messages you already fetched', 'method_messages.report' => 'Report a message', 'method_messages.report_param_peer_type_InputPeer' => 'The user that sent the messages', 'method_messages.report_param_id_type_Vector t' => 'The messages to report', 'method_messages.report_param_reason_type_ReportReason' => 'The reason why you\'re sending this report', 'method_messages.getStickers_param_hash_type_int' => 'IDs of previously fetched stickers', 'method_messages.editMessage_param_media_type_InputMedia' => 'The media to substitute', 'method_messages.editInlineBotMessage_param_media_type_InputMedia' => 'The media to substitute', 'method_messages.toggleDialogPin_param_peer_type_InputDialogPeer' => 'The dialog to pin', 'method_messages.getRecentLocations_param_hash_type_int' => 'IDs of previously fetched locations', 'method_messages.searchStickerSets' => 'Find a sticker set', 'method_messages.searchStickerSets_param_exclude_featured_type_true' => 'Exclude featured sticker sets from the search?', 'method_messages.searchStickerSets_param_q_type_string' => 'The search query', 'method_messages.searchStickerSets_param_hash_type_int' => 'Ids of stickers you already cached', 'method_upload.getFileHashes' => 'Get file hashes', 'method_upload.getFileHashes_param_location_type_InputFileLocation' => 'The file', 'method_upload.getFileHashes_param_offset_type_int' => 'Offset', 'method_help.getProxyData' => 'Get information about the current proxy', 'method_help.getTermsOfServiceUpdate' => 'Get updated TOS', 'method_help.acceptTermsOfService' => 'Accept telegram\'s TOS', 'method_help.acceptTermsOfService_param_id_type_DataJSON' => 'TOS', 'method_help.getDeepLinkInfo' => 'Get deep link info', 'method_help.getDeepLinkInfo_param_path_type_string' => 'Deep link', 'object_inputSecureFileLocation' => 'Secure file location', 'object_inputSecureFileLocation_param_id_type_long' => 'ID', 'object_inputSecureFileLocation_param_access_hash_type_long' => 'Access hash', 'object_messageActionBotAllowed' => 'Message action bot allowed', 'object_messageActionBotAllowed_param_domain_type_string' => 'Domain', 'object_messageActionSecureValuesSentMe' => 'Message action secure values sent me', 'object_messageActionSecureValuesSentMe_param_values_type_Vector t' => 'Values', 'object_messageActionSecureValuesSentMe_param_credentials_type_SecureCredentialsEncrypted' => 'Credentials', 'object_messageActionSecureValuesSent' => 'Message action secure values sent', 'object_messageActionSecureValuesSent_param_types_type_Vector t' => 'Types', 'object_auth.sentCode_param_terms_of_service_type_help.TermsOfService' => 'Terms of service', 'object_inputPeerNotifySettings_param_silent_type_Bool' => 'Silent?', 'object_peerNotifySettings_param_silent_type_Bool' => 'Silent?', 'object_updateDialogPinned_param_peer_type_DialogPeer' => 'Peer', 'object_upload.fileCdnRedirect_param_file_hashes_type_Vector t' => 'File hashes', 'object_dcOption_param_secret_type_bytes' => 'Secret', 'object_config_param_preload_featured_stickers_type_true' => 'Preload featured stickers?', 'object_config_param_ignore_phone_entities_type_true' => 'Ignore phone entities?', 'object_config_param_revoke_pm_inbox_type_true' => 'Revoke pm inbox?', 'object_config_param_blocked_mode_type_true' => 'Blocked mode?', 'object_config_param_revoke_time_limit_type_int' => 'Revoke time limit', 'object_config_param_revoke_pm_time_limit_type_int' => 'Revoke pm time limit', 'object_config_param_autoupdate_url_prefix_type_string' => 'Autoupdate URL prefix', 'object_messages.stickers_param_hash_type_int' => 'Hash', 'object_account.noPassword_param_new_secure_salt_type_bytes' => 'New secure salt', 'object_account.noPassword_param_secure_random_type_bytes' => 'Secure random', 'object_account.password_param_has_recovery_type_true' => 'Has recovery?', 'object_account.password_param_has_secure_values_type_true' => 'Has secure values?', 'object_account.password_param_new_secure_salt_type_bytes' => 'New secure salt', 'object_account.password_param_secure_random_type_bytes' => 'Secure random', 'object_account.passwordSettings_param_secure_salt_type_bytes' => 'Secure salt', 'object_account.passwordSettings_param_secure_secret_type_bytes' => 'Secure secret', 'object_account.passwordSettings_param_secure_secret_id_type_long' => 'Secure secret ID', 'object_account.passwordInputSettings_param_new_secure_salt_type_bytes' => 'New secure salt', 'object_account.passwordInputSettings_param_new_secure_secret_type_bytes' => 'New secure secret', 'object_account.passwordInputSettings_param_new_secure_secret_id_type_long' => 'New secure secret ID', 'object_stickerSet_param_installed_date_type_int' => 'Installed date', 'object_messageEntityPhone' => 'Message entity phone', 'object_messageEntityPhone_param_offset_type_int' => 'Offset', 'object_messageEntityPhone_param_length_type_int' => 'Length', 'object_messageEntityCashtag' => 'Message entity cashtag', 'object_messageEntityCashtag_param_offset_type_int' => 'Offset', 'object_messageEntityCashtag_param_length_type_int' => 'Length', 'object_help.termsOfService_param_popup_type_true' => 'Popup?', 'object_help.termsOfService_param_id_type_DataJSON' => 'ID', 'object_help.termsOfService_param_entities_type_Vector t' => 'Entities', 'object_help.termsOfService_param_min_age_confirm_type_int' => 'Min age confirm', 'object_inputBotInlineMessageMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_inputBotInlineResult_param_thumb_type_InputWebDocument' => 'Thumbnail', 'object_inputBotInlineResult_param_content_type_InputWebDocument' => 'Content', 'object_botInlineMessageMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_botInlineResult_param_thumb_type_WebDocument' => 'Thumbnailnail', 'object_botInlineResult_param_content_type_WebDocument' => 'Content', 'object_messages.recentStickers_param_packs_type_Vector t' => 'Packs', 'object_messages.recentStickers_param_dates_type_Vector t' => 'Dates', 'object_webDocumentNoProxy' => 'Web document no proxy', 'object_webDocumentNoProxy_param_url_type_string' => 'URL', 'object_webDocumentNoProxy_param_size_type_int' => 'Size', 'object_webDocumentNoProxy_param_mime_type_type_string' => 'Mime type', 'object_webDocumentNoProxy_param_attributes_type_Vector t' => 'Attributes', 'object_inputWebFileGeoPointLocation' => 'Web file geo point location', 'object_inputWebFileGeoPointLocation_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputWebFileGeoPointLocation_param_w_type_int' => 'Width', 'object_inputWebFileGeoPointLocation_param_h_type_int' => 'Height', 'object_inputWebFileGeoPointLocation_param_zoom_type_int' => 'Zoom', 'object_inputWebFileGeoPointLocation_param_scale_type_int' => 'Scale', 'object_inputWebFileGeoMessageLocation' => 'Web file geo message location', 'object_inputWebFileGeoMessageLocation_param_peer_type_InputPeer' => 'Peer', 'object_inputWebFileGeoMessageLocation_param_msg_id_type_int' => 'Msg ID', 'object_inputWebFileGeoMessageLocation_param_w_type_int' => 'Width', 'object_inputWebFileGeoMessageLocation_param_h_type_int' => 'Height', 'object_inputWebFileGeoMessageLocation_param_zoom_type_int' => 'Zoom', 'object_inputWebFileGeoMessageLocation_param_scale_type_int' => 'Scale', 'object_channelAdminRights_param_manage_call_type_true' => 'Manage group calls', 'object_inputDialogPeer' => 'Dialog peer', 'object_inputDialogPeer_param_peer_type_InputPeer' => 'Peer', 'object_dialogPeer' => 'Dialog peer', 'object_dialogPeer_param_peer_type_Peer' => 'Peer', 'object_messages.foundStickerSetsNotModified' => 'Found sticker sets not modified', 'object_messages.foundStickerSets' => 'Found sticker sets', 'object_messages.foundStickerSets_param_hash_type_int' => 'Hash', 'object_messages.foundStickerSets_param_sets_type_Vector t' => 'Sets', 'object_fileHash' => 'File hash', 'object_fileHash_param_offset_type_int' => 'Offset', 'object_fileHash_param_limit_type_int' => 'Limit', 'object_fileHash_param_hash_type_bytes' => 'Hash', 'object_inputClientProxy' => 'Client proxy', 'object_inputClientProxy_param_address_type_string' => 'Address', 'object_inputClientProxy_param_port_type_int' => 'Port', 'object_help.proxyDataEmpty' => 'Empty proxy data', 'object_help.proxyDataEmpty_param_expires_type_int' => 'Expires', 'object_help.proxyDataPromo' => 'Proxy data promo', 'object_help.proxyDataPromo_param_expires_type_int' => 'Expires', 'object_help.proxyDataPromo_param_peer_type_Peer' => 'Peer', 'object_help.proxyDataPromo_param_chats_type_Vector t' => 'Chats', 'object_help.proxyDataPromo_param_users_type_Vector t' => 'Users', 'object_help.termsOfServiceUpdateEmpty' => 'Empty terms of service update', 'object_help.termsOfServiceUpdateEmpty_param_expires_type_int' => 'Expires', 'object_help.termsOfServiceUpdate' => 'Terms of service update', 'object_help.termsOfServiceUpdate_param_expires_type_int' => 'Expires', 'object_help.termsOfServiceUpdate_param_terms_of_service_type_help.TermsOfService' => 'Terms of service', 'object_inputSecureFileUploaded' => 'Secure file uploaded', 'object_inputSecureFileUploaded_param_id_type_long' => 'ID', 'object_inputSecureFileUploaded_param_parts_type_int' => 'Parts', 'object_inputSecureFileUploaded_param_md5_checksum_type_string' => 'Md5 checksum', 'object_inputSecureFileUploaded_param_file_hash_type_bytes' => 'File hash', 'object_inputSecureFileUploaded_param_secret_type_bytes' => 'Secret', 'object_inputSecureFile' => 'Secure file', 'object_inputSecureFile_param_id_type_long' => 'ID', 'object_inputSecureFile_param_access_hash_type_long' => 'Access hash', 'object_secureFileEmpty' => 'Empty secure file', 'object_secureFile' => 'Secure file', 'object_secureFile_param_id_type_long' => 'ID', 'object_secureFile_param_access_hash_type_long' => 'Access hash', 'object_secureFile_param_size_type_int' => 'Size', 'object_secureFile_param_dc_id_type_int' => 'DC ID', 'object_secureFile_param_date_type_int' => 'Date', 'object_secureFile_param_file_hash_type_bytes' => 'File hash', 'object_secureFile_param_secret_type_bytes' => 'Secret', 'object_secureData' => 'Secure data', 'object_secureData_param_data_type_bytes' => 'Data', 'object_secureData_param_data_hash_type_bytes' => 'Data hash', 'object_secureData_param_secret_type_bytes' => 'Secret', 'object_securePlainPhone' => 'Secure plain phone', 'object_securePlainPhone_param_phone_type_string' => 'Phone', 'object_securePlainEmail' => 'Secure plain email', 'object_securePlainEmail_param_email_type_string' => 'Email', 'object_secureValueTypePersonalDetails' => 'Secure value type personal details', 'object_secureValueTypePassport' => 'Secure value type passport', 'object_secureValueTypeDriverLicense' => 'Secure value type driver license', 'object_secureValueTypeIdentityCard' => 'Secure value type IDentity card', 'object_secureValueTypeInternalPassport' => 'Secure value type internal passport', 'object_secureValueTypeAddress' => 'Secure value type address', 'object_secureValueTypeUtilityBill' => 'Secure value type utility bill', 'object_secureValueTypeBankStatement' => 'Secure value type bank statement', 'object_secureValueTypeRentalAgreement' => 'Secure value type rental agreement', 'object_secureValueTypePassportRegistration' => 'Secure value type passport registration', 'object_secureValueTypeTemporaryRegistration' => 'Secure value type temporary registration', 'object_secureValueTypePhone' => 'Secure value type phone', 'object_secureValueTypeEmail' => 'Secure value type email', 'object_secureValue' => 'Secure value', 'object_secureValue_param_type_type_SecureValueType' => 'Type', 'object_secureValue_param_data_type_SecureData' => 'Data', 'object_secureValue_param_front_side_type_SecureFile' => 'Front side', 'object_secureValue_param_reverse_side_type_SecureFile' => 'Reverse side', 'object_secureValue_param_selfie_type_SecureFile' => 'Selfie', 'object_secureValue_param_files_type_Vector t' => 'Files', 'object_secureValue_param_plain_data_type_SecurePlainData' => 'Plain data', 'object_secureValue_param_hash_type_bytes' => 'Hash', 'object_inputSecureValue' => 'Secure value', 'object_inputSecureValue_param_type_type_SecureValueType' => 'Type', 'object_inputSecureValue_param_data_type_SecureData' => 'Data', 'object_inputSecureValue_param_front_side_type_InputSecureFile' => 'Front side', 'object_inputSecureValue_param_reverse_side_type_InputSecureFile' => 'Reverse side', 'object_inputSecureValue_param_selfie_type_InputSecureFile' => 'Selfie', 'object_inputSecureValue_param_files_type_Vector t' => 'Files', 'object_inputSecureValue_param_plain_data_type_SecurePlainData' => 'Plain data', 'object_secureValueHash' => 'Secure value hash', 'object_secureValueHash_param_type_type_SecureValueType' => 'Type', 'object_secureValueHash_param_hash_type_bytes' => 'Hash', 'object_secureValueErrorData' => 'Secure value error data', 'object_secureValueErrorData_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorData_param_data_hash_type_bytes' => 'Data hash', 'object_secureValueErrorData_param_field_type_string' => 'Field', 'object_secureValueErrorData_param_text_type_string' => 'Text', 'object_secureValueErrorFrontSide' => 'Secure value error front side', 'object_secureValueErrorFrontSide_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorFrontSide_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorFrontSide_param_text_type_string' => 'Text', 'object_secureValueErrorReverseSide' => 'Secure value error reverse side', 'object_secureValueErrorReverseSide_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorReverseSide_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorReverseSide_param_text_type_string' => 'Text', 'object_secureValueErrorSelfie' => 'Secure value error selfie', 'object_secureValueErrorSelfie_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorSelfie_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorSelfie_param_text_type_string' => 'Text', 'object_secureValueErrorFile' => 'Secure value error file', 'object_secureValueErrorFile_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorFile_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorFile_param_text_type_string' => 'Text', 'object_secureValueErrorFiles' => 'Secure value error files', 'object_secureValueErrorFiles_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorFiles_param_file_hash_type_Vector t' => 'File hash', 'object_secureValueErrorFiles_param_text_type_string' => 'Text', 'object_secureCredentialsEncrypted' => 'Secure credentials encrypted', 'object_secureCredentialsEncrypted_param_data_type_bytes' => 'Data', 'object_secureCredentialsEncrypted_param_hash_type_bytes' => 'Hash', 'object_secureCredentialsEncrypted_param_secret_type_bytes' => 'Secret', 'object_account.authorizationForm' => 'Telegram passport authorization form', 'object_account.authorizationForm_param_selfie_required_type_true' => 'Selfie required?', 'object_account.authorizationForm_param_required_types_type_Vector t' => 'Required types', 'object_account.authorizationForm_param_values_type_Vector t' => 'Values', 'object_account.authorizationForm_param_errors_type_Vector t' => 'Errors', 'object_account.authorizationForm_param_users_type_Vector t' => 'Users', 'object_account.authorizationForm_param_privacy_policy_url_type_string' => 'Privacy policy URL', 'object_account.sentEmailCode' => 'Sent email code', 'object_account.sentEmailCode_param_email_pattern_type_string' => 'Email pattern', 'object_account.sentEmailCode_param_length_type_int' => 'Length', 'object_help.deepLinkInfoEmpty' => 'Empty deep link info', 'object_help.deepLinkInfo' => 'Deep link info', 'object_help.deepLinkInfo_param_update_app_type_true' => 'Update app?', 'object_help.deepLinkInfo_param_message_type_string' => 'Message', 'object_help.deepLinkInfo_param_entities_type_Vector t' => 'Entities', 'method_invokeWithMessagesRange' => 'Invoke with messages range', 'method_invokeWithMessagesRange_param_range_type_MessageRange' => 'The range', 'method_invokeWithMessagesRange_param_query_type_!X' => 'The query', 'method_invokeWithTakeout' => 'Invoke method from takeout session', 'method_invokeWithTakeout_param_takeout_id_type_long' => 'The takeout session ID', 'method_invokeWithTakeout_param_query_type_!X' => 'The query', 'method_account.initTakeoutSession' => 'Start account exporting session', 'method_account.initTakeoutSession_param_contacts_type_true' => 'Export contacts?', 'method_account.initTakeoutSession_param_message_users_type_true' => 'Export users?', 'method_account.initTakeoutSession_param_message_chats_type_true' => 'Export chats?', 'method_account.initTakeoutSession_param_message_megagroups_type_true' => 'Export supergroups?', 'method_account.initTakeoutSession_param_message_channels_type_true' => 'Export channel messages?', 'method_account.initTakeoutSession_param_files_type_true' => 'Export files?', 'method_account.initTakeoutSession_param_file_max_size_type_int' => 'Export only files smaller than this size', 'method_account.finishTakeoutSession' => 'Finish account exporting session', 'method_account.finishTakeoutSession_param_success_type_true' => 'Did the data export succeed?', 'method_contacts.getSaved' => 'Get saved contacts', 'method_messages.getSplitRanges' => 'Get message ranges to fetch', 'method_channels.getLeftChannels' => 'Get all channels you left', 'method_channels.getLeftChannels_param_offset_type_int' => 'Offset', 'object_ipPortSecret' => 'Ip port secret', 'object_ipPortSecret_param_ipv4_type_int' => 'Ipv4', 'object_ipPortSecret_param_port_type_int' => 'Port', 'object_ipPortSecret_param_secret_type_bytes' => 'Secret', 'object_accessPointRule' => 'Access point rule', 'object_accessPointRule_param_phone_prefix_rules_type_string' => 'Phone prefix rules', 'object_accessPointRule_param_dc_id_type_int' => 'DC ID', 'object_accessPointRule_param_ips_type_vector' => 'Ips', 'object_help.configSimple_param_rules_type_vector' => 'Rules', 'object_inputTakeoutFileLocation' => 'Takeout file location', 'object_savedPhoneContact' => 'Saved phone contact', 'object_savedPhoneContact_param_phone_type_string' => 'Phone', 'object_savedPhoneContact_param_first_name_type_string' => 'First name', 'object_savedPhoneContact_param_last_name_type_string' => 'Last name', 'object_savedPhoneContact_param_date_type_int' => 'Date', 'object_account.takeout' => 'Takeout', 'object_account.takeout_param_id_type_long' => 'ID', 'method_contacts.toggleTopPeers' => 'Toggle top peers', 'method_contacts.toggleTopPeers_param_enabled_type_Bool' => 'Enable or disable top peer', 'method_messages.getDialogs_param_hash_type_int' => 'IDs of previously fetched dialogs', 'method_messages.markDialogUnread' => 'Mark dialog as unread ', 'method_messages.markDialogUnread_param_unread_type_true' => 'Should it be marked or unmarked as read', 'method_messages.markDialogUnread_param_peer_type_InputDialogPeer' => 'The dialog to mark as unread', 'method_messages.getDialogUnreadMarks' => 'Get dialogs marked as unread manually', 'object_inputMediaContact_param_vcard_type_string' => 'Vcard', 'object_messageMediaContact_param_vcard_type_string' => 'Vcard', 'object_dialog_param_unread_mark_type_true' => 'Unread mark?', 'object_geoPoint_param_access_hash_type_long' => 'Access hash', 'object_messages.dialogsNotModified' => 'Dialogs not modified', 'object_messages.dialogsNotModified_param_count_type_int' => 'Count', 'object_updateDialogUnreadMark' => 'Update dialog unread mark', 'object_updateDialogUnreadMark_param_unread_type_true' => 'Unread?', 'object_updateDialogUnreadMark_param_peer_type_DialogPeer' => 'Peer', 'object_config_param_dc_txt_domain_name_type_string' => 'DC txt domain name', 'object_config_param_gif_search_username_type_string' => 'Gif search username', 'object_config_param_venue_search_username_type_string' => 'Venue search username', 'object_config_param_img_search_username_type_string' => 'Img search username', 'object_config_param_static_maps_provider_type_string' => 'Static maps provider', 'object_config_param_caption_length_max_type_int' => 'Caption length max', 'object_config_param_message_length_max_type_int' => 'Message length max', 'object_config_param_webfile_dc_id_type_int' => 'Webfile DC ID', 'object_inputBotInlineMessageMediaContact_param_vcard_type_string' => 'Vcard', 'object_botInlineMessageMediaContact_param_vcard_type_string' => 'Vcard', 'object_contacts.topPeersDisabled' => 'Top peers disabled', 'object_draftMessageEmpty_param_date_type_int' => 'Date', 'object_inputWebFileGeoPointLocation_param_access_hash_type_long' => 'Access hash', 'method_contacts.getContacts_param_hash_type_Vector t' => 'User IDs of previously cached contacts', 'method_contacts.getTopPeers_param_hash_type_Vector t' => 'Peer IDs of previously cached peers', 'method_messages.getDialogs_param_hash_type_Vector t' => 'IDs of previously fetched dialogs', 'method_messages.getHistory_param_hash_type_Vector t' => 'IDs of messages you already fetched', 'method_messages.search_param_hash_type_Vector t' => 'The IDs of messages you already fetched', 'method_messages.getStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getAllStickers_param_hash_type_Vector t' => 'The hash parameter of the previous result of this method', 'method_messages.getSavedGifs_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getFeaturedStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getRecentStickers_param_hash_type_Vector t' => 'IDs the hash parameter of the previous result of this method', 'method_messages.getMaskStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getWebPage_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getFavedStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getRecentLocations_param_hash_type_Vector t' => 'IDs of locations you already fetched', 'method_messages.searchStickerSets_param_hash_type_Vector t' => 'The IDs of stickersets you already fetched', 'method_channels.getParticipants_param_hash_type_Vector t' => 'IDs of previously fetched participants', 'method_auth.checkPassword_param_password_type_InputCheckPasswordSRP' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_account.getPasswordSettings_param_password_type_InputCheckPasswordSRP' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'method_account.updatePasswordSettings_param_password_type_InputCheckPasswordSRP' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'method_account.getTmpPassword_param_password_type_InputCheckPasswordSRP' => 'Password', 'method_account.confirmPasswordEmail' => 'Confirm password recovery using email', 'method_account.confirmPasswordEmail_param_code_type_string' => 'Code', 'method_account.resendPasswordEmail' => 'Resend password recovery email', 'method_account.cancelPasswordEmail' => 'Cancel password recovery email', 'method_account.getContactSignUpNotification' => 'Contact signup notification setting value', 'method_account.setContactSignUpNotification' => 'Set contact sign up notification', 'method_account.setContactSignUpNotification_param_silent_type_Bool' => 'Silent?', 'method_account.getNotifyExceptions' => 'Get notification exceptions', 'method_account.getNotifyExceptions_param_compare_sound_type_true' => 'Compare sound?', 'method_account.getNotifyExceptions_param_peer_type_InputNotifyPeer' => 'Peer', 'method_contacts.getContactIDs' => 'Get contacts by IDs', 'method_contacts.getContactIDs_param_hash_type_Vector t' => 'Previously fetched IDs', 'method_contacts.deleteByPhones' => 'Delete contacts by phones', 'method_contacts.deleteByPhones_param_phones_type_Vector t' => 'Phones', 'method_messages.sendInlineBotResult_param_hide_via_type_true' => 'Hide "via @bot"', 'method_messages.clearAllDrafts' => 'Clear all drafts', 'method_messages.updatePinnedMessage' => 'Update pinned message', 'method_messages.updatePinnedMessage_param_silent_type_true' => 'Silent?', 'method_messages.updatePinnedMessage_param_peer_type_InputPeer' => 'Peer', 'method_messages.updatePinnedMessage_param_id_type_int' => 'Message ID', 'method_messages.sendVote' => 'Send vote', 'method_messages.sendVote_param_peer_type_InputPeer' => 'Peer', 'method_messages.sendVote_param_msg_id_type_int' => 'Message ID', 'method_messages.sendVote_param_options_type_Vector t' => 'Options', 'method_messages.getPollResults' => 'Get poll results', 'method_messages.getPollResults_param_peer_type_InputPeer' => 'Peer', 'method_messages.getPollResults_param_msg_id_type_int' => 'Message ID', 'method_messages.getOnlines' => 'Get online users', 'method_messages.getOnlines_param_peer_type_InputPeer' => 'Peer', 'method_messages.getStatsURL' => 'Get stats URL', 'method_messages.getStatsURL_param_peer_type_InputPeer' => 'Peer', 'method_help.getAppUpdate_param_source_type_string' => 'Source', 'method_help.getAppConfig' => 'Get app config', 'method_help.getPassportConfig' => 'Get passport config', 'method_help.getPassportConfig_param_hash_type_Vector t' => 'Hash', 'method_help.getSupportName' => 'Get support name', 'method_help.getUserInfo' => 'Get user info', 'method_help.getUserInfo_param_user_id_type_InputUser' => 'User ID', 'method_help.editUserInfo' => 'Edit user info', 'method_help.editUserInfo_param_user_id_type_InputUser' => 'User ID', 'method_help.editUserInfo_param_message_type_string' => 'Message', 'method_help.editUserInfo_param_entities_type_Vector t' => 'Entities', 'method_langpack.getLangPack_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getStrings_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getDifference_param_lang_code_type_string' => 'Lang code', 'method_langpack.getLanguages_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getLanguage' => 'Get language', 'method_langpack.getLanguage_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getLanguage_param_lang_code_type_string' => 'Lang code', 'object_inputMediaGeoLive_param_stopped_type_true' => 'Stopped?', 'object_inputMediaPoll' => 'Media poll', 'object_inputMediaPoll_param_poll_type_Poll' => 'Poll', 'object_inputPhoto_param_file_reference_type_bytes' => 'File reference', 'object_inputFileLocation_param_file_reference_type_bytes' => 'File reference', 'object_inputDocumentFileLocation_param_file_reference_type_bytes' => 'File reference', 'object_fileLocation_param_file_reference_type_bytes' => 'File reference', 'object_chatFull_param_pinned_msg_id_type_int' => 'Pinned msg ID', 'object_channelFull_param_can_view_stats_type_true' => 'Can view stats?', 'object_channelFull_param_online_count_type_int' => 'Online count', 'object_message_param_from_scheduled_type_true' => 'From scheduled?', 'object_messageMediaPoll' => 'Message media poll', 'object_messageMediaPoll_param_poll_type_Poll' => 'Poll', 'object_messageMediaPoll_param_results_type_PollResults' => 'Results', 'object_messageActionContactSignUp' => 'Message action contact sign up', 'object_photo_param_file_reference_type_bytes' => 'File reference', 'object_inputNotifyBroadcasts' => 'Notify broadcasts', 'object_inputReportReasonChildAbuse' => 'Report reason child abuse', 'object_inputReportReasonCopyright' => 'Report reason copyright', 'object_userFull_param_can_pin_message_type_true' => 'Can pin message?', 'object_userFull_param_pinned_msg_id_type_int' => 'Pinned msg ID', 'object_messages.channelMessages_param_inexact_type_true' => 'Inexact?', 'object_updateLangPackTooLong_param_lang_code_type_string' => 'Lang code', 'object_updateUserPinnedMessage' => 'Update user pinned message', 'object_updateUserPinnedMessage_param_user_id_type_int' => 'User ID', 'object_updateUserPinnedMessage_param_id_type_int' => 'ID', 'object_updateChatPinnedMessage' => 'Update chat pinned message', 'object_updateChatPinnedMessage_param_chat_id_type_int' => 'Chat ID', 'object_updateChatPinnedMessage_param_id_type_int' => 'ID', 'object_updateMessagePoll' => 'Update message poll', 'object_updateMessagePoll_param_poll_id_type_long' => 'Poll ID', 'object_updateMessagePoll_param_poll_type_Poll' => 'Poll', 'object_updateMessagePoll_param_results_type_PollResults' => 'Results', 'object_config_param_pfs_enabled_type_true' => 'Pfs enabled?', 'object_config_param_base_lang_pack_version_type_int' => 'Base lang pack version', 'object_help.appUpdate_param_popup_type_true' => 'Popup?', 'object_help.appUpdate_param_version_type_string' => 'Version', 'object_help.appUpdate_param_entities_type_Vector t' => 'Entities', 'object_help.appUpdate_param_document_type_Document' => 'Document', 'object_inputDocument_param_file_reference_type_bytes' => 'File reference', 'object_document_param_file_reference_type_bytes' => 'File reference', 'object_notifyBroadcasts' => 'Notify broadcasts', 'object_inputPrivacyKeyPhoneP2P' => 'Privacy key phone p2p', 'object_privacyKeyPhoneP2P' => 'Privacy key phone p2p', 'object_authorization_param_current_type_true' => 'Current?', 'object_authorization_param_official_app_type_true' => 'Official app?', 'object_authorization_param_password_pending_type_true' => 'Password pending?', 'object_account.password_param_has_password_type_true' => 'Has password?', 'object_account.password_param_current_algo_type_PasswordKdfAlgo' => 'Current algo', 'object_account.password_param_srp_B_type_bytes' => 'Srp b', 'object_account.password_param_srp_id_type_long' => 'Srp ID', 'object_account.password_param_new_algo_type_PasswordKdfAlgo' => 'New algo', 'object_account.password_param_new_secure_algo_type_SecurePasswordKdfAlgo' => 'New secure algo', 'object_account.passwordSettings_param_secure_settings_type_SecureSecretSettings' => 'Secure settings', 'object_account.passwordInputSettings_param_new_algo_type_PasswordKdfAlgo' => 'New algo', 'object_account.passwordInputSettings_param_new_secure_settings_type_SecureSecretSettings' => 'New secure settings', 'object_textSubscript' => 'Text subscript', 'object_textSubscript_param_text_type_RichText' => 'Text', 'object_textSuperscript' => 'Text superscript', 'object_textSuperscript_param_text_type_RichText' => 'Text', 'object_textMarked' => 'Text marked', 'object_textMarked_param_text_type_RichText' => 'Text', 'object_textPhone' => 'Text phone', 'object_textPhone_param_text_type_RichText' => 'Text', 'object_textPhone_param_phone_type_string' => 'Phone', 'object_textImage' => 'Text image', 'object_textImage_param_document_id_type_long' => 'Document ID', 'object_textImage_param_w_type_int' => 'Width', 'object_textImage_param_h_type_int' => 'Height', 'object_textAnchor' => 'Text anchor', 'object_textAnchor_param_text_type_RichText' => 'Text', 'object_textAnchor_param_name_type_string' => 'Name', 'object_pageBlockPhoto_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockPhoto_param_url_type_string' => 'URL', 'object_pageBlockPhoto_param_webpage_id_type_long' => 'Webpage ID', 'object_pageBlockVideo_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockEmbed_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockEmbedPost_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockCollage_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockSlideshow_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockAudio_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockKicker' => 'Page block kicker', 'object_pageBlockKicker_param_text_type_RichText' => 'Text', 'object_pageBlockTable' => 'Page block table', 'object_pageBlockTable_param_bordered_type_true' => 'Bordered?', 'object_pageBlockTable_param_striped_type_true' => 'Striped?', 'object_pageBlockTable_param_title_type_RichText' => 'Title', 'object_pageBlockTable_param_rows_type_Vector t' => 'Rows', 'object_pageBlockOrderedList' => 'Page block ordered list', 'object_pageBlockOrderedList_param_items_type_Vector t' => 'Items', 'object_pageBlockDetails' => 'Page block details', 'object_pageBlockDetails_param_open_type_true' => 'Open?', 'object_pageBlockDetails_param_blocks_type_Vector t' => 'Blocks', 'object_pageBlockDetails_param_title_type_RichText' => 'Title', 'object_pageBlockRelatedArticles' => 'Page block related articles', 'object_pageBlockRelatedArticles_param_title_type_RichText' => 'Title', 'object_pageBlockRelatedArticles_param_articles_type_Vector t' => 'Articles', 'object_pageBlockMap' => 'Page block map', 'object_pageBlockMap_param_geo_type_GeoPoint' => 'Geo', 'object_pageBlockMap_param_zoom_type_int' => 'Zoom', 'object_pageBlockMap_param_w_type_int' => 'Width', 'object_pageBlockMap_param_h_type_int' => 'Height', 'object_pageBlockMap_param_caption_type_PageCaption' => 'Caption', 'object_phoneCall_param_p2p_allowed_type_true' => 'P2p allowed?', 'object_langPackLanguage_param_official_type_true' => 'Official?', 'object_langPackLanguage_param_rtl_type_true' => 'Rtl?', 'object_langPackLanguage_param_beta_type_true' => 'Beta?', 'object_langPackLanguage_param_base_lang_code_type_string' => 'Base lang code', 'object_langPackLanguage_param_plural_code_type_string' => 'Plural code', 'object_langPackLanguage_param_strings_count_type_int' => 'Strings count', 'object_langPackLanguage_param_translated_count_type_int' => 'Translated count', 'object_langPackLanguage_param_translations_url_type_string' => 'Translations URL', 'object_secureValue_param_translation_type_Vector t' => 'Translation', 'object_inputSecureValue_param_translation_type_Vector t' => 'Translation', 'object_secureValueError' => 'Secure value error', 'object_secureValueError_param_type_type_SecureValueType' => 'Type', 'object_secureValueError_param_hash_type_bytes' => 'Hash', 'object_secureValueError_param_text_type_string' => 'Text', 'object_secureValueErrorTranslationFile' => 'Secure value error translation file', 'object_secureValueErrorTranslationFile_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorTranslationFile_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorTranslationFile_param_text_type_string' => 'Text', 'object_secureValueErrorTranslationFiles' => 'Secure value error translation files', 'object_secureValueErrorTranslationFiles_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorTranslationFiles_param_file_hash_type_Vector t' => 'File hash', 'object_secureValueErrorTranslationFiles_param_text_type_string' => 'Text', 'object_passwordKdfAlgoUnknown' => 'Password kdf algo unknown', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow' => 'Password kdf algo sha256sha256pbkdf2hmacsh a512iter100000 sha256 mod pow', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_salt1_type_bytes' => 'Salt1', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_salt2_type_bytes' => 'Salt2', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_g_type_int' => 'G', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_p_type_bytes' => 'P', 'object_securePasswordKdfAlgoUnknown' => 'Secure password kdf algo unknown', 'object_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000' => 'Secure password kdf algo pbkdf2hmacsh a512iter100000', 'object_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000_param_salt_type_bytes' => 'Salt', 'object_securePasswordKdfAlgoSHA512' => 'Secure password kdf algo sha512', 'object_securePasswordKdfAlgoSHA512_param_salt_type_bytes' => 'Salt', 'object_secureSecretSettings' => 'Secure secret settings', 'object_secureSecretSettings_param_secure_algo_type_SecurePasswordKdfAlgo' => 'Secure algo', 'object_secureSecretSettings_param_secure_secret_type_bytes' => 'Secure secret', 'object_secureSecretSettings_param_secure_secret_id_type_long' => 'Secure secret ID', 'object_inputCheckPasswordEmpty' => 'Empty input check password', 'object_inputCheckPasswordSRP' => 'Check password srp', 'object_inputCheckPasswordSRP_param_srp_id_type_long' => 'Srp ID', 'object_inputCheckPasswordSRP_param_A_type_bytes' => 'A', 'object_inputCheckPasswordSRP_param_M1_type_bytes' => 'M1', 'object_secureRequiredType' => 'Secure required type', 'object_secureRequiredType_param_native_names_type_true' => 'Native names?', 'object_secureRequiredType_param_selfie_required_type_true' => 'Selfie required?', 'object_secureRequiredType_param_translation_required_type_true' => 'Translation required?', 'object_secureRequiredType_param_type_type_SecureValueType' => 'Type', 'object_secureRequiredTypeOneOf' => 'Secure required type one of', 'object_secureRequiredTypeOneOf_param_types_type_Vector t' => 'Types', 'object_help.passportConfigNotModified' => 'Passport config not modified', 'object_help.passportConfig' => 'Passport config', 'object_help.passportConfig_param_hash_type_int' => 'Hash', 'object_help.passportConfig_param_countries_langs_type_DataJSON' => 'Countries langs', 'object_inputAppEvent_param_data_type_JSONValue' => 'Data', 'object_jsonObjectValue' => 'Json object value', 'object_jsonObjectValue_param_key_type_string' => 'Key', 'object_jsonObjectValue_param_value_type_JSONValue' => 'Value', 'object_jsonNull' => 'Json null', 'object_jsonBool' => 'Json bool', 'object_jsonBool_param_value_type_Bool' => 'Value?', 'object_jsonNumber' => 'Json number', 'object_jsonNumber_param_value_type_double' => 'Value', 'object_jsonString' => 'Json string', 'object_jsonString_param_value_type_string' => 'Value', 'object_jsonArray' => 'Json array', 'object_jsonArray_param_value_type_Vector t' => 'Value', 'object_jsonObject' => 'Json object', 'object_jsonObject_param_value_type_Vector t' => 'Value', 'object_pageTableCell' => 'Page table cell', 'object_pageTableCell_param_header_type_true' => 'Header?', 'object_pageTableCell_param_align_center_type_true' => 'Align center?', 'object_pageTableCell_param_align_right_type_true' => 'Align right?', 'object_pageTableCell_param_valign_middle_type_true' => 'Valign middle?', 'object_pageTableCell_param_valign_bottom_type_true' => 'Valign bottom?', 'object_pageTableCell_param_text_type_RichText' => 'Text', 'object_pageTableCell_param_colspan_type_int' => 'Colspan', 'object_pageTableCell_param_rowspan_type_int' => 'Rowspan', 'object_pageTableRow' => 'Page table row', 'object_pageTableRow_param_cells_type_Vector t' => 'Cells', 'object_pageCaption' => 'Page caption', 'object_pageCaption_param_text_type_RichText' => 'Text', 'object_pageCaption_param_credit_type_RichText' => 'Credit', 'object_pageListItemText' => 'Page list item text', 'object_pageListItemText_param_text_type_RichText' => 'Text', 'object_pageListItemBlocks' => 'Page list item blocks', 'object_pageListItemBlocks_param_blocks_type_Vector t' => 'Blocks', 'object_pageListOrderedItemText' => 'Page list ordered item text', 'object_pageListOrderedItemText_param_num_type_string' => 'Num', 'object_pageListOrderedItemText_param_text_type_RichText' => 'Text', 'object_pageListOrderedItemBlocks' => 'Page list ordered item blocks', 'object_pageListOrderedItemBlocks_param_num_type_string' => 'Num', 'object_pageListOrderedItemBlocks_param_blocks_type_Vector t' => 'Blocks', 'object_pageRelatedArticle' => 'Page related article', 'object_pageRelatedArticle_param_url_type_string' => 'URL', 'object_pageRelatedArticle_param_webpage_id_type_long' => 'Webpage ID', 'object_pageRelatedArticle_param_title_type_string' => 'Title', 'object_pageRelatedArticle_param_description_type_string' => 'Description', 'object_pageRelatedArticle_param_photo_id_type_long' => 'Photo ID', 'object_pageRelatedArticle_param_author_type_string' => 'Author', 'object_pageRelatedArticle_param_published_date_type_int' => 'Published date', 'object_page' => 'Page', 'object_page_param_part_type_true' => 'Part?', 'object_page_param_rtl_type_true' => 'Rtl?', 'object_page_param_v2_type_true' => 'V2?', 'object_page_param_url_type_string' => 'URL', 'object_page_param_blocks_type_Vector t' => 'Blocks', 'object_page_param_photos_type_Vector t' => 'Photos', 'object_page_param_documents_type_Vector t' => 'Documents', 'object_help.supportName' => 'Support name', 'object_help.supportName_param_name_type_string' => 'Name', 'object_help.userInfoEmpty' => 'Empty user info', 'object_help.userInfo' => 'User info', 'object_help.userInfo_param_message_type_string' => 'Message', 'object_help.userInfo_param_entities_type_Vector t' => 'Entities', 'object_help.userInfo_param_author_type_string' => 'Author', 'object_help.userInfo_param_date_type_int' => 'Date', 'object_pollAnswer' => 'Poll answer', 'object_pollAnswer_param_text_type_string' => 'Text', 'object_pollAnswer_param_option_type_bytes' => 'Option', 'object_poll' => 'Poll', 'object_poll_param_id_type_long' => 'ID', 'object_poll_param_closed_type_true' => 'Closed?', 'object_poll_param_question_type_string' => 'Question', 'object_poll_param_answers_type_Vector t' => 'Answers', 'object_pollAnswerVoters' => 'Poll answer voters', 'object_pollAnswerVoters_param_chosen_type_true' => 'Chosen?', 'object_pollAnswerVoters_param_option_type_bytes' => 'Option', 'object_pollAnswerVoters_param_voters_type_int' => 'Voters', 'object_pollResults' => 'Poll results', 'object_pollResults_param_min_type_true' => 'Min?', 'object_pollResults_param_results_type_Vector t' => 'Results', 'object_pollResults_param_total_voters_type_int' => 'Total voters', 'object_chatOnlines' => 'Chat onlines', 'object_chatOnlines_param_onlines_type_int' => 'Onlines', 'object_statsURL' => 'Stats URL', 'object_statsURL_param_url_type_string' => 'URL', 'method_auth.sendCode_param_settings_type_CodeSettings' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_account.getWallPapers_param_hash_type_Vector t' => 'IDs of previously fetched wallpapers', 'method_account.sendChangePhoneCode_param_settings_type_CodeSettings' => 'Code settings', 'method_account.sendConfirmPhoneCode_param_settings_type_CodeSettings' => 'Code settings', 'method_account.sendVerifyPhoneCode_param_settings_type_CodeSettings' => 'Code settings', 'method_account.getWallPaper' => 'Get wallpaper info', 'method_account.getWallPaper_param_wallpaper_type_InputWallPaper' => 'Wallpaper', 'method_account.uploadWallPaper' => 'Upload wallpaper', 'method_account.uploadWallPaper_param_file_type_InputFile' => 'Image', 'method_account.uploadWallPaper_param_mime_type_type_string' => 'Mime type', 'method_account.uploadWallPaper_param_settings_type_WallPaperSettings' => 'Wallpaper settings', 'method_account.saveWallPaper' => 'Save wallpaper', 'method_account.saveWallPaper_param_wallpaper_type_InputWallPaper' => 'The wallpaper to save', 'method_account.saveWallPaper_param_unsave_type_Bool' => 'Delete saved wallpaper', 'method_account.saveWallPaper_param_settings_type_WallPaperSettings' => 'The wallpaper to save', 'method_account.installWallPaper' => 'Install wallpaper', 'method_account.installWallPaper_param_wallpaper_type_InputWallPaper' => 'Wallpaper to install', 'method_account.installWallPaper_param_settings_type_WallPaperSettings' => 'Wallpaper settings', 'method_account.resetWallPapers' => 'Reset wallpapers', 'method_messages.exportChatInvite_param_peer_type_InputPeer' => 'Export invite only for this user', 'method_messages.editChatAbout' => 'Edit chat info', 'method_messages.editChatAbout_param_peer_type_InputPeer' => 'Chat', 'method_messages.editChatAbout_param_about_type_string' => 'Info', 'method_messages.editChatDefaultBannedRights' => 'Edit default rights of chat', 'method_messages.editChatDefaultBannedRights_param_peer_type_InputPeer' => 'Chat', 'method_messages.editChatDefaultBannedRights_param_banned_rights_type_ChatBannedRights' => 'Global chat rights', 'method_channels.editAdmin_param_admin_rights_type_ChatAdminRights' => 'Admin rights', 'method_channels.editBanned_param_banned_rights_type_ChatBannedRights' => 'Banned rights', 'object_chat_param_admin_rights_type_ChatAdminRights' => 'Admin rights of current user', 'object_chat_param_default_banned_rights_type_ChatBannedRights' => 'Global chat banned rights', 'object_channel_param_admin_rights_type_ChatAdminRights' => 'Admin rights of current user', 'object_channel_param_banned_rights_type_ChatBannedRights' => 'Banned rights of current user', 'object_channel_param_default_banned_rights_type_ChatBannedRights' => 'Global chat banned rights', 'object_chatFull_param_can_set_username_type_true' => 'Can set username?', 'object_chatFull_param_about_type_string' => 'Chat about', 'object_photoStrippedSize' => 'Stripped size', 'object_photoStrippedSize_param_type_type_string' => 'Stripped size', 'object_photoStrippedSize_param_bytes_type_bytes' => 'Bytes', 'object_wallPaper_param_id_type_long' => 'ID', 'object_wallPaper_param_creator_type_true' => 'Am I the creator?', 'object_wallPaper_param_default_type_true' => 'Default?', 'object_wallPaper_param_pattern_type_true' => 'Pattern', 'object_wallPaper_param_dark_type_true' => 'Dark?', 'object_wallPaper_param_access_hash_type_long' => 'Hash', 'object_wallPaper_param_slug_type_string' => 'Slug?', 'object_wallPaper_param_document_type_Document' => 'Wallpaper', 'object_wallPaper_param_settings_type_WallPaperSettings' => 'Wallpaper settings', 'object_messages.messagesSlice_param_inexact_type_true' => 'Inexact?', 'object_updateChatDefaultBannedRights' => 'Global chat rights updated', 'object_updateChatDefaultBannedRights_param_peer_type_Peer' => 'Peer', 'object_updateChatDefaultBannedRights_param_default_banned_rights_type_ChatBannedRights' => 'Global chat rights', 'object_updateChatDefaultBannedRights_param_version_type_int' => 'Version', 'object_document_param_thumbs_type_Vector t' => 'Thumbnails', 'object_channelParticipantAdmin_param_self_type_true' => 'Is this the current user?', 'object_channelParticipantAdmin_param_admin_rights_type_ChatAdminRights' => 'Admin rights', 'object_channelParticipantBanned_param_banned_rights_type_ChatBannedRights' => 'Banned rights', 'object_channelParticipantsContacts' => 'Contacts', 'object_channelParticipantsContacts_param_q_type_string' => 'Query', 'object_channelAdminLogEventActionDefaultBannedRights' => 'Changed global chat rights', 'object_channelAdminLogEventActionDefaultBannedRights_param_prev_banned_rights_type_ChatBannedRights' => 'Previous Banned rights of current user', 'object_channelAdminLogEventActionDefaultBannedRights_param_new_banned_rights_type_ChatBannedRights' => 'New Banned rights of current user', 'object_channelAdminLogEventActionStopPoll' => 'Stopped poll', 'object_channelAdminLogEventActionStopPoll_param_message_type_Message' => 'Message', 'object_chatAdminRights' => 'Admin rights', 'object_chatAdminRights_param_change_info_type_true' => 'Can change info?', 'object_chatAdminRights_param_post_messages_type_true' => 'Can post messages?', 'object_chatAdminRights_param_edit_messages_type_true' => 'Can edit messages?', 'object_chatAdminRights_param_delete_messages_type_true' => 'Can delete messages?', 'object_chatAdminRights_param_ban_users_type_true' => 'Can ban users?', 'object_chatAdminRights_param_invite_users_type_true' => 'Can invite users?', 'object_chatAdminRights_param_pin_messages_type_true' => 'Can pin messages?', 'object_chatAdminRights_param_add_admins_type_true' => 'Can add other admins?', 'object_chatBannedRights' => 'Banned rights (when true, the user will NOT be able to do that thing)', 'object_chatBannedRights_param_view_messages_type_true' => 'Can view messages?', 'object_chatBannedRights_param_send_messages_type_true' => 'Can send messages?', 'object_chatBannedRights_param_send_media_type_true' => 'Can send media?', 'object_chatBannedRights_param_send_stickers_type_true' => 'Can send stickers?', 'object_chatBannedRights_param_send_gifs_type_true' => 'Can send gifs?', 'object_chatBannedRights_param_send_games_type_true' => 'Can send games?', 'object_chatBannedRights_param_send_inline_type_true' => 'Can use inline bots?', 'object_chatBannedRights_param_embed_links_type_true' => 'Can embed links?', 'object_chatBannedRights_param_send_polls_type_true' => 'Can send polls?', 'object_chatBannedRights_param_change_info_type_true' => 'Can change info?', 'object_chatBannedRights_param_invite_users_type_true' => 'Can invite users?', 'object_chatBannedRights_param_pin_messages_type_true' => 'Can pin messages?', 'object_chatBannedRights_param_until_date_type_int' => 'Until date (0 = forever)', 'object_inputWallPaper' => 'Wallpaper', 'object_inputWallPaper_param_id_type_long' => 'ID', 'object_inputWallPaper_param_access_hash_type_long' => 'Access hash', 'object_inputWallPaperSlug' => 'Wallpaper slug', 'object_inputWallPaperSlug_param_slug_type_string' => 'Type', 'object_account.wallPapersNotModified' => 'No wallpapers were modified', 'object_account.wallPapers' => 'Wallpapers', 'object_account.wallPapers_param_hash_type_int' => 'Hash', 'object_account.wallPapers_param_wallpapers_type_Vector t' => 'Wallpapers', 'object_codeSettings' => 'Code settings', 'object_codeSettings_param_allow_flashcall_type_true' => 'Allow flashcal?', 'object_codeSettings_param_current_number_type_true' => 'Current number?', 'object_codeSettings_param_app_hash_persistent_type_true' => 'Persistent hash?', 'object_codeSettings_param_app_hash_type_string' => 'Hash type', 'object_wallPaperSettings' => 'Wallpaper settings', 'object_wallPaperSettings_param_blur_type_true' => 'Blur?', 'object_wallPaperSettings_param_motion_type_true' => 'Motion?', 'object_wallPaperSettings_param_background_color_type_int' => 'Background color', 'object_wallPaperSettings_param_intensity_type_int' => 'Intensity', 'object_inputPrivacyKeyProfilePhoto' => 'Can his profile photo be viewed?', 'object_inputPrivacyKeyForwards' => 'Can his messages be forwarded?', 'method_account.getAutoDownloadSettings' => 'Get autodownload settings', 'method_account.saveAutoDownloadSettings' => 'Save autodownload settings', 'method_account.saveAutoDownloadSettings_param_low_type_true' => 'Low preset', 'method_account.saveAutoDownloadSettings_param_high_type_true' => 'High preset', 'method_account.saveAutoDownloadSettings_param_settings_type_AutoDownloadSettings' => 'Autodownload settings', 'method_messages.deleteHistory_param_revoke_type_true' => 'Delete messages for the other user', 'method_messages.getStatsURL_param_dark_type_true' => 'Dark?', 'method_messages.getStatsURL_param_params_type_string' => 'Params', 'method_messages.getEmojiKeywords' => 'Get emoji keywords', 'method_messages.getEmojiKeywords_param_lang_code_type_string' => 'Language code', 'method_messages.getEmojiKeywordsDifference' => 'Get emoji keyword difference', 'method_messages.getEmojiKeywordsDifference_param_lang_code_type_string' => 'Language code', 'method_messages.getEmojiKeywordsDifference_param_from_version_type_int' => 'From version', 'method_messages.getEmojiURL' => 'Get emoji URL', 'method_messages.getEmojiURL_param_lang_code_type_string' => 'Language code', 'method_phone.setCallRating_param_user_initiative_type_true' => 'User initiative', 'method_langpack.getDifference_param_lang_pack_type_string' => 'Language pack', 'object_user_param_support_type_true' => 'Is this a support user?', 'object_updateChatPinnedMessage_param_version_type_int' => 'Version', 'object_privacyKeyForwards' => 'Forwards privacy key', 'object_privacyKeyProfilePhoto' => 'Show profile photo?', 'object_stickerSet_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_messageFwdHeader_param_from_name_type_string' => 'Author of the original message', 'object_autoDownloadSettings' => 'Autodownload settings', 'object_autoDownloadSettings_param_disabled_type_true' => 'Disabled?', 'object_autoDownloadSettings_param_video_preload_large_type_true' => 'Preload large videos?', 'object_autoDownloadSettings_param_audio_preload_next_type_true' => 'Preload audios?', 'object_autoDownloadSettings_param_phonecalls_less_data_type_true' => 'Use less data in phonecalls?', 'object_autoDownloadSettings_param_photo_size_max_type_int' => 'Maximum photo file size to preload', 'object_autoDownloadSettings_param_video_size_max_type_int' => 'Maximum video file size to preload', 'object_autoDownloadSettings_param_file_size_max_type_int' => 'Maximum file size to preload', 'object_account.autoDownloadSettings' => 'Autodownload settings', 'object_account.autoDownloadSettings_param_low_type_AutoDownloadSettings' => 'Low preset?', 'object_account.autoDownloadSettings_param_medium_type_AutoDownloadSettings' => 'Medium preset?', 'object_account.autoDownloadSettings_param_high_type_AutoDownloadSettings' => 'High preset?', 'object_emojiKeyword' => 'Emoji keyword', 'object_emojiKeyword_param_keyword_type_string' => 'Keyword', 'object_emojiKeyword_param_emoticons_type_Vector t' => 'Emoticons', 'object_emojiKeywordDeleted' => 'Deleted emoji keyword', 'object_emojiKeywordDeleted_param_keyword_type_string' => 'Keyword', 'object_emojiKeywordDeleted_param_emoticons_type_Vector t' => 'Emoticons', 'object_emojiKeywordsDifference' => 'Emoji keword difference', 'object_emojiKeywordsDifference_param_lang_code_type_string' => 'Language code', 'object_emojiKeywordsDifference_param_from_version_type_int' => 'Previous version', 'object_emojiKeywordsDifference_param_version_type_int' => 'Current version', 'object_emojiKeywordsDifference_param_keywords_type_Vector t' => 'Keywords', 'object_emojiURL' => 'Emoji URL', 'object_emojiURL_param_url_type_string' => 'URL', ), ); // THIS WILL BE OVERWRITTEN BY $lang["en"] public static $current_lang = array ( 'req_pq' => 'Requesting pq...', 'done' => 'Done!', 'cdn_reupload' => 'File is not stored on CDN, requesting reupload!', 'stored_on_cdn' => 'File is stored on CDN!', 'serializing_madelineproto' => 'Serializing MadelineProto...', 'phpseclib_fork' => 'Please install this fork of phpseclib: https://github.com/danog/phpseclib', 'inst_dc' => 'Istantiating DataCenter...', 'load_rsa' => 'Loading RSA keys...', 'TL_translation' => 'Translating TL schemas...', 'dh_prime_check_0' => 'Executing dh_prime checks (0/3)...', 'nearest_dc' => 'We\'re in %s, nearest DC is %d.', 'serialization_ofd' => 'Serialization is out of date, reconstructing object!', 'getupdates_deserialization' => 'Getting updates after deserialization...', 'shutdown_reader_pool' => 'Shutting down reader pool, %d jobs left', 'threading_on' => 'THREADING IS ENABLED', 'socket_reader' => 'Socket reader on DC %s: ', 'socket_status_1' => 'CREATING', 'socket_status_2' => 'SUBMITTING', 'socket_status_3' => 'WAITING', 'socket_status_4' => 'READY', 'socket_status_5' => 'WORKING', 'api_not_set' => 'You must provide an api key and an api id, get your own @ my.telegram.org', 'session_corrupted' => 'The session is corrupted!', 'reset_session_seqno' => 'Resetting session id and seq_no in DC %s...', 'gen_perm_auth_key' => 'Generating permanent authorization key for DC %s...', 'gen_temp_auth_key' => 'Generating temporary authorization key for DC %s...', 'copy_auth_dcs' => 'Copying authorization from DC %s to DC %s...', 'write_client_info' => 'Writing client info (also executing %s)...', 'config_updated' => 'Updated config!', 'length_not_4' => 'Length is not equal to 4', 'length_not_8' => 'Length is not equal to 8', 'value_bigger_than_2147483647' => 'Provided value %s is bigger than 2147483647', 'value_smaller_than_2147483648' => 'Provided value %s is smaller than -2147483648', 'value_bigger_than_9223372036854775807' => 'Provided value %s is bigger than 9223372036854775807', 'value_smaller_than_9223372036854775808' => 'Provided value %s is smaller than -9223372036854775808', 'value_bigger_than_4294967296' => 'Provided value %s is bigger than 4294967296', 'value_smaller_than_0' => 'Provided value %s is smaller than 0', 'encode_double_error' => 'Could not properly encode double', 'file_not_exist' => 'File does not exist', 'deserialization_error' => 'An error occurred on deserialization', 'rsa_init' => 'Istantiating \\phpseclib\\Crypt\\RSA...', 'loading_key' => 'Loading key...', 'computing_fingerprint' => 'Computing fingerprint...', 'rsa_encrypting' => 'Encrypting with rsa key...', 'rpc_tg_error' => 'Telegram ha ritornato un errore RPC: %s (%s), causato da %s:%s%sTL trace:', 'v_error' => '506c656173652075706461746520746f20746865206c61746573742076657273696f6e206f66204d6164656c696e6550726f746f2e', 'v_tgerror' => '506c6561736520757064617465207068702d6c69627467766f6970', 'no_mode_specified' => 'No mode was specified!', 'constructor_function_uncalled' => 'The constructor function wasn\'t called! Please call the constructor function before using this method.', 'proxy_class_invalid' => 'Invalid proxy class provided!', 'socket_con_error' => 'Connection: couldn\'t connect to socket.', 'protocol_not_implemented' => 'Connection: This protocol isn\'t implemented yet.', 'protocol_invalid' => 'Connection: invalid protocol specified.', 'nothing_in_socket' => 'Nothing in the socket!', 'wrong_length_read' => 'WARNING: Wrong length was read (should\'ve read %s, read %s)!', 'no_data_in_socket' => 'No data in the socket!', 'dc_con_start' => 'Connecting to DC %s...', 'dc_con_stop' => 'Disconnecting from DC %s...', 'dc_con_test_start' => 'Connecting to DC %s (%s server, %s, %s)...', 'script_not_exist' => 'Provided script does not exist', 'apifactory_start' => 'Running APIFactory...', 'madelineproto_ready' => 'MadelineProto is ready!', 'logout_error' => 'An error occurred while logging out!', 'logout_ok' => 'Logged out successfully!', 'already_logged_in' => 'This instance of MadelineProto is already logged in. Logging out first...', 'login_ok' => 'Logged in successfully!', 'login_user' => 'Logging in as a normal user...', 'login_bot' => 'Logging in as a bot...', 'login_code_sending' => 'Sending code...', 'login_code_sent' => 'Code sent successfully! Once you receive the code you should use the complete_phone_login function.', 'login_code_uncalled' => 'I\'m not waiting for the code! Please call the phone_login method first', 'login_2fa_enabled' => '2FA enabled, you will have to call the complete_2fa_login function...', 'login_need_signup' => 'An account has not been created for this number, you will have to call the complete_signup function...', 'login_auth_key' => 'Logging in using auth key...', 'not_logged_in' => 'I\'m not logged in!', 'signup_uncalled' => 'I\'m not waiting to signup! Please call the phone_login and the complete_phone_login methods first!', 'signing_up' => 'Signing up as a normal user...', 'signup_ok' => 'Signed up in successfully!', '2fa_uncalled' => 'I\'m not waiting for the password! Please call the phone_login and the complete_phone_login methods first!', 'getting_dialogs' => 'Getting dialogs...', 'libtgvoip_required' => 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'peer_not_in_db' => 'This peer is not present in the internal peer database', 'calling_user' => 'Calling %s...', 'generating_a' => 'Generating a...', 'generating_g_a' => 'Generating g_a...', 'call_error_1' => 'Could not find and accept call %s', 'accepting_call' => 'Accepting call from %s...', 'generating_b' => 'Generating b...', 'call_already_accepted' => 'Call %s already accepted', 'call_already_declined' => 'Call %s already declined', 'call_error_2' => 'Could not find and confirm call %s', 'call_confirming' => 'Confirming call from %s...', 'call_error_3' => 'Could not find and complete call %s', 'call_completing' => 'Completing call from %s...', 'invalid_g_a' => 'Invalid g_a!', 'fingerprint_invalid' => 'Invalid key fingerprint!', 'call_discarding' => 'Discarding call %s...', 'call_set_rating' => 'Setting rating for call %s...', 'call_debug_saving' => 'Saving debug data for call %s...', 'TL_loading' => 'Loading TL schemes...', 'file_parsing' => 'Parsing %s...', 'crc32_mismatch' => 'CRC32 mismatch (%s, %s) for %s', 'src_file_invalid' => 'Invalid source file was provided: ', 'translating_obj' => 'Translating objects...', 'translating_methods' => 'Translating methods...', 'bool_error' => 'Could not extract boolean', 'not_numeric' => 'Given value isn\'t numeric', 'long_not_16' => 'Given value is not 16 bytes long', 'long_not_32' => 'Given value is not 32 bytes long', 'long_not_64' => 'Given value is not 64 bytes long', 'array_invalid' => 'You didn\'t provide a valid array', 'predicate_not_set' => 'Predicate (value under _) was not set!', 'type_extract_error' => 'Could not extract type "%s"', 'method_not_found' => 'Could not find method: ', 'params_missing' => 'Missing required parameter', 'sec_peer_not_in_db' => 'This secret peer is not present in the internal peer database', 'stream_handle_invalid' => 'An invalid stream handle was provided.', 'length_too_big' => 'Length is too big', 'deserialize_not_str' => 'Deserialize: Generated value isn\'t a string', 'type_extract_error_id' => 'Could not extract type: %s with id %s', 'vector_invalid' => 'Invalid vector constructor: ', 'constructor_not_found' => 'Constructor not found for type: ', 'rand_bytes_too_small' => 'Random_bytes is too small!', 'botapi_conversion_error' => 'Can\'t convert %s to a bot API object', 'non_text_conversion' => 'Can\'t convert non text messages yet!', 'last_byte_invalid' => 'Invalid last byte', 'file_type_invalid' => 'Invalid file type detected (%s)', 'recreate_temp_auth_key' => 'I had to recreate the temporary authorization key', 'resetting_auth_key' => 'WARNING: Resetting auth key...', 'shutting_down_reader_pool' => 'Shutting down reader pool ', 'shutting_down_handler_pool' => 'Shutting down handler pool for dc %s, %d jobs left', 'secret_chat_skipping' => 'I do not have the secret chat %s in the database, skipping message...', 'fingerprint_mismatch' => 'Key fingerprint mismatch', 'msg_data_length_too_big' => 'Message_data_length is too big', 'length_not_divisible_16' => 'Length of decrypted data is not divisible by 16', 'msg_key_mismatch' => 'Msg_key mismatch', 'rand_bytes_too_short' => 'Random_bytes is too short!', 'resending_unsupported' => 'Resending of messages is not yet supported', 'unrecognized_dec_msg' => 'Unrecognized decrypted message received: ', 'method_req_pq' => 'Requests PQ for factorization', 'method_req_pq_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_req_pq_multi' => 'Requests PQ for factorization (new version)', 'method_req_pq_multi_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_req_DH_params' => 'Requests Diffie-hellman parameters for key exchange', 'method_req_DH_params_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_req_DH_params_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'method_req_DH_params_param_p_type_bytes' => 'Factorized p from pq', 'method_req_DH_params_param_q_type_bytes' => 'Factorized q from pq', 'method_req_DH_params_param_public_key_fingerprint_type_long' => 'Server RSA fingerprint', 'method_req_DH_params_param_encrypted_data_type_bytes' => 'Encrypted key exchange message', 'method_set_client_DH_params' => 'Sets client diffie-hellman parameters', 'method_set_client_DH_params_param_nonce_type_int128' => 'Random number for cryptographic security', 'method_set_client_DH_params_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'method_set_client_DH_params_param_encrypted_data_type_bytes' => 'Encrypted key exchange message', 'method_rpc_drop_answer' => 'Do not send answer to provided request', 'method_rpc_drop_answer_param_req_msg_id_type_long' => 'The message ID of the request', 'method_get_future_salts' => 'Get future salts', 'method_get_future_salts_param_num_type_int' => 'How many salts should be fetched', 'method_ping' => 'Pings the server', 'method_ping_param_ping_id_type_long' => 'Ping ID', 'method_ping_delay_disconnect' => 'Pings the server and causes disconection if the same method is not called within ping_disconnect_delay', 'method_ping_delay_disconnect_param_ping_id_type_long' => 'Ping ID', 'method_ping_delay_disconnect_param_disconnect_delay_type_int' => 'Disconection delay', 'method_destroy_session' => 'Destroy the current MTProto session', 'method_destroy_session_param_session_id_type_long' => 'The session to destroy', 'method_http_wait' => 'Makes the server send messages waiting in the buffer', 'method_http_wait_param_max_delay_type_int' => 'Denotes the maximum number of milliseconds that has elapsed between the first message for this session and the transmission of an HTTP response', 'method_http_wait_param_wait_after_type_int' => 'After the receipt of the latest message for a particular session, the server waits another wait_after milliseconds in case there are more messages. If there are no additional messages, the result is transmitted (a container with all the messages).', 'method_http_wait_param_max_wait_type_int' => 'If more messages appear, the wait_after timer is reset.', 'method_invokeAfterMsg' => 'Invokes a query after successfull completion of one of the previous queries.', 'method_invokeAfterMsg_param_msg_id_type_long' => 'Message identifier on which a current query depends', 'method_invokeAfterMsg_param_query_type_!X' => 'The query itself', 'method_invokeAfterMsgs' => 'Result type returned by a current query.', 'method_invokeAfterMsgs_param_msg_ids_type_Vector t' => 'List of messages on which a current query depends', 'method_invokeAfterMsgs_param_query_type_!X' => 'The query itself', 'method_initConnection' => 'Initializes connection and save information on the user\'s device and application.', 'method_initConnection_param_api_id_type_int' => 'Application identifier', 'method_initConnection_param_device_model_type_string' => 'Device model', 'method_initConnection_param_system_version_type_string' => 'System version', 'method_initConnection_param_app_version_type_string' => 'App version', 'method_initConnection_param_system_lang_code_type_string' => 'Language code', 'method_initConnection_param_lang_pack_type_string' => 'Language pack to use', 'method_initConnection_param_lang_code_type_string' => 'Language code to set', 'method_initConnection_param_query_type_!X' => 'Nested query', 'method_invokeWithLayer' => 'Invoke this method with layer X', 'method_invokeWithLayer_param_layer_type_int' => 'The layer version', 'method_invokeWithLayer_param_query_type_!X' => 'The query', 'method_invokeWithoutUpdates' => 'Invoke with method without returning updates in the socket', 'method_invokeWithoutUpdates_param_query_type_!X' => 'The query', 'method_auth.checkPhone' => 'Check if this phone number is registered on telegram', 'method_auth.checkPhone_param_phone_number_type_string' => 'The phone number to check', 'method_auth.sendCode' => 'Use phone_login instead', 'method_auth.sendCode_param_allow_flashcall_type_true' => 'Use phone_login instead', 'method_auth.sendCode_param_phone_number_type_string' => 'Use phone_login instead', 'method_auth.sendCode_param_current_number_type_Bool' => 'Use phone_login instead', 'method_auth.sendCode_param_api_id_type_int' => 'Use phone_login instead', 'method_auth.sendCode_param_api_hash_type_string' => 'Use phone_login instead', 'method_auth.signUp' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_phone_number_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_phone_code_hash_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_phone_code_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_first_name_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signUp_param_last_name_type_string' => 'You cannot use this method directly, use the complete_signup method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn_param_phone_number_type_string' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn_param_phone_code_hash_type_string' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.signIn_param_phone_code_type_string' => 'You cannot use this method directly, use the complete_phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.logOut' => 'You cannot use this method directly, use the logout method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.resetAuthorizations' => 'Delete all logged-in sessions.', 'method_auth.sendInvites' => 'Invite friends to telegram!', 'method_auth.sendInvites_param_phone_numbers_type_Vector t' => 'Phone numbers to invite', 'method_auth.sendInvites_param_message_type_string' => 'The message to send', 'method_auth.exportAuthorization' => 'You cannot use this method directly, use $MadelineProto->export_authorization() instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.exportAuthorization_param_dc_id_type_int' => 'You cannot use this method directly, use $MadelineProto->export_authorization() instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.importAuthorization' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.importAuthorization_param_id_type_int' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.importAuthorization_param_bytes_type_bytes' => 'You cannot use this method directly, use $MadelineProto->import_authorization($authorization) instead, see https://docs.madelineproto.xyz/docs/LOGIN.html', 'method_auth.bindTempAuthKey' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_perm_auth_key_id_type_long' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_nonce_type_long' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_expires_at_type_int' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.bindTempAuthKey_param_encrypted_message_type_bytes' => 'You cannot use this method directly, instead modify the PFS and default_temp_auth_key_expires_in settings, see https://docs.madelineproto.xyz/docs/SETTINGS.html for more info', 'method_auth.importBotAuthorization' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_api_id_type_int' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_api_hash_type_string' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_bot_auth_token_type_string' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.checkPassword' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.checkPassword_param_password_hash_type_bytes' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.requestPasswordRecovery' => 'Send an email to recover the 2FA password', 'method_auth.recoverPassword' => 'Use the code that was emailed to you after running $MadelineProto->auth->requestPasswordRecovery to login to your account', 'method_auth.recoverPassword_param_code_type_string' => 'The code that was emailed to you', 'method_auth.resendCode' => 'Resend the SMS verification code', 'method_auth.resendCode_param_phone_number_type_string' => 'The phone number', 'method_auth.resendCode_param_phone_code_hash_type_string' => 'The phone code hash', 'method_auth.cancelCode' => 'Invalidate sent phone code', 'method_auth.cancelCode_param_phone_number_type_string' => 'Phone number', 'method_auth.cancelCode_param_phone_code_hash_type_string' => 'Phone code hash', 'method_auth.dropTempAuthKeys' => 'Delete all temporary authorization keys except the ones provided', 'method_auth.dropTempAuthKeys_param_except_auth_keys_type_Vector t' => 'The temporary authorization keys to keep', 'method_account.registerDevice' => 'Register device for push notifications', 'method_account.registerDevice_param_token_type_type_int' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone, 6 - Blackberry, and other, see source code of official apps for more info', 'method_account.registerDevice_param_token_type_string' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone,6 - Blackberry, and other, see source code of official apps for more info', 'method_account.registerDevice_param_app_sandbox_type_Bool' => 'Should the app run in a sandbox?', 'method_account.registerDevice_param_other_uids_type_Vector t' => 'Other UIDs', 'method_account.unregisterDevice' => 'Stop sending PUSH notifications to app', 'method_account.unregisterDevice_param_token_type_type_int' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone,6 - Blackberry, and other, see source code of official apps for more info', 'method_account.unregisterDevice_param_token_type_string' => 'Device token type. Possible values: 1 - APNS, 2 - GCM, 3 - MPNS, 4 - Simple Push, 5 - Ubuntu Phone,6 - Blackberry, and other, see source code of official apps for more info', 'method_account.unregisterDevice_param_other_uids_type_Vector t' => 'Other UIDs', 'method_account.updateNotifySettings' => 'Change notification settings', 'method_account.updateNotifySettings_param_peer_type_InputNotifyPeer' => 'The peers to which the notification settings should be applied', 'method_account.updateNotifySettings_param_settings_type_InputPeerNotifySettings' => 'Notification settings', 'method_account.getNotifySettings' => 'Get notification settings', 'method_account.getNotifySettings_param_peer_type_InputNotifyPeer' => 'Notification source ', 'method_account.resetNotifySettings' => 'Reset all notification settings', 'method_account.updateProfile' => 'Update profile info', 'method_account.updateProfile_param_first_name_type_string' => 'The first name', 'method_account.updateProfile_param_last_name_type_string' => 'The last name', 'method_account.updateProfile_param_about_type_string' => 'The bio/about field', 'method_account.updateStatus' => 'Update online status', 'method_account.updateStatus_param_offline_type_Bool' => 'True to set the status to offline', 'method_account.getWallPapers' => 'Returns a list of available wallpapers.', 'method_account.reportPeer' => 'Report for spam', 'method_account.reportPeer_param_peer_type_InputPeer' => 'The peer to report', 'method_account.reportPeer_param_reason_type_ReportReason' => 'Why are you reporting this peer', 'method_account.checkUsername' => 'Check if this username is available', 'method_account.checkUsername_param_username_type_string' => 'The username to check', 'method_account.updateUsername' => 'Update this user\'s username', 'method_account.updateUsername_param_username_type_string' => 'The new username', 'method_account.getPrivacy' => 'Get privacy settings', 'method_account.getPrivacy_param_key_type_InputPrivacyKey' => 'Privacy setting key', 'method_account.setPrivacy' => 'Set privacy settings', 'method_account.setPrivacy_param_key_type_InputPrivacyKey' => 'Privacy setting', 'method_account.setPrivacy_param_rules_type_Vector t' => 'Privacy settings', 'method_account.deleteAccount' => 'Delete this account', 'method_account.deleteAccount_param_reason_type_string' => 'Why are you going away? :(', 'method_account.getAccountTTL' => 'Get account TTL', 'method_account.setAccountTTL' => 'Set account TTL', 'method_account.setAccountTTL_param_ttl_type_AccountDaysTTL' => 'Time To Live of account', 'method_account.sendChangePhoneCode' => 'Change the phone number', 'method_account.sendChangePhoneCode_param_allow_flashcall_type_true' => 'Can the code be sent using a flash call instead of an SMS?', 'method_account.sendChangePhoneCode_param_phone_number_type_string' => 'New phone number', 'method_account.sendChangePhoneCode_param_current_number_type_Bool' => 'Current phone number', 'method_account.changePhone' => 'Change the phone number associated to this account', 'method_account.changePhone_param_phone_number_type_string' => 'Phone number', 'method_account.changePhone_param_phone_code_hash_type_string' => 'Phone code hash returned by account.sendChangePhoneCode', 'method_account.changePhone_param_phone_code_type_string' => 'The phone code sent by account.sendChangePhoneCode', 'method_account.updateDeviceLocked' => 'Disable all notifications for a certain period', 'method_account.updateDeviceLocked_param_period_type_int' => 'For how long should notifications be disabled', 'method_account.getAuthorizations' => 'Get all logged-in authorizations', 'method_account.resetAuthorization' => 'Delete a certain session', 'method_account.resetAuthorization_param_hash_type_long' => 'The session hash, obtained from $MadelineProto->account->getAuthorizations', 'method_account.getPassword' => 'Get the current password', 'method_account.getPasswordSettings' => 'Get the current 2FA settings', 'method_account.getPasswordSettings_param_current_password_hash_type_bytes' => 'Use only if you have set a 2FA password: `$current_salt = $MadelineProto->account->getPassword()[\'current_salt\']; $current_password_hash = hash(\'sha256\', $current_salt.$password.$current_salt, true);`', 'method_account.updatePasswordSettings' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'method_account.updatePasswordSettings_param_current_password_hash_type_bytes' => 'Use only if you have set a 2FA password: `$current_salt = $MadelineProto->account->getPassword()[\'current_salt\']; $current_password_hash = hash(\'sha256\', $current_salt.$password.$current_salt, true);`', 'method_account.updatePasswordSettings_param_new_settings_type_account.PasswordInputSettings' => 'New 2FA settings', 'method_account.sendConfirmPhoneCode' => 'Send confirmation phone code', 'method_account.sendConfirmPhoneCode_param_allow_flashcall_type_true' => 'Can telegram call you instead of sending an SMS?', 'method_account.sendConfirmPhoneCode_param_hash_type_string' => 'The hash', 'method_account.sendConfirmPhoneCode_param_current_number_type_Bool' => 'The current phone number', 'method_account.confirmPhone' => 'Confirm this phone number is associated to this account, obtain phone_code_hash from sendConfirmPhoneCode', 'method_account.confirmPhone_param_phone_code_hash_type_string' => 'Obtain phone_code_hash from sendConfirmPhoneCode', 'method_account.confirmPhone_param_phone_code_type_string' => 'The code sent by sendConfirmPhoneCode', 'method_account.getTmpPassword' => 'Get temporary password for buying products through bots', 'method_account.getTmpPassword_param_password_hash_type_bytes' => 'The password hash', 'method_account.getTmpPassword_param_period_type_int' => 'The validity period', 'method_account.getWebAuthorizations' => 'Get telegram web login authorizations', 'method_account.resetWebAuthorization' => 'Delete a certain telegram web login authorization', 'method_account.resetWebAuthorization_param_hash_type_long' => 'The authorization\'s hash', 'method_account.resetWebAuthorizations' => 'Reset all telegram web login authorizations', 'method_users.getUsers' => 'Get info about users', 'method_users.getUsers_param_id_type_Vector t' => 'The ids of the users', 'method_users.getFullUser' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_users.getFullUser_param_id_type_InputUser' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_contacts.getStatuses' => 'Get online status of all users', 'method_contacts.getContacts' => 'Get all contacts', 'method_contacts.getContacts_param_hash_type_int' => 'User ids of contacts previously fetched with this method', 'method_contacts.importContacts' => 'Add phone number as contact', 'method_contacts.importContacts_param_contacts_type_Vector t' => 'The numbers to import', 'method_contacts.deleteContact' => 'Delete a contact', 'method_contacts.deleteContact_param_id_type_InputUser' => 'The contact to delete', 'method_contacts.deleteContacts' => 'Delete multiple contacts', 'method_contacts.deleteContacts_param_id_type_Vector t' => 'The contacts to delete', 'method_contacts.block' => 'Block a user', 'method_contacts.block_param_id_type_InputUser' => 'The user to block', 'method_contacts.unblock' => 'Unblock a user', 'method_contacts.unblock_param_id_type_InputUser' => 'The user to unblock', 'method_contacts.getBlocked' => 'Get blocked users', 'method_contacts.getBlocked_param_offset_type_int' => 'Initially 0, then set to the number of blocked contacts previously fetched', 'method_contacts.getBlocked_param_limit_type_int' => 'How many blocked contacts to fetch', 'method_contacts.exportCard' => 'Export contact as card', 'method_contacts.importCard' => 'Import card as contact', 'method_contacts.importCard_param_export_card_type_Vector t' => 'The card', 'method_contacts.search' => 'Search contacts', 'method_contacts.search_param_q_type_string' => 'The search query', 'method_contacts.search_param_limit_type_int' => 'How many results should be returned', 'method_contacts.resolveUsername' => 'You cannot use this method directly, use the resolve_username, get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_contacts.resolveUsername_param_username_type_string' => 'You cannot use this method directly, use the resolve_username, get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_contacts.getTopPeers' => 'Get most used chats', 'method_contacts.getTopPeers_param_correspondents_type_true' => 'Fetch users?', 'method_contacts.getTopPeers_param_bots_pm_type_true' => 'Fetch bots?', 'method_contacts.getTopPeers_param_bots_inline_type_true' => 'Fetch inline bots?', 'method_contacts.getTopPeers_param_phone_calls_type_true' => 'Fetch phone calls?', 'method_contacts.getTopPeers_param_groups_type_true' => 'Fetch groups?', 'method_contacts.getTopPeers_param_channels_type_true' => 'Fetch channels and supergroups?', 'method_contacts.getTopPeers_param_offset_type_int' => 'Initially 0, then `$offset += $contacts_TopPeers[\'categories\'][\'count\'];`', 'method_contacts.getTopPeers_param_limit_type_int' => 'How many results to fetch', 'method_contacts.getTopPeers_param_hash_type_int' => 'Peer ids previously fetched with this method', 'method_contacts.resetTopPeerRating' => 'Reset top peer rating for a certain category/peer', 'method_contacts.resetTopPeerRating_param_category_type_TopPeerCategory' => 'The category ', 'method_contacts.resetTopPeerRating_param_peer_type_InputPeer' => 'The peer', 'method_contacts.resetSaved' => 'Reset saved contacts', 'method_messages.getMessages' => 'Get messages', 'method_messages.getMessages_param_id_type_Vector t' => 'The IDs of messages to fetch (only for users and normal groups)', 'method_messages.getDialogs' => 'Gets list of chats: you should use $MadelineProto->get_dialogs() instead: https://docs.madelineproto.xyz/docs/DIALOGS.html', 'method_messages.getDialogs_param_exclude_pinned_type_true' => 'Do not fetch pinned chats', 'method_messages.getDialogs_param_offset_date_type_int' => 'End($res[\'messages\'])[\'date\'];', 'method_messages.getDialogs_param_offset_id_type_int' => 'End($res[\'messages\'])[\'id\'];', 'method_messages.getDialogs_param_offset_peer_type_InputPeer' => 'End($res[\'dialogs\'])[\'peer\'];', 'method_messages.getDialogs_param_limit_type_int' => 'Number of dialogs to fetch', 'method_messages.getHistory' => 'Get previous messages of a group', 'method_messages.getHistory_param_peer_type_InputPeer' => 'The chat', 'method_messages.getHistory_param_offset_id_type_int' => 'The last fetched message ID, initially 0', 'method_messages.getHistory_param_offset_date_type_int' => 'The date of the last previously fetched message, initially 0', 'method_messages.getHistory_param_add_offset_type_int' => 'Additional offset, can be 0', 'method_messages.getHistory_param_limit_type_int' => 'Number of messages to fetch', 'method_messages.getHistory_param_max_id_type_int' => 'Maximum message ID to fetch', 'method_messages.getHistory_param_min_id_type_int' => 'Minumum message ID to fetch', 'method_messages.getHistory_param_hash_type_int' => 'List of IDs of already parsed messages', 'method_messages.search' => 'Search peers or messages', 'method_messages.search_param_peer_type_InputPeer' => 'Where to search', 'method_messages.search_param_q_type_string' => 'What to search', 'method_messages.search_param_from_id_type_InputUser' => 'Show only messages from a certain user?', 'method_messages.search_param_filter_type_MessagesFilter' => 'Message filter', 'method_messages.search_param_min_date_type_int' => 'Minumum date of results to fetch', 'method_messages.search_param_max_date_type_int' => 'Maximum date of results to fetch', 'method_messages.search_param_offset_id_type_int' => 'Message ID offset', 'method_messages.search_param_add_offset_type_int' => 'Additional offset, can be 0', 'method_messages.search_param_limit_type_int' => 'Number of results to return', 'method_messages.search_param_max_id_type_int' => 'Maximum message id to return', 'method_messages.search_param_min_id_type_int' => 'Minumum message id to return', 'method_messages.readHistory' => 'Mark messages as read', 'method_messages.readHistory_param_peer_type_InputPeer' => 'Where to mark messages as read', 'method_messages.readHistory_param_max_id_type_int' => 'Maximum message ID to mark as read', 'method_messages.deleteHistory' => 'Delete chat history', 'method_messages.deleteHistory_param_just_clear_type_true' => 'Only clear it from your side', 'method_messages.deleteHistory_param_peer_type_InputPeer' => 'Where to clear it', 'method_messages.deleteHistory_param_max_id_type_int' => 'Maximum message id of messages to delete', 'method_messages.deleteMessages' => 'Delete messages', 'method_messages.deleteMessages_param_revoke_type_true' => 'Delete the messages for everyone?', 'method_messages.deleteMessages_param_id_type_Vector t' => 'IDs of messages to delete, use channels->deleteMessages for supergroups', 'method_messages.receivedMessages' => 'Mark messages as read', 'method_messages.receivedMessages_param_max_id_type_int' => 'Maximum message id of messages to mark as read', 'method_messages.setTyping' => 'Change typing status', 'method_messages.setTyping_param_peer_type_InputPeer' => 'Where to change typing status', 'method_messages.setTyping_param_action_type_SendMessageAction' => 'Typing status', 'method_messages.sendMessage' => 'Send a message', 'method_messages.sendMessage_param_no_webpage_type_true' => 'Disable webpage preview?', 'method_messages.sendMessage_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendMessage_param_background_type_true' => 'Disable background notifications?', 'method_messages.sendMessage_param_clear_draft_type_true' => 'Clear the message draft of this chat?', 'method_messages.sendMessage_param_peer_type_InputPeer' => 'The chat where to send this message', 'method_messages.sendMessage_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendMessage_param_message_type_string' => 'The message to send', 'method_messages.sendMessage_param_reply_markup_type_ReplyMarkup' => 'Keyboards to send', 'method_messages.sendMessage_param_entities_type_Vector t' => 'Entities to send (for styled text)', 'method_messages.sendMedia' => 'Send a media', 'method_messages.sendMedia_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendMedia_param_background_type_true' => 'Disable background notifications?', 'method_messages.sendMedia_param_clear_draft_type_true' => 'Clear the message draft of this chat?', 'method_messages.sendMedia_param_peer_type_InputPeer' => 'Where to send the media', 'method_messages.sendMedia_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendMedia_param_media_type_InputMedia' => 'The media to send', 'method_messages.sendMedia_param_message_type_string' => 'The caption', 'method_messages.sendMedia_param_reply_markup_type_ReplyMarkup' => 'Keyboards to send', 'method_messages.sendMedia_param_entities_type_Vector t' => 'Entities for styled text', 'method_messages.forwardMessages' => 'Forward messages', 'method_messages.forwardMessages_param_silent_type_true' => 'Disable notifications', 'method_messages.forwardMessages_param_background_type_true' => 'Disable background notifications', 'method_messages.forwardMessages_param_with_my_score_type_true' => 'If forwarding a game, forward your score, too', 'method_messages.forwardMessages_param_grouped_type_true' => 'Set to true if forwarding albums', 'method_messages.forwardMessages_param_from_peer_type_InputPeer' => 'From where to forward the messages', 'method_messages.forwardMessages_param_id_type_Vector t' => 'The message IDs', 'method_messages.forwardMessages_param_to_peer_type_InputPeer' => 'Where to forward the messages', 'method_messages.reportSpam' => 'Report a peer for spam', 'method_messages.reportSpam_param_peer_type_InputPeer' => 'The peer to report', 'method_messages.hideReportSpam' => 'Hide report spam popup', 'method_messages.hideReportSpam_param_peer_type_InputPeer' => 'Where to hide the popup', 'method_messages.getPeerSettings' => 'Get the settings of apeer', 'method_messages.getPeerSettings_param_peer_type_InputPeer' => 'The peer', 'method_messages.getChats' => 'Get info about chats', 'method_messages.getChats_param_id_type_Vector t' => 'The MTProto IDs of chats to fetch info about', 'method_messages.getFullChat' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_messages.getFullChat_param_chat_id_type_InputPeer' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_messages.editChatTitle' => 'Edit the title of a normal chat (not supergroup)', 'method_messages.editChatTitle_param_chat_id_type_InputPeer' => 'The ID of the chat', 'method_messages.editChatTitle_param_title_type_string' => 'The new title', 'method_messages.editChatPhoto' => 'Edit the photo of a normal chat (not supergroup)', 'method_messages.editChatPhoto_param_chat_id_type_InputPeer' => 'The ID of the chat', 'method_messages.editChatPhoto_param_photo_type_InputChatPhoto' => 'The new phto', 'method_messages.addChatUser' => 'Add a user to a normal chat (use channels->inviteToChannel for supergroups)', 'method_messages.addChatUser_param_chat_id_type_InputPeer' => 'The chat where to invite users', 'method_messages.addChatUser_param_user_id_type_InputUser' => 'The user to invite', 'method_messages.addChatUser_param_fwd_limit_type_int' => 'Number of old messages the user will see', 'method_messages.deleteChatUser' => 'Delete a user from a chat (not supergroup)', 'method_messages.deleteChatUser_param_chat_id_type_InputPeer' => 'The ID of the chat', 'method_messages.deleteChatUser_param_user_id_type_InputUser' => 'The user to delete (pass @me to leave the chat)', 'method_messages.createChat' => 'Create a chat (not supergroup)', 'method_messages.createChat_param_users_type_Vector t' => 'The users to add to the chat', 'method_messages.createChat_param_title_type_string' => 'The new chat\'s title', 'method_messages.getDhConfig' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'method_messages.getDhConfig_param_version_type_int' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'method_messages.getDhConfig_param_random_length_type_int' => 'You cannot use this method directly, instead use $MadelineProto->get_dh_config();', 'method_messages.requestEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.requestEncryption_param_user_id_type_InputUser' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.requestEncryption_param_g_a_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption_param_peer_type_InputEncryptedChat' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption_param_g_b_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.acceptEncryption_param_key_fingerprint_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.discardEncryption' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.discardEncryption_param_chat_id_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling secret chats', 'method_messages.setEncryptedTyping' => 'Send typing notification to secret chat', 'method_messages.setEncryptedTyping_param_peer_type_InputEncryptedChat' => 'The secret chat where to send the notification', 'method_messages.setEncryptedTyping_param_typing_type_Bool' => 'Set to true to enable the notification, false to disable it', 'method_messages.readEncryptedHistory' => 'Mark messages as read in secret chats', 'method_messages.readEncryptedHistory_param_peer_type_InputEncryptedChat' => 'The secret chat where to mark messages as read', 'method_messages.readEncryptedHistory_param_max_date_type_int' => 'Maximum date of messages to mark', 'method_messages.sendEncrypted' => 'Send message to secret chat', 'method_messages.sendEncrypted_param_peer_type_InputEncryptedChat' => 'The chat where to send the message', 'method_messages.sendEncrypted_param_message_type_DecryptedMessage' => 'The message to send', 'method_messages.sendEncryptedFile' => 'Send a file to a secret chat', 'method_messages.sendEncryptedFile_param_peer_type_InputEncryptedChat' => 'The chat where to send the file', 'method_messages.sendEncryptedFile_param_message_type_DecryptedMessage' => 'The message with the file', 'method_messages.sendEncryptedFile_param_file_type_InputEncryptedFile' => 'The file (optional)', 'method_messages.sendEncryptedService' => 'Send a service message to a secret chat', 'method_messages.sendEncryptedService_param_peer_type_InputEncryptedChat' => 'The chat where to send the service message', 'method_messages.sendEncryptedService_param_message_type_DecryptedMessage' => 'The service message', 'method_messages.receivedQueue' => 'You cannot use this method directly', 'method_messages.receivedQueue_param_max_qts_type_int' => 'You cannot use this method directly', 'method_messages.reportEncryptedSpam' => 'Report for spam a secret chat', 'method_messages.reportEncryptedSpam_param_peer_type_InputEncryptedChat' => 'The chat to report', 'method_messages.readMessageContents' => 'Mark message as read', 'method_messages.readMessageContents_param_id_type_Vector t' => 'The messages to mark as read (only users and normal chats, not supergroups)', 'method_messages.getStickers' => 'Get stickers', 'method_messages.getStickers_param_emoticon_type_string' => 'Search by emoji', 'method_messages.getStickers_param_hash_type_string' => 'Previously fetched sticker IDs', 'method_messages.getAllStickers' => 'Get all stickerpacks', 'method_messages.getAllStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.getWebPagePreview' => 'Get webpage preview', 'method_messages.getWebPagePreview_param_message_type_string' => 'Extract preview from this message', 'method_messages.getWebPagePreview_param_entities_type_Vector t' => 'Entities for styled text', 'method_messages.exportChatInvite' => 'Export chat invite ', 'method_messages.exportChatInvite_param_chat_id_type_InputPeer' => 'The chat id ', 'method_messages.checkChatInvite' => 'Check if an invitation link is valid', 'method_messages.checkChatInvite_param_hash_type_string' => 'The invite link in t.me/joinchat/aflakf format', 'method_messages.importChatInvite' => 'Import chat invite', 'method_messages.importChatInvite_param_hash_type_string' => 'The invite link in t.me/joinchat/aflakf format', 'method_messages.getStickerSet' => 'Get a stickerset', 'method_messages.getStickerSet_param_stickerset_type_InputStickerSet' => 'The stickerset to get', 'method_messages.installStickerSet' => 'Add a sticker set', 'method_messages.installStickerSet_param_stickerset_type_InputStickerSet' => 'The sticker set to add', 'method_messages.installStickerSet_param_archived_type_Bool' => 'Archive this set?', 'method_messages.uninstallStickerSet' => 'Remove a sticker set', 'method_messages.uninstallStickerSet_param_stickerset_type_InputStickerSet' => 'The sticker set to remove', 'method_messages.startBot' => 'Start a bot', 'method_messages.startBot_param_bot_type_InputUser' => 'The bot\'s ID or username', 'method_messages.startBot_param_peer_type_InputPeer' => 'Where to start the bot (@me or group ID/username)', 'method_messages.startBot_param_start_param_type_string' => 'The bot\'s start parameter', 'method_messages.getMessagesViews' => 'Get and increase message views', 'method_messages.getMessagesViews_param_peer_type_InputPeer' => 'The chat where the message is located', 'method_messages.getMessagesViews_param_id_type_Vector t' => 'The IDs messages to get', 'method_messages.getMessagesViews_param_increment_type_Bool' => 'Increase message views?', 'method_messages.toggleChatAdmins' => 'Enable all users are admins in normal groups (not supergroups)', 'method_messages.toggleChatAdmins_param_chat_id_type_InputPeer' => 'Group ID', 'method_messages.toggleChatAdmins_param_enabled_type_Bool' => 'Enable all users are admins', 'method_messages.editChatAdmin' => 'Edit admin permissions', 'method_messages.editChatAdmin_param_chat_id_type_InputPeer' => 'The chat ID (no supergroups)', 'method_messages.editChatAdmin_param_user_id_type_InputUser' => 'The user ID', 'method_messages.editChatAdmin_param_is_admin_type_Bool' => 'Should the user be admin?', 'method_messages.migrateChat' => 'Convert chat to supergroup', 'method_messages.migrateChat_param_chat_id_type_InputPeer' => 'The chat to convert', 'method_messages.searchGlobal' => 'Global message search', 'method_messages.searchGlobal_param_q_type_string' => 'The query', 'method_messages.searchGlobal_param_offset_date_type_int' => '0 or the date offset', 'method_messages.searchGlobal_param_offset_peer_type_InputPeer' => '0 or the peer offset', 'method_messages.searchGlobal_param_offset_id_type_int' => '0 or the message ID offset', 'method_messages.searchGlobal_param_limit_type_int' => 'The number of results to return', 'method_messages.reorderStickerSets' => 'Reorder sticker sets', 'method_messages.reorderStickerSets_param_masks_type_true' => 'Reorder masks?', 'method_messages.reorderStickerSets_param_order_type_Vector t' => 'The order', 'method_messages.getDocumentByHash' => 'Get document by SHA256 hash', 'method_messages.getDocumentByHash_param_sha256_type_bytes' => '`hash(\'sha256\', $filename, true);`', 'method_messages.getDocumentByHash_param_size_type_int' => 'The file size', 'method_messages.getDocumentByHash_param_mime_type_type_string' => 'The mime type of the file', 'method_messages.searchGifs' => 'Search gifs', 'method_messages.searchGifs_param_q_type_string' => 'The search query', 'method_messages.searchGifs_param_offset_type_int' => 'The offset ', 'method_messages.getSavedGifs' => 'Get saved gifs', 'method_messages.getSavedGifs_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.saveGif' => 'Save a GIF', 'method_messages.saveGif_param_id_type_InputDocument' => 'The GIF to save', 'method_messages.saveGif_param_unsave_type_Bool' => 'Remove the gif?', 'method_messages.getInlineBotResults' => 'Call inline bot', 'method_messages.getInlineBotResults_param_bot_type_InputUser' => 'The bot to call', 'method_messages.getInlineBotResults_param_peer_type_InputPeer' => 'The chat where to call the bot', 'method_messages.getInlineBotResults_param_geo_point_type_InputGeoPoint' => 'The current location', 'method_messages.getInlineBotResults_param_query_type_string' => 'The query to send to the bot', 'method_messages.getInlineBotResults_param_offset_type_string' => 'The offset to send to the bot', 'method_messages.setInlineBotResults' => 'Bots only: set the results of an inline query', 'method_messages.setInlineBotResults_param_gallery_type_true' => 'Is this a gallery?', 'method_messages.setInlineBotResults_param_private_type_true' => 'Is this result private (not cached)?', 'method_messages.setInlineBotResults_param_query_id_type_long' => 'Query ID', 'method_messages.setInlineBotResults_param_results_type_Vector t' => 'Results', 'method_messages.setInlineBotResults_param_cache_time_type_int' => 'Cache time', 'method_messages.setInlineBotResults_param_next_offset_type_string' => 'The next offset', 'method_messages.setInlineBotResults_param_switch_pm_type_InlineBotSwitchPM' => 'Switch to PM?', 'method_messages.sendInlineBotResult' => 'Send inline bot result obtained with messages.getInlineBotResults to the chat', 'method_messages.sendInlineBotResult_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendInlineBotResult_param_background_type_true' => 'Disable background notifications?', 'method_messages.sendInlineBotResult_param_clear_draft_type_true' => 'Clear the message draft?', 'method_messages.sendInlineBotResult_param_peer_type_InputPeer' => 'Where to send the message', 'method_messages.sendInlineBotResult_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendInlineBotResult_param_query_id_type_long' => 'The inline query ID', 'method_messages.sendInlineBotResult_param_id_type_string' => 'The ID of one of the inline results', 'method_messages.getMessageEditData' => 'Check if about to edit a message or a media caption', 'method_messages.getMessageEditData_param_peer_type_InputPeer' => 'The chat', 'method_messages.getMessageEditData_param_id_type_int' => 'The message ID', 'method_messages.editMessage' => 'Edit a message', 'method_messages.editMessage_param_no_webpage_type_true' => 'Disable webpage preview', 'method_messages.editMessage_param_stop_geo_live_type_true' => 'Stop live location', 'method_messages.editMessage_param_peer_type_InputPeer' => 'The chat', 'method_messages.editMessage_param_id_type_int' => 'The message ID', 'method_messages.editMessage_param_message_type_string' => 'The new message', 'method_messages.editMessage_param_reply_markup_type_ReplyMarkup' => 'The new keyboard', 'method_messages.editMessage_param_entities_type_Vector t' => 'The new entities (for styled text)', 'method_messages.editMessage_param_geo_point_type_InputGeoPoint' => 'The new location', 'method_messages.editInlineBotMessage' => 'Edit a sent inline message', 'method_messages.editInlineBotMessage_param_no_webpage_type_true' => 'Disable webpage preview', 'method_messages.editInlineBotMessage_param_stop_geo_live_type_true' => 'Stop live location', 'method_messages.editInlineBotMessage_param_id_type_InputBotInlineMessageID' => 'The message ID', 'method_messages.editInlineBotMessage_param_message_type_string' => 'The new message', 'method_messages.editInlineBotMessage_param_reply_markup_type_ReplyMarkup' => 'The new keyboard', 'method_messages.editInlineBotMessage_param_entities_type_Vector t' => 'The new entities (for styled text)', 'method_messages.editInlineBotMessage_param_geo_point_type_InputGeoPoint' => 'The new location', 'method_messages.getBotCallbackAnswer' => 'Get the callback answer of a bot (after clicking a button)', 'method_messages.getBotCallbackAnswer_param_game_type_true' => 'Is this a game?', 'method_messages.getBotCallbackAnswer_param_peer_type_InputPeer' => 'The chat', 'method_messages.getBotCallbackAnswer_param_msg_id_type_int' => 'The message ID', 'method_messages.getBotCallbackAnswer_param_data_type_bytes' => 'The data to send to the bot', 'method_messages.setBotCallbackAnswer' => 'Bots only: set the callback answer (after a button was clicked)', 'method_messages.setBotCallbackAnswer_param_alert_type_true' => 'Is this an alert?', 'method_messages.setBotCallbackAnswer_param_query_id_type_long' => 'The query ID', 'method_messages.setBotCallbackAnswer_param_message_type_string' => 'The message', 'method_messages.setBotCallbackAnswer_param_url_type_string' => 'The URL', 'method_messages.setBotCallbackAnswer_param_cache_time_type_int' => 'Cache time', 'method_messages.getPeerDialogs' => 'Get dialog info of peers', 'method_messages.getPeerDialogs_param_peers_type_Vector t' => 'The peers', 'method_messages.saveDraft' => 'Save a message draft', 'method_messages.saveDraft_param_no_webpage_type_true' => 'Disable webpage preview', 'method_messages.saveDraft_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.saveDraft_param_peer_type_InputPeer' => 'The chat', 'method_messages.saveDraft_param_message_type_string' => 'The message', 'method_messages.saveDraft_param_entities_type_Vector t' => 'The entities (for styled text)', 'method_messages.getAllDrafts' => 'Get all message drafts', 'method_messages.getFeaturedStickers' => 'Get featured stickers', 'method_messages.getFeaturedStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.readFeaturedStickers' => 'Mark new featured stickers as read', 'method_messages.readFeaturedStickers_param_id_type_Vector t' => 'The stickers to mark as read', 'method_messages.getRecentStickers' => 'Get recent stickers', 'method_messages.getRecentStickers_param_attached_type_true' => 'Get stickers attached to image?', 'method_messages.getRecentStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.saveRecentSticker' => 'Add a sticker to recent stickers', 'method_messages.saveRecentSticker_param_attached_type_true' => 'Get stickers attached to image?', 'method_messages.saveRecentSticker_param_id_type_InputDocument' => 'The sticker', 'method_messages.saveRecentSticker_param_unsave_type_Bool' => 'Remove the sticker from recent stickers?', 'method_messages.clearRecentStickers' => 'Clear all recent stickers', 'method_messages.clearRecentStickers_param_attached_type_true' => 'Clear recent stickers attached to images?', 'method_messages.getArchivedStickers' => 'Get all archived stickers', 'method_messages.getArchivedStickers_param_masks_type_true' => 'Get masks?', 'method_messages.getArchivedStickers_param_offset_id_type_long' => 'Sticker ID offset', 'method_messages.getArchivedStickers_param_limit_type_int' => 'Number of stickers to fetch', 'method_messages.getMaskStickers' => 'Get masks', 'method_messages.getMaskStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.getAttachedStickers' => 'Get stickers attachable to images', 'method_messages.getAttachedStickers_param_media_type_InputStickeredMedia' => 'The stickered media', 'method_messages.setGameScore' => 'Set the game score', 'method_messages.setGameScore_param_edit_message_type_true' => 'Should the message with the game be edited?', 'method_messages.setGameScore_param_force_type_true' => 'Force setting the game score', 'method_messages.setGameScore_param_peer_type_InputPeer' => 'The chat where the game was sent', 'method_messages.setGameScore_param_id_type_int' => 'The message ID', 'method_messages.setGameScore_param_user_id_type_InputUser' => 'The user that set the score', 'method_messages.setGameScore_param_score_type_int' => 'The score', 'method_messages.setInlineGameScore' => 'Set the game score of an inline message', 'method_messages.setInlineGameScore_param_edit_message_type_true' => 'Should the message with the game be edited?', 'method_messages.setInlineGameScore_param_force_type_true' => 'Force setting the game score', 'method_messages.setInlineGameScore_param_id_type_InputBotInlineMessageID' => 'The ID of the inline message', 'method_messages.setInlineGameScore_param_user_id_type_InputUser' => 'The user that set the score', 'method_messages.setInlineGameScore_param_score_type_int' => 'The score', 'method_messages.getGameHighScores' => 'Get high scores of a game', 'method_messages.getGameHighScores_param_peer_type_InputPeer' => 'The chat', 'method_messages.getGameHighScores_param_id_type_int' => 'The message ID', 'method_messages.getGameHighScores_param_user_id_type_InputUser' => 'The user that set the high scores', 'method_messages.getInlineGameHighScores' => 'Get high scores of a game sent in an inline message', 'method_messages.getInlineGameHighScores_param_id_type_InputBotInlineMessageID' => 'The inline message', 'method_messages.getInlineGameHighScores_param_user_id_type_InputUser' => 'The user that set the high scores', 'method_messages.getCommonChats' => 'Get chats in common with a user', 'method_messages.getCommonChats_param_user_id_type_InputUser' => 'The user', 'method_messages.getCommonChats_param_max_id_type_int' => 'The maximum chat ID to fetch', 'method_messages.getCommonChats_param_limit_type_int' => 'Number of results to fetch', 'method_messages.getAllChats' => 'Get all chats (not supergroups or channels)', 'method_messages.getAllChats_param_except_ids_type_Vector t' => 'Do not fetch these chats (MTProto id)', 'method_messages.getWebPage' => 'Get webpage preview', 'method_messages.getWebPage_param_url_type_string' => 'URL', 'method_messages.getWebPage_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.toggleDialogPin' => 'Pin or unpin dialog', 'method_messages.toggleDialogPin_param_pinned_type_true' => 'Pin or unpin the dialog?', 'method_messages.toggleDialogPin_param_peer_type_InputPeer' => 'The peer to pin', 'method_messages.reorderPinnedDialogs' => 'Reorder pinned dialogs', 'method_messages.reorderPinnedDialogs_param_force_type_true' => 'Force reordering', 'method_messages.reorderPinnedDialogs_param_order_type_Vector t' => 'New order', 'method_messages.getPinnedDialogs' => 'Get pinned dialogs', 'method_messages.setBotShippingResults' => 'Bots only: set shipping results', 'method_messages.setBotShippingResults_param_query_id_type_long' => 'Query ID', 'method_messages.setBotShippingResults_param_error_type_string' => 'Error', 'method_messages.setBotShippingResults_param_shipping_options_type_Vector t' => 'Shipping options', 'method_messages.setBotPrecheckoutResults' => 'Bots only: set precheckout results', 'method_messages.setBotPrecheckoutResults_param_success_type_true' => 'Success?', 'method_messages.setBotPrecheckoutResults_param_query_id_type_long' => 'Query ID', 'method_messages.setBotPrecheckoutResults_param_error_type_string' => 'Error', 'method_messages.uploadMedia' => 'Upload a file without sending it to anyone', 'method_messages.uploadMedia_param_peer_type_InputPeer' => 'Nothing', 'method_messages.uploadMedia_param_media_type_InputMedia' => 'The media to upload', 'method_messages.sendScreenshotNotification' => 'Send screenshot notification', 'method_messages.sendScreenshotNotification_param_peer_type_InputPeer' => 'Where to send the notification', 'method_messages.sendScreenshotNotification_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.getFavedStickers' => 'Get favorite stickers', 'method_messages.getFavedStickers_param_hash_type_int' => '0 or $result[\'hash\']', 'method_messages.faveSticker' => 'Add a sticker to favorites', 'method_messages.faveSticker_param_id_type_InputDocument' => 'The sticker to add to favorites', 'method_messages.faveSticker_param_unfave_type_Bool' => 'Remove it from favorites?', 'method_messages.getUnreadMentions' => 'Get unread mentions', 'method_messages.getUnreadMentions_param_peer_type_InputPeer' => 'The chat where to get unread mentions', 'method_messages.getUnreadMentions_param_offset_id_type_int' => 'The offset', 'method_messages.getUnreadMentions_param_add_offset_type_int' => 'The additional offset', 'method_messages.getUnreadMentions_param_limit_type_int' => 'The number of results to fetch', 'method_messages.getUnreadMentions_param_max_id_type_int' => 'The maximum message ID to fetch', 'method_messages.getUnreadMentions_param_min_id_type_int' => 'The minumum message ID to fetch', 'method_messages.readMentions' => 'Mark mentions as read', 'method_messages.readMentions_param_peer_type_InputPeer' => 'The chat', 'method_messages.getRecentLocations' => 'Get recent locations', 'method_messages.getRecentLocations_param_peer_type_InputPeer' => 'The chat where to search locations', 'method_messages.getRecentLocations_param_limit_type_int' => 'Number of results to return', 'method_messages.sendMultiMedia' => 'Send an album', 'method_messages.sendMultiMedia_param_silent_type_true' => 'Disable notifications?', 'method_messages.sendMultiMedia_param_background_type_true' => 'Disable background notification?', 'method_messages.sendMultiMedia_param_clear_draft_type_true' => 'Clear draft?', 'method_messages.sendMultiMedia_param_peer_type_InputPeer' => 'Where to send the album', 'method_messages.sendMultiMedia_param_reply_to_msg_id_type_int' => 'Reply to message by ID', 'method_messages.sendMultiMedia_param_multi_media_type_Vector t' => 'The album', 'method_messages.uploadEncryptedFile' => 'Upload a secret chat file without sending it to anyone', 'method_messages.uploadEncryptedFile_param_peer_type_InputEncryptedChat' => 'The chat where to upload the media', 'method_messages.uploadEncryptedFile_param_file_type_InputEncryptedFile' => 'The file', 'method_updates.getState' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_pts_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_pts_total_limit_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_date_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getDifference_param_qts_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_force_type_true' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_channel_type_InputChannel' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_filter_type_ChannelMessagesFilter' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_pts_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_updates.getChannelDifference_param_limit_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_photos.updateProfilePhoto' => 'Change the profile photo', 'method_photos.updateProfilePhoto_param_id_type_InputPhoto' => 'The photo to use', 'method_photos.uploadProfilePhoto' => 'Upload profile photo', 'method_photos.uploadProfilePhoto_param_file_type_InputFile' => 'The photo', 'method_photos.deletePhotos' => 'Delete profile photos', 'method_photos.deletePhotos_param_id_type_Vector t' => 'The profile photos to delete', 'method_photos.getUserPhotos' => 'Get the profile photos of a user', 'method_photos.getUserPhotos_param_user_id_type_InputUser' => 'The user', 'method_photos.getUserPhotos_param_offset_type_int' => 'Offset', 'method_photos.getUserPhotos_param_max_id_type_long' => 'Maximum ID of photo to return', 'method_photos.getUserPhotos_param_limit_type_int' => 'Number of photos to return', 'method_upload.saveFilePart' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveFilePart_param_file_id_type_long' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveFilePart_param_file_part_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveFilePart_param_bytes_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile_param_location_type_InputFileLocation' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile_param_offset_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getFile_param_limit_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_file_id_type_long' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_file_part_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_file_total_parts_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.saveBigFilePart_param_bytes_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getWebFile' => 'Download a file through telegram', 'method_upload.getWebFile_param_location_type_InputWebFileLocation' => 'The file', 'method_upload.getWebFile_param_offset_type_int' => 'The offset in bytes', 'method_upload.getWebFile_param_limit_type_int' => 'The number of bytes to fetch', 'method_upload.getCdnFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFile_param_file_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFile_param_offset_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFile_param_limit_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.reuploadCdnFile' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.reuploadCdnFile_param_file_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.reuploadCdnFile_param_request_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFileHashes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFileHashes_param_file_token_type_bytes' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_upload.getCdnFileHashes_param_offset_type_int' => 'You cannot use this method directly, use the upload, download_to_stream, download_to_file, download_to_dir methods instead; see https://docs.madelineproto.xyz for more info', 'method_help.getConfig' => 'Get server configuration', 'method_help.getNearestDc' => 'Get nearest datacenter', 'method_help.getAppUpdate' => 'Get info about app updates', 'method_help.saveAppLog' => 'Log data for developer of this app', 'method_help.saveAppLog_param_events_type_Vector t' => 'Event list', 'method_help.getInviteText' => 'Get invitation text', 'method_help.getSupport' => 'Get info of support user', 'method_help.getAppChangelog' => 'Get the changelog of this app', 'method_help.getAppChangelog_param_prev_app_version_type_string' => 'Previous app version', 'method_help.getTermsOfService' => 'Get terms of service', 'method_help.setBotUpdatesStatus' => 'Set the update status of webhook', 'method_help.setBotUpdatesStatus_param_pending_updates_count_type_int' => 'Pending update count', 'method_help.setBotUpdatesStatus_param_message_type_string' => 'Message', 'method_help.getCdnConfig' => 'Get CDN configuration', 'method_help.getRecentMeUrls' => 'Get recent t.me URLs', 'method_help.getRecentMeUrls_param_referer_type_string' => 'Referrer', 'method_channels.readHistory' => 'Mark channel/supergroup history as read', 'method_channels.readHistory_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.readHistory_param_max_id_type_int' => 'Maximum message ID to mark as read', 'method_channels.deleteMessages' => 'Delete channel/supergroup messages', 'method_channels.deleteMessages_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.deleteMessages_param_id_type_Vector t' => 'The IDs of messages to delete', 'method_channels.deleteUserHistory' => 'Delete all messages of a user in a channel/supergroup', 'method_channels.deleteUserHistory_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.deleteUserHistory_param_user_id_type_InputUser' => 'The user', 'method_channels.reportSpam' => 'Report a message in a supergroup/channel for spam', 'method_channels.reportSpam_param_channel_type_InputChannel' => 'The channel', 'method_channels.reportSpam_param_user_id_type_InputUser' => 'The user that sent the messages', 'method_channels.reportSpam_param_id_type_Vector t' => 'The IDs of messages to report', 'method_channels.getMessages' => 'Get channel/supergroup messages', 'method_channels.getMessages_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.getMessages_param_id_type_Vector t' => 'The message IDs', 'method_channels.getParticipants' => 'Get channel/supergroup participants (you should use `$MadelineProto->get_pwr_chat($id)` instead)', 'method_channels.getParticipants_param_channel_type_InputChannel' => 'The channel', 'method_channels.getParticipants_param_filter_type_ChannelParticipantsFilter' => 'Member filter', 'method_channels.getParticipants_param_offset_type_int' => 'Offset', 'method_channels.getParticipants_param_limit_type_int' => 'Limit', 'method_channels.getParticipants_param_hash_type_int' => 'Sorted list of IDs of participants you already fetched', 'method_channels.getParticipant' => 'Get info about a certain channel/supergroup participant', 'method_channels.getParticipant_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.getParticipant_param_user_id_type_InputUser' => 'The user to fetch info about', 'method_channels.getChannels' => 'Get info about multiple channels/supergroups', 'method_channels.getChannels_param_id_type_Vector t' => 'The channel/supergroup MTProto IDs', 'method_channels.getFullChannel' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_channels.getFullChannel_param_channel_type_InputChannel' => 'You cannot use this method directly, use the get_pwr_chat, get_info, get_full_info methods instead (see https://docs.madelineproto.xyz for more info)', 'method_channels.createChannel' => 'Create channel/supergroup', 'method_channels.createChannel_param_broadcast_type_true' => 'Set this to true to create a channel', 'method_channels.createChannel_param_megagroup_type_true' => 'Set this to true to create a supergroup', 'method_channels.createChannel_param_title_type_string' => 'Supergroup/channel title', 'method_channels.createChannel_param_about_type_string' => 'About text', 'method_channels.editAbout' => 'Edit the about text of a channel/supergroup', 'method_channels.editAbout_param_channel_type_InputChannel' => 'The channel', 'method_channels.editAbout_param_about_type_string' => 'The new about text', 'method_channels.editAdmin' => 'Edit admin permissions of a user in a channel/supergroup', 'method_channels.editAdmin_param_channel_type_InputChannel' => 'The channel', 'method_channels.editAdmin_param_user_id_type_InputUser' => 'The user', 'method_channels.editAdmin_param_admin_rights_type_ChannelAdminRights' => 'The new admin rights', 'method_channels.editTitle' => 'Edit the title of a supergroup/channel', 'method_channels.editTitle_param_channel_type_InputChannel' => 'The channel', 'method_channels.editTitle_param_title_type_string' => 'The new channel/supergroup title', 'method_channels.editPhoto' => 'Edit the photo of a supergroup/channel', 'method_channels.editPhoto_param_channel_type_InputChannel' => 'The channel', 'method_channels.editPhoto_param_photo_type_InputChatPhoto' => 'The new photo', 'method_channels.checkUsername' => 'Check if this username is free and can be assigned to a channel/supergroup', 'method_channels.checkUsername_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.checkUsername_param_username_type_string' => 'The new username for this channel/supergroup', 'method_channels.updateUsername' => 'Update the username of a supergroup/channel', 'method_channels.updateUsername_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.updateUsername_param_username_type_string' => 'The new username', 'method_channels.joinChannel' => 'Join a channel/supergroup', 'method_channels.joinChannel_param_channel_type_InputChannel' => 'The channel/supergroup to join', 'method_channels.leaveChannel' => 'Leave a channel/supergroup', 'method_channels.leaveChannel_param_channel_type_InputChannel' => 'The channel/supergroup to leave', 'method_channels.inviteToChannel' => 'Add users to channel/supergroup', 'method_channels.inviteToChannel_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.inviteToChannel_param_users_type_Vector t' => 'The users to add', 'method_channels.exportInvite' => 'Export the invite link of a channel', 'method_channels.exportInvite_param_channel_type_InputChannel' => 'The channel', 'method_channels.deleteChannel' => 'Delete a channel/supergroup', 'method_channels.deleteChannel_param_channel_type_InputChannel' => 'The channel/supergroup to delete', 'method_channels.toggleInvites' => 'Allow or disallow any user to invite users to this channel/supergroup', 'method_channels.toggleInvites_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.toggleInvites_param_enabled_type_Bool' => 'Allow or disallow', 'method_channels.exportMessageLink' => 'Get the link of a message in a channel', 'method_channels.exportMessageLink_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.exportMessageLink_param_id_type_int' => 'The ID of the message', 'method_channels.exportMessageLink_param_grouped_type_Bool' => 'Is this an album?', 'method_channels.toggleSignatures' => 'Toggle channel signatures', 'method_channels.toggleSignatures_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.toggleSignatures_param_enabled_type_Bool' => 'Enable or disable channel signatures?', 'method_channels.updatePinnedMessage' => 'Set the pinned message of a channel/supergroup', 'method_channels.updatePinnedMessage_param_silent_type_true' => 'Pin silently', 'method_channels.updatePinnedMessage_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.updatePinnedMessage_param_id_type_int' => 'The ID of the message to pin', 'method_channels.getAdminedPublicChannels' => 'Get all supergroups/channels where you\'re admin', 'method_channels.editBanned' => 'Kick or ban a user from a channel/supergroup', 'method_channels.editBanned_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.editBanned_param_user_id_type_InputUser' => 'The user to kick/ban', 'method_channels.editBanned_param_banned_rights_type_ChannelBannedRights' => 'Banned/kicked permissions', 'method_channels.getAdminLog' => 'Get admin log of a channel/supergroup', 'method_channels.getAdminLog_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.getAdminLog_param_q_type_string' => 'Search query', 'method_channels.getAdminLog_param_events_filter_type_ChannelAdminLogEventsFilter' => 'Event filter', 'method_channels.getAdminLog_param_admins_type_Vector t' => 'Fetch only actions from these admins', 'method_channels.getAdminLog_param_max_id_type_long' => 'Maximum message ID to fetch', 'method_channels.getAdminLog_param_min_id_type_long' => 'Minimum message ID to fetch', 'method_channels.getAdminLog_param_limit_type_int' => 'Number of results to fetch', 'method_channels.setStickers' => 'Set the supergroup/channel stickerpack', 'method_channels.setStickers_param_channel_type_InputChannel' => 'The channel/supergoup', 'method_channels.setStickers_param_stickerset_type_InputStickerSet' => 'The stickerset', 'method_channels.readMessageContents' => 'Mark channel/supergroup messages as read', 'method_channels.readMessageContents_param_channel_type_InputChannel' => 'The channel', 'method_channels.readMessageContents_param_id_type_Vector t' => 'List of message IDs', 'method_channels.deleteHistory' => 'Delete the history of a supergroup/channel', 'method_channels.deleteHistory_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.deleteHistory_param_max_id_type_int' => 'Maximum message ID to delete', 'method_channels.togglePreHistoryHidden' => 'Enable or disable hidden history for new channel/supergroup users', 'method_channels.togglePreHistoryHidden_param_channel_type_InputChannel' => 'The channel/supergroup', 'method_channels.togglePreHistoryHidden_param_enabled_type_Bool' => 'Enable or disable hidden history for new channel/supergroup users', 'method_bots.sendCustomRequest' => 'Send a custom request to the bot API', 'method_bots.sendCustomRequest_param_custom_method_type_string' => 'The method to call', 'method_bots.sendCustomRequest_param_params_type_DataJSON' => 'Method parameters', 'method_bots.answerWebhookJSONQuery' => 'Send webhook request via bot API', 'method_bots.answerWebhookJSONQuery_param_query_id_type_long' => 'The query ID', 'method_bots.answerWebhookJSONQuery_param_data_type_DataJSON' => 'The parameters', 'method_payments.getPaymentForm' => 'Get payment form', 'method_payments.getPaymentForm_param_msg_id_type_int' => 'Message ID', 'method_payments.getPaymentReceipt' => 'Get payment receipt', 'method_payments.getPaymentReceipt_param_msg_id_type_int' => 'The message ID', 'method_payments.validateRequestedInfo' => 'Validate requested payment info', 'method_payments.validateRequestedInfo_param_save_type_true' => 'Save payment info?', 'method_payments.validateRequestedInfo_param_msg_id_type_int' => 'The message ID', 'method_payments.validateRequestedInfo_param_info_type_PaymentRequestedInfo' => 'The requested payment info', 'method_payments.sendPaymentForm' => 'Bots only: send payment form', 'method_payments.sendPaymentForm_param_msg_id_type_int' => 'Message ID', 'method_payments.sendPaymentForm_param_requested_info_id_type_string' => 'ID of requested info', 'method_payments.sendPaymentForm_param_shipping_option_id_type_string' => 'Shipping option ID', 'method_payments.sendPaymentForm_param_credentials_type_InputPaymentCredentials' => 'Payment credentials', 'method_payments.getSavedInfo' => 'Get saved payments info', 'method_payments.clearSavedInfo' => 'Clear saved payments info', 'method_payments.clearSavedInfo_param_credentials_type_true' => 'Clear credentials?', 'method_payments.clearSavedInfo_param_info_type_true' => 'Clear payment info?', 'method_stickers.createStickerSet' => 'Create stickerset', 'method_stickers.createStickerSet_param_masks_type_true' => 'Masks?', 'method_stickers.createStickerSet_param_user_id_type_InputUser' => 'The user ID associated to this stickerset', 'method_stickers.createStickerSet_param_title_type_string' => 'The stickerset title', 'method_stickers.createStickerSet_param_short_name_type_string' => 'The stickerset short name', 'method_stickers.createStickerSet_param_stickers_type_Vector t' => 'The stickers to add', 'method_stickers.removeStickerFromSet' => 'Remove sticker from stickerset', 'method_stickers.removeStickerFromSet_param_sticker_type_InputDocument' => 'The sticker to remove', 'method_stickers.changeStickerPosition' => 'Change sticker position in photo', 'method_stickers.changeStickerPosition_param_sticker_type_InputDocument' => 'The sticker', 'method_stickers.changeStickerPosition_param_position_type_int' => 'New position', 'method_stickers.addStickerToSet' => 'Add sticker to stickerset', 'method_stickers.addStickerToSet_param_stickerset_type_InputStickerSet' => 'The stickerset', 'method_stickers.addStickerToSet_param_sticker_type_InputStickerSetItem' => 'The sticker', 'method_phone.getCallConfig' => 'Get call configuration', 'method_phone.requestCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.requestCall_param_user_id_type_InputUser' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.requestCall_param_g_a_hash_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.requestCall_param_protocol_type_PhoneCallProtocol' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_peer_type_InputPhoneCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_g_b_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_protocol_type_PhoneCallProtocol' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_peer_type_InputPhoneCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_g_a_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_key_fingerprint_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.confirmCall_param_protocol_type_PhoneCallProtocol' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.receivedCall' => 'Notify server that you received a call (server will refuse all incoming calls until the current call is over)', 'method_phone.receivedCall_param_peer_type_InputPhoneCall' => 'The phone call you received', 'method_phone.discardCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_peer_type_InputPhoneCall' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_duration_type_int' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_reason_type_PhoneCallDiscardReason' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.discardCall_param_connection_id_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.setCallRating' => 'Set phone call rating', 'method_phone.setCallRating_param_peer_type_InputPhoneCall' => 'The phone call', 'method_phone.setCallRating_param_rating_type_int' => 'Rating (1-5 stars)', 'method_phone.setCallRating_param_comment_type_string' => 'An optional comment', 'method_phone.saveCallDebug' => 'Save call debugging info', 'method_phone.saveCallDebug_param_peer_type_InputPhoneCall' => 'The call', 'method_phone.saveCallDebug_param_debug_type_DataJSON' => 'Debugging info', 'method_langpack.getLangPack' => 'Get language pack', 'method_langpack.getLangPack_param_lang_code_type_string' => 'Language code', 'method_langpack.getStrings' => 'Get language pack strings', 'method_langpack.getStrings_param_lang_code_type_string' => 'Language code', 'method_langpack.getStrings_param_keys_type_Vector t' => 'Keys', 'method_langpack.getDifference' => 'Get language pack updates', 'method_langpack.getDifference_param_from_version_type_int' => 'Previous version', 'method_langpack.getLanguages' => 'Get available languages', 'method_auth.sendCode_param_sms_type_type_int' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.sendCode_param_lang_code_type_string' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.sendCall' => 'Send verification phone call', 'method_auth.sendCall_param_phone_number_type_string' => 'The phone number', 'method_auth.sendCall_param_phone_code_hash_type_string' => 'The phone code hash', 'method_account.registerDevice_param_device_model_type_string' => 'Device model', 'method_account.registerDevice_param_system_version_type_string' => 'System version', 'method_account.registerDevice_param_app_version_type_string' => 'App version', 'method_account.registerDevice_param_lang_code_type_string' => 'Language code', 'method_contacts.getContacts_param_hash_type_string' => 'List of contact user IDs you already cached', 'method_contacts.importContacts_param_replace_type_Bool' => 'Replace contacts?', 'method_contacts.getSuggested' => 'Get suggested contacts', 'method_contacts.getSuggested_param_limit_type_int' => 'Number of results to return', 'method_messages.getDialogs_param_offset_type_int' => 'Offset', 'method_messages.getDialogs_param_max_id_type_int' => 'Maximum ID of result to return', 'method_messages.getHistory_param_offset_type_int' => 'Message ID offset', 'method_messages.search_param_offset_type_int' => 'Offset ', 'method_messages.readHistory_param_offset_type_int' => 'Offset', 'method_messages.readHistory_param_read_contents_type_Bool' => 'Mark messages as read?', 'method_messages.deleteHistory_param_offset_type_int' => 'Offset', 'method_messages.forwardMessages_param_peer_type_InputPeer' => 'Peer', 'method_photos.updateProfilePhoto_param_crop_type_InputPhotoCrop' => 'Cropping info', 'method_photos.uploadProfilePhoto_param_caption_type_string' => 'Caption type', 'method_photos.uploadProfilePhoto_param_geo_point_type_InputGeoPoint' => 'Location', 'method_photos.uploadProfilePhoto_param_crop_type_InputPhotoCrop' => 'Cropping info', 'method_help.getAppUpdate_param_device_model_type_string' => 'Device model', 'method_help.getAppUpdate_param_system_version_type_string' => 'System version', 'method_help.getAppUpdate_param_app_version_type_string' => 'App version', 'method_help.getAppUpdate_param_lang_code_type_string' => 'Langauge code', 'method_help.getInviteText_param_lang_code_type_string' => 'Language', 'method_photos.getUserPhotos_param_max_id_type_int' => 'Maximum ID of photo to return', 'method_messages.forwardMessage' => 'Forward message', 'method_messages.forwardMessage_param_peer_type_InputPeer' => 'From where to forward the message', 'method_messages.forwardMessage_param_id_type_int' => 'The message ID', 'method_messages.sendBroadcast' => 'Send a message to all users in the chat list', 'method_messages.sendBroadcast_param_contacts_type_Vector t' => 'The users to which send the message', 'method_messages.sendBroadcast_param_message_type_string' => 'The message', 'method_messages.sendBroadcast_param_media_type_InputMedia' => 'The media', 'method_auth.sendSms' => 'Send SMS verification code', 'method_auth.sendSms_param_phone_number_type_string' => 'Phone number', 'method_auth.sendSms_param_phone_code_hash_type_string' => 'Phone code ash', 'method_invokeWithLayer18' => 'Invoke this method with layer 18', 'method_invokeWithLayer18_param_query_type_!X' => 'The method call', 'method_messages.getAllStickers_param_hash_type_string' => 'Previously fetched stickers', 'method_geochats.getLocated' => 'Get nearby geochats', 'method_geochats.getLocated_param_geo_point_type_InputGeoPoint' => 'Current location', 'method_geochats.getLocated_param_radius_type_int' => 'Radius', 'method_geochats.getLocated_param_limit_type_int' => 'Number of results to return', 'method_geochats.getRecents' => 'Get recent geochats', 'method_geochats.getRecents_param_offset_type_int' => 'Offset', 'method_geochats.getRecents_param_limit_type_int' => 'Number of results to return', 'method_geochats.checkin' => 'Join a geochat', 'method_geochats.checkin_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.getFullChat' => 'Get full info about a geochat', 'method_geochats.getFullChat_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.editChatTitle' => 'Edit geochat title', 'method_geochats.editChatTitle_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.editChatTitle_param_title_type_string' => 'The new title', 'method_geochats.editChatTitle_param_address_type_string' => 'The new address', 'method_geochats.editChatPhoto' => 'Edit geochat photo', 'method_geochats.editChatPhoto_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.editChatPhoto_param_photo_type_InputChatPhoto' => 'The new photo', 'method_geochats.search' => 'Search messages in geocha', 'method_geochats.search_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.search_param_q_type_string' => 'The search query', 'method_geochats.search_param_filter_type_MessagesFilter' => 'Search filter', 'method_geochats.search_param_min_date_type_int' => 'Minumum date', 'method_geochats.search_param_max_date_type_int' => 'Maximum date', 'method_geochats.search_param_offset_type_int' => 'Offset', 'method_geochats.search_param_max_id_type_int' => 'Maximum message ID', 'method_geochats.search_param_limit_type_int' => 'Number of results to return', 'method_geochats.getHistory' => 'Get geochat history', 'method_geochats.getHistory_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.getHistory_param_offset_type_int' => 'Offset', 'method_geochats.getHistory_param_max_id_type_int' => 'Maximum message ID', 'method_geochats.getHistory_param_limit_type_int' => 'Number of results to return', 'method_geochats.setTyping' => 'Send typing notification to geochat', 'method_geochats.setTyping_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.setTyping_param_typing_type_Bool' => 'Typing or not typing', 'method_geochats.sendMessage' => 'Send message to geochat', 'method_geochats.sendMessage_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.sendMessage_param_message_type_string' => 'The message', 'method_geochats.sendMedia' => 'Send media to geochat', 'method_geochats.sendMedia_param_peer_type_InputGeoChat' => 'The geochat', 'method_geochats.sendMedia_param_media_type_InputMedia' => 'The media', 'method_geochats.createGeoChat' => 'Create geochat', 'method_geochats.createGeoChat_param_title_type_string' => 'Geochat title', 'method_geochats.createGeoChat_param_geo_point_type_InputGeoPoint' => 'Geochat location', 'method_geochats.createGeoChat_param_address_type_string' => 'Geochat address', 'method_geochats.createGeoChat_param_venue_type_string' => 'Geochat venue ', 'method_account.setPassword' => 'Set 2FA password', 'method_account.setPassword_param_current_password_hash_type_bytes' => 'Use only if you have set a 2FA password: `$current_salt = $MadelineProto->account->getPassword()[\'current_salt\']; $current_password_hash = hash(\'sha256\', $current_salt.$password.$current_salt, true);`', 'method_account.setPassword_param_new_salt_type_bytes' => 'New salt', 'method_account.setPassword_param_new_password_hash_type_bytes' => '`hash(\'sha256\', $new_salt.$new_password.$new_salt, true)`', 'method_account.setPassword_param_hint_type_string' => 'Hint', 'method_messages.installStickerSet_param_disabled_type_Bool' => 'Disable stickerset?', 'method_messages.startBot_param_chat_id_type_InputPeer' => 'Chat ID', 'method_help.getAppChangelog_param_device_model_type_string' => 'Device model', 'method_help.getAppChangelog_param_system_version_type_string' => 'System version', 'method_help.getAppChangelog_param_app_version_type_string' => 'App version', 'method_help.getAppChangelog_param_lang_code_type_string' => 'Language code', 'method_channels.getDialogs' => 'Get channel dialogs', 'method_channels.getDialogs_param_offset_type_int' => 'Offset', 'method_channels.getDialogs_param_limit_type_int' => 'Number of results to return', 'method_channels.getImportantHistory' => 'Get important channel/supergroup history', 'method_channels.getImportantHistory_param_channel_type_InputChannel' => 'The supergroup/channel', 'method_channels.getImportantHistory_param_offset_id_type_int' => 'Message ID offset', 'method_channels.getImportantHistory_param_add_offset_type_int' => 'Additional offset', 'method_channels.getImportantHistory_param_limit_type_int' => 'Number of results to return', 'method_channels.getImportantHistory_param_max_id_type_int' => 'Maximum message ID', 'method_channels.getImportantHistory_param_min_id_type_int' => 'Minumum message ID', 'method_channels.createChannel_param_users_type_Vector t' => 'Users to add to channel', 'method_channels.editAdmin_param_role_type_ChannelParticipantRole' => 'User role', 'method_channels.toggleComments' => 'Enable channel comments', 'method_channels.toggleComments_param_channel_type_InputChannel' => 'The channel ', 'method_channels.toggleComments_param_enabled_type_Bool' => 'Enable or disable comments', 'method_channels.kickFromChannel' => 'Kick user from channel', 'method_channels.kickFromChannel_param_channel_type_InputChannel' => 'The channel', 'method_channels.kickFromChannel_param_user_id_type_InputUser' => 'The user to kick', 'method_channels.kickFromChannel_param_kicked_type_Bool' => 'Kick or unkick?', 'method_messages.getChannelDialogs' => 'Get channel/supergruop dialogs', 'method_messages.getChannelDialogs_param_offset_type_int' => 'Offset', 'method_messages.getChannelDialogs_param_limit_type_int' => 'Number of results to return', 'method_messages.getImportantHistory' => 'Get important message history', 'method_messages.getImportantHistory_param_peer_type_InputPeer' => 'Peer', 'method_messages.getImportantHistory_param_max_id_type_int' => 'Maximum message ID to fetch', 'method_messages.getImportantHistory_param_min_id_type_int' => 'Minumum message ID to fetch', 'method_messages.getImportantHistory_param_limit_type_int' => 'Number of results to fetch', 'method_messages.readChannelHistory' => 'Mark channel/supergroup history as read', 'method_messages.readChannelHistory_param_peer_type_InputPeer' => 'The channel/supergruop', 'method_messages.readChannelHistory_param_max_id_type_int' => 'Maximum message ID to mark as read', 'method_messages.createChannel' => 'Create channel', 'method_messages.createChannel_param_title_type_string' => 'Channel/supergroup title', 'method_messages.deleteChannelMessages' => 'Delete channel messages', 'method_messages.deleteChannelMessages_param_peer_type_InputPeer' => 'The channel/supergroup', 'method_messages.deleteChannelMessages_param_id_type_Vector t' => 'The IDs of messages to delete', 'method_updates.getChannelDifference_param_peer_type_InputPeer' => 'You cannot use this method directly, see https://docs.madelineproto.xyz for more info on handling updates', 'method_messages.search_param_important_only_type_true' => 'Show only important messages', 'method_messages.sendMessage_param_broadcast_type_true' => 'Broadcast this message', 'method_messages.sendMedia_param_broadcast_type_true' => 'Broadcast this message', 'method_messages.forwardMessages_param_broadcast_type_true' => 'Broadcast this message', 'method_messages.deactivateChat' => 'Deactivate chat', 'method_messages.deactivateChat_param_chat_id_type_InputPeer' => 'The chat to deactivate', 'method_messages.deactivateChat_param_enabled_type_Bool' => 'Activate or deactivate?', 'method_help.getTermsOfService_param_lang_code_type_string' => 'Language code', 'method_messages.sendInlineBotResult_param_broadcast_type_true' => 'Broadcast this message?', 'method_channels.getImportantHistory_param_offset_date_type_int' => 'Date offset', 'method_messages.getUnusedStickers' => 'Get unused stickers', 'method_messages.getUnusedStickers_param_limit_type_int' => 'Number of results to return', 'method_destroy_auth_key' => 'Destroy current authorization key', 'method_phone.requestCall_param_g_a_type_bytes' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_phone.acceptCall_param_key_fingerprint_type_long' => 'You cannot use this method directly, see https://docs.madelineproto.xyz#calls for more info on handling calls', 'method_req_DH_params_param_p_type_string' => 'Factorized p from pq', 'method_req_DH_params_param_q_type_string' => 'Factorized q from pq', 'method_req_DH_params_param_encrypted_data_type_string' => 'Encrypted message', 'method_set_client_DH_params_param_encrypted_data_type_string' => 'Encrypted message', 'method_contest.saveDeveloperInfo' => 'Save developer info for telegram contest', 'method_contest.saveDeveloperInfo_param_vk_id_type_int' => 'VK user ID', 'method_contest.saveDeveloperInfo_param_name_type_string' => 'Name', 'method_contest.saveDeveloperInfo_param_phone_number_type_string' => 'Phone number', 'method_contest.saveDeveloperInfo_param_age_type_int' => 'Age', 'method_contest.saveDeveloperInfo_param_city_type_string' => 'City', 'method_auth.importBotAuthorization_param_a_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_b_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_c_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_auth.importBotAuthorization_param_d_type_true' => 'You cannot use this method directly, use the bot_login method instead (see https://docs.madelineproto.xyz for more info)', 'object_vector' => 'Array', 'object_resPQ' => 'Contains pq to factorize', 'object_resPQ_param_nonce_type_int128' => 'Nonce', 'object_resPQ_param_server_nonce_type_int128' => 'Server nonce', 'object_resPQ_param_pq_type_bytes' => 'PQ ', 'object_resPQ_param_server_public_key_fingerprints_type_Vector t' => 'RSA key fingerprints', 'object_p_q_inner_data' => 'PQ inner data', 'object_p_q_inner_data_param_pq_type_bytes' => 'PQ', 'object_p_q_inner_data_param_p_type_bytes' => 'P', 'object_p_q_inner_data_param_q_type_bytes' => 'Q', 'object_p_q_inner_data_param_nonce_type_int128' => 'Nonce', 'object_p_q_inner_data_param_server_nonce_type_int128' => 'Nonce', 'object_p_q_inner_data_param_new_nonce_type_int256' => 'Nonce', 'object_p_q_inner_data_temp' => 'Inner data temp', 'object_p_q_inner_data_temp_param_pq_type_bytes' => 'Pq', 'object_p_q_inner_data_temp_param_p_type_bytes' => 'P', 'object_p_q_inner_data_temp_param_q_type_bytes' => 'Q', 'object_p_q_inner_data_temp_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_p_q_inner_data_temp_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_p_q_inner_data_temp_param_new_nonce_type_int256' => 'New nonce', 'object_p_q_inner_data_temp_param_expires_in_type_int' => 'Expires in', 'object_server_DH_params_fail' => 'Server params fail', 'object_server_DH_params_fail_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_server_DH_params_fail_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_server_DH_params_fail_param_new_nonce_hash_type_int128' => 'New nonce hash', 'object_server_DH_params_ok' => 'Server params ok', 'object_server_DH_params_ok_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_server_DH_params_ok_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_server_DH_params_ok_param_encrypted_answer_type_bytes' => 'Encrypted answer', 'object_server_DH_inner_data' => 'Server inner data', 'object_server_DH_inner_data_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_server_DH_inner_data_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_server_DH_inner_data_param_g_type_int' => 'G', 'object_server_DH_inner_data_param_dh_prime_type_bytes' => 'Dh prime', 'object_server_DH_inner_data_param_g_a_type_bytes' => 'G a', 'object_server_DH_inner_data_param_server_time_type_int' => 'Server time', 'object_client_DH_inner_data' => 'Client inner data', 'object_client_DH_inner_data_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_client_DH_inner_data_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_client_DH_inner_data_param_retry_id_type_long' => 'Retry ID', 'object_client_DH_inner_data_param_g_b_type_bytes' => 'G b', 'object_dh_gen_ok' => 'Dh gen ok', 'object_dh_gen_ok_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_dh_gen_ok_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_dh_gen_ok_param_new_nonce_hash1_type_int128' => 'New nonce hash1', 'object_dh_gen_retry' => 'Dh gen retry', 'object_dh_gen_retry_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_dh_gen_retry_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_dh_gen_retry_param_new_nonce_hash2_type_int128' => 'New nonce hash2', 'object_dh_gen_fail' => 'Dh gen fail', 'object_dh_gen_fail_param_nonce_type_int128' => 'Random number for cryptographic security', 'object_dh_gen_fail_param_server_nonce_type_int128' => 'Random number for cryptographic security, given by server', 'object_dh_gen_fail_param_new_nonce_hash3_type_int128' => 'New nonce hash3', 'object_rpc_result' => 'Rpc result', 'object_rpc_result_param_req_msg_id_type_long' => 'Req msg ID', 'object_rpc_result_param_result_type_Object' => 'Result', 'object_rpc_error' => 'Rpc error', 'object_rpc_error_param_error_code_type_int' => 'Error code', 'object_rpc_error_param_error_message_type_string' => 'Error message', 'object_rpc_answer_unknown' => 'Rpc answer unknown', 'object_rpc_answer_dropped_running' => 'Rpc answer dropped running', 'object_rpc_answer_dropped' => 'Rpc answer dropped', 'object_rpc_answer_dropped_param_msg_id_type_long' => 'Msg ID', 'object_rpc_answer_dropped_param_seq_no_type_int' => 'Seq no', 'object_rpc_answer_dropped_param_bytes_type_int' => 'Bytes', 'object_future_salt' => 'Future salt', 'object_future_salt_param_valid_since_type_int' => 'Valid since', 'object_future_salt_param_valid_until_type_int' => 'Valid until', 'object_future_salt_param_salt_type_long' => 'Salt', 'object_future_salts' => 'Future salts', 'object_future_salts_param_req_msg_id_type_long' => 'Req msg ID', 'object_future_salts_param_now_type_int' => 'Now', 'object_future_salts_param_salts_type_vector' => 'Salts', 'object_pong' => 'Pong', 'object_pong_param_msg_id_type_long' => 'Msg ID', 'object_pong_param_ping_id_type_long' => 'Ping ID', 'object_destroy_session_ok' => 'Destroy session ok', 'object_destroy_session_ok_param_session_id_type_long' => 'Session ID', 'object_destroy_session_none' => 'Destroy session none', 'object_destroy_session_none_param_session_id_type_long' => 'Session ID', 'object_new_session_created' => 'New session created', 'object_new_session_created_param_first_msg_id_type_long' => 'First msg ID', 'object_new_session_created_param_unique_id_type_long' => 'Unique ID', 'object_new_session_created_param_server_salt_type_long' => 'Server salt', 'object_msg_container' => 'Msg container', 'object_msg_container_param_messages_type_vector' => 'Messages', 'object_MTmessage' => 'MTProto message', 'object_MTmessage_param_msg_id_type_long' => 'Message ID', 'object_MTmessage_param_seqno_type_int' => 'Seqno', 'object_MTmessage_param_bytes_type_int' => 'Message body', 'object_MTmessage_param_body_type_Object' => 'Message body', 'object_msg_copy' => 'Msg copy', 'object_msg_copy_param_orig_message_type_MTMessage' => 'Orig message', 'object_gzip_packed' => 'Gzip packed', 'object_gzip_packed_param_packed_data_type_bytes' => 'Packed data', 'object_msgs_ack' => 'Msgs ack', 'object_msgs_ack_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_bad_msg_notification' => 'Bad msg notification', 'object_bad_msg_notification_param_bad_msg_id_type_long' => 'Bad msg ID', 'object_bad_msg_notification_param_bad_msg_seqno_type_int' => 'Bad msg seqno', 'object_bad_msg_notification_param_error_code_type_int' => 'Error code', 'object_bad_server_salt' => 'Bad server salt', 'object_bad_server_salt_param_bad_msg_id_type_long' => 'Bad msg ID', 'object_bad_server_salt_param_bad_msg_seqno_type_int' => 'Bad msg seqno', 'object_bad_server_salt_param_error_code_type_int' => 'Error code', 'object_bad_server_salt_param_new_server_salt_type_long' => 'New server salt', 'object_msg_resend_req' => 'Msg resend req', 'object_msg_resend_req_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_msgs_state_req' => 'Msgs state req', 'object_msgs_state_req_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_msgs_state_info' => 'Msgs state info', 'object_msgs_state_info_param_req_msg_id_type_long' => 'Req msg ID', 'object_msgs_state_info_param_info_type_bytes' => 'Info', 'object_msgs_all_info' => 'Msgs all info', 'object_msgs_all_info_param_msg_ids_type_Vector t' => 'Msg IDs', 'object_msgs_all_info_param_info_type_bytes' => 'Info', 'object_msg_detailed_info' => 'Msg detailed info', 'object_msg_detailed_info_param_msg_id_type_long' => 'Msg ID', 'object_msg_detailed_info_param_answer_msg_id_type_long' => 'Answer msg ID', 'object_msg_detailed_info_param_bytes_type_int' => 'Bytes', 'object_msg_detailed_info_param_status_type_int' => 'Status', 'object_msg_new_detailed_info' => 'Msg new detailed info', 'object_msg_new_detailed_info_param_answer_msg_id_type_long' => 'Answer msg ID', 'object_msg_new_detailed_info_param_bytes_type_int' => 'Bytes', 'object_msg_new_detailed_info_param_status_type_int' => 'Status', 'object_bind_auth_key_inner' => 'Bind auth key inner', 'object_bind_auth_key_inner_param_nonce_type_long' => 'Nonce', 'object_bind_auth_key_inner_param_temp_auth_key_id_type_long' => 'Temp auth key ID', 'object_bind_auth_key_inner_param_perm_auth_key_id_type_long' => 'Perm auth key ID', 'object_bind_auth_key_inner_param_temp_session_id_type_long' => 'Temp session ID', 'object_bind_auth_key_inner_param_expires_at_type_int' => 'Expires at', 'object_boolFalse' => 'Bool false', 'object_boolTrue' => 'Bool true', 'object_true' => 'True', 'object_error' => 'Error', 'object_error_param_code_type_int' => 'Code', 'object_error_param_text_type_string' => 'Text', 'object_null' => 'Null', 'object_inputPeerEmpty' => 'Empty input peer', 'object_inputPeerSelf' => 'Peer self', 'object_inputPeerChat' => 'Peer chat', 'object_inputPeerChat_param_chat_id_type_int' => 'Chat ID', 'object_inputPeerUser' => 'Peer user', 'object_inputPeerUser_param_user_id_type_int' => 'User ID', 'object_inputPeerUser_param_access_hash_type_long' => 'Access hash', 'object_inputPeerChannel' => 'Peer channel', 'object_inputPeerChannel_param_channel_id_type_int' => 'Channel ID', 'object_inputPeerChannel_param_access_hash_type_long' => 'Access hash', 'object_inputUserEmpty' => 'Empty input user', 'object_inputUserSelf' => 'User self', 'object_inputUser' => 'User', 'object_inputUser_param_user_id_type_int' => 'User ID', 'object_inputUser_param_access_hash_type_long' => 'Access hash', 'object_inputPhoneContact' => 'Phone contact', 'object_inputPhoneContact_param_client_id_type_long' => 'Client ID', 'object_inputPhoneContact_param_phone_type_string' => 'Phone', 'object_inputPhoneContact_param_first_name_type_string' => 'First name', 'object_inputPhoneContact_param_last_name_type_string' => 'Last name', 'object_inputFile' => 'File', 'object_inputFile_param_id_type_long' => 'ID', 'object_inputFile_param_parts_type_int' => 'Parts', 'object_inputFile_param_name_type_string' => 'Name', 'object_inputFile_param_md5_checksum_type_string' => 'Md5 checksum', 'object_inputFileBig' => 'File big', 'object_inputFileBig_param_id_type_long' => 'ID', 'object_inputFileBig_param_parts_type_int' => 'Parts', 'object_inputFileBig_param_name_type_string' => 'Name', 'object_inputMediaEmpty' => 'Empty input media', 'object_inputMediaUploadedPhoto' => 'Media uploaded photo', 'object_inputMediaUploadedPhoto_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedPhoto_param_stickers_type_Vector t' => 'Stickers', 'object_inputMediaUploadedPhoto_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaPhoto' => 'Media photo', 'object_inputMediaPhoto_param_id_type_InputPhoto' => 'ID', 'object_inputMediaPhoto_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaGeoPoint' => 'Media geo point', 'object_inputMediaGeoPoint_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputMediaContact' => 'Media contact', 'object_inputMediaContact_param_phone_number_type_string' => 'Phone number', 'object_inputMediaContact_param_first_name_type_string' => 'First name', 'object_inputMediaContact_param_last_name_type_string' => 'Last name', 'object_inputMediaUploadedDocument' => 'Media uploaded document', 'object_inputMediaUploadedDocument_param_nosound_video_type_true' => 'Nosound video?', 'object_inputMediaUploadedDocument_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedDocument_param_thumb_type_InputFile' => 'Thumbnail', 'object_inputMediaUploadedDocument_param_mime_type_type_string' => 'Mime type', 'object_inputMediaUploadedDocument_param_attributes_type_Vector t' => 'Attributes', 'object_inputMediaUploadedDocument_param_stickers_type_Vector t' => 'Stickers', 'object_inputMediaUploadedDocument_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaDocument' => 'Media document', 'object_inputMediaDocument_param_id_type_InputDocument' => 'ID', 'object_inputMediaDocument_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaVenue' => 'Media venue', 'object_inputMediaVenue_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputMediaVenue_param_title_type_string' => 'Title', 'object_inputMediaVenue_param_address_type_string' => 'Address', 'object_inputMediaVenue_param_provider_type_string' => 'Provider', 'object_inputMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_inputMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_inputMediaGifExternal' => 'Media gif external', 'object_inputMediaGifExternal_param_url_type_string' => 'URL', 'object_inputMediaGifExternal_param_q_type_string' => 'Q', 'object_inputMediaPhotoExternal' => 'Media photo external', 'object_inputMediaPhotoExternal_param_url_type_string' => 'URL', 'object_inputMediaPhotoExternal_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaDocumentExternal' => 'Media document external', 'object_inputMediaDocumentExternal_param_url_type_string' => 'URL', 'object_inputMediaDocumentExternal_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_inputMediaGame' => 'Media game', 'object_inputMediaGame_param_id_type_InputGame' => 'ID', 'object_inputMediaInvoice' => 'Media invoice', 'object_inputMediaInvoice_param_title_type_string' => 'Title', 'object_inputMediaInvoice_param_description_type_string' => 'Description', 'object_inputMediaInvoice_param_photo_type_InputWebDocument' => 'Photo', 'object_inputMediaInvoice_param_invoice_type_Invoice' => 'Invoice', 'object_inputMediaInvoice_param_payload_type_bytes' => 'Payload', 'object_inputMediaInvoice_param_provider_type_string' => 'Provider', 'object_inputMediaInvoice_param_provider_data_type_DataJSON' => 'Provider data', 'object_inputMediaInvoice_param_start_param_type_string' => 'Start param', 'object_inputMediaGeoLive' => 'Media geo live', 'object_inputMediaGeoLive_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputMediaGeoLive_param_period_type_int' => 'Period', 'object_inputChatPhotoEmpty' => 'Empty input chat photo', 'object_inputChatUploadedPhoto' => 'Chat uploaded photo', 'object_inputChatUploadedPhoto_param_file_type_InputFile' => 'File', 'object_inputChatPhoto' => 'Chat photo', 'object_inputChatPhoto_param_id_type_InputPhoto' => 'ID', 'object_inputGeoPointEmpty' => 'Empty input geo point', 'object_inputGeoPoint' => 'Geo point', 'object_inputGeoPoint_param_lat_type_double' => 'Lat', 'object_inputGeoPoint_param_long_type_double' => 'Long', 'object_inputPhotoEmpty' => 'Empty input photo', 'object_inputPhoto' => 'Photo', 'object_inputPhoto_param_id_type_long' => 'ID', 'object_inputPhoto_param_access_hash_type_long' => 'Access hash', 'object_inputFileLocation' => 'File location', 'object_inputFileLocation_param_volume_id_type_long' => 'Volume ID', 'object_inputFileLocation_param_local_id_type_int' => 'Local ID', 'object_inputFileLocation_param_secret_type_long' => 'Secret', 'object_inputEncryptedFileLocation' => 'Encrypted file location', 'object_inputEncryptedFileLocation_param_id_type_long' => 'ID', 'object_inputEncryptedFileLocation_param_access_hash_type_long' => 'Access hash', 'object_inputDocumentFileLocation' => 'Document file location', 'object_inputDocumentFileLocation_param_id_type_long' => 'ID', 'object_inputDocumentFileLocation_param_access_hash_type_long' => 'Access hash', 'object_inputDocumentFileLocation_param_version_type_int' => 'Version', 'object_inputAppEvent' => 'App event', 'object_inputAppEvent_param_time_type_double' => 'Time', 'object_inputAppEvent_param_type_type_string' => 'Type', 'object_inputAppEvent_param_peer_type_long' => 'Peer', 'object_inputAppEvent_param_data_type_string' => 'Data', 'object_peerUser' => 'Peer user', 'object_peerUser_param_user_id_type_int' => 'User ID', 'object_peerChat' => 'Peer chat', 'object_peerChat_param_chat_id_type_int' => 'Chat ID', 'object_peerChannel' => 'Peer channel', 'object_peerChannel_param_channel_id_type_int' => 'Channel ID', 'object_storage.fileUnknown' => 'File unknown', 'object_storage.filePartial' => 'File partial', 'object_storage.fileJpeg' => 'File jpeg', 'object_storage.fileGif' => 'File gif', 'object_storage.filePng' => 'File png', 'object_storage.filePdf' => 'File pdf', 'object_storage.fileMp3' => 'File mp3', 'object_storage.fileMov' => 'File mov', 'object_storage.fileMp4' => 'File mp4', 'object_storage.fileWebp' => 'File webp', 'object_fileLocationUnavailable' => 'File location unavailable', 'object_fileLocationUnavailable_param_volume_id_type_long' => 'Volume ID', 'object_fileLocationUnavailable_param_local_id_type_int' => 'Local ID', 'object_fileLocationUnavailable_param_secret_type_long' => 'Secret', 'object_fileLocation' => 'File location', 'object_fileLocation_param_dc_id_type_int' => 'DC ID', 'object_fileLocation_param_volume_id_type_long' => 'Volume ID', 'object_fileLocation_param_local_id_type_int' => 'Local ID', 'object_fileLocation_param_secret_type_long' => 'Secret', 'object_userEmpty' => 'Empty user', 'object_userEmpty_param_id_type_int' => 'ID', 'object_user' => 'User', 'object_user_param_self_type_true' => 'Self?', 'object_user_param_contact_type_true' => 'Contact?', 'object_user_param_mutual_contact_type_true' => 'Mutual contact?', 'object_user_param_deleted_type_true' => 'Deleted?', 'object_user_param_bot_type_true' => 'Bot?', 'object_user_param_bot_chat_history_type_true' => 'Bot chat history?', 'object_user_param_bot_nochats_type_true' => 'Bot nochats?', 'object_user_param_verified_type_true' => 'Verified?', 'object_user_param_restricted_type_true' => 'Restricted?', 'object_user_param_min_type_true' => 'Min?', 'object_user_param_bot_inline_geo_type_true' => 'Bot inline geo?', 'object_user_param_id_type_int' => 'ID', 'object_user_param_access_hash_type_long' => 'Access hash', 'object_user_param_first_name_type_string' => 'First name', 'object_user_param_last_name_type_string' => 'Last name', 'object_user_param_username_type_string' => 'Username', 'object_user_param_phone_type_string' => 'Phone', 'object_user_param_photo_type_UserProfilePhoto' => 'Photo', 'object_user_param_status_type_UserStatus' => 'Status', 'object_user_param_bot_info_version_type_int' => 'Bot info version', 'object_user_param_restriction_reason_type_string' => 'Restriction reason', 'object_user_param_bot_inline_placeholder_type_string' => 'Bot inline placeholder', 'object_user_param_lang_code_type_string' => 'Lang code', 'object_userProfilePhotoEmpty' => 'Empty user profile photo', 'object_userProfilePhoto' => 'User profile photo', 'object_userProfilePhoto_param_photo_id_type_long' => 'Photo ID', 'object_userProfilePhoto_param_photo_small_type_FileLocation' => 'Photo small', 'object_userProfilePhoto_param_photo_big_type_FileLocation' => 'Photo big', 'object_chatEmpty' => 'Empty chat', 'object_chatEmpty_param_id_type_int' => 'ID', 'object_chat' => 'Chat', 'object_chat_param_creator_type_true' => 'Creator?', 'object_chat_param_kicked_type_true' => 'Kicked?', 'object_chat_param_left_type_true' => 'Left?', 'object_chat_param_admins_enabled_type_true' => 'Admins enabled?', 'object_chat_param_admin_type_true' => 'Admin?', 'object_chat_param_deactivated_type_true' => 'Deactivated?', 'object_chat_param_id_type_int' => 'ID', 'object_chat_param_title_type_string' => 'Title', 'object_chat_param_photo_type_ChatPhoto' => 'Photo', 'object_chat_param_participants_count_type_int' => 'Participants count', 'object_chat_param_date_type_int' => 'Date', 'object_chat_param_version_type_int' => 'Version', 'object_chat_param_migrated_to_type_InputChannel' => 'Migrated to', 'object_chatForbidden' => 'Chat forbidden', 'object_chatForbidden_param_id_type_int' => 'ID', 'object_chatForbidden_param_title_type_string' => 'Title', 'object_channel' => 'Channel', 'object_channel_param_creator_type_true' => 'Creator?', 'object_channel_param_left_type_true' => 'Left?', 'object_channel_param_editor_type_true' => 'Editor?', 'object_channel_param_broadcast_type_true' => 'Broadcast?', 'object_channel_param_verified_type_true' => 'Verified?', 'object_channel_param_megagroup_type_true' => 'Megagroup?', 'object_channel_param_restricted_type_true' => 'Restricted?', 'object_channel_param_democracy_type_true' => 'Democracy?', 'object_channel_param_signatures_type_true' => 'Signatures?', 'object_channel_param_min_type_true' => 'Min?', 'object_channel_param_id_type_int' => 'ID', 'object_channel_param_access_hash_type_long' => 'Access hash', 'object_channel_param_title_type_string' => 'Title', 'object_channel_param_username_type_string' => 'Username', 'object_channel_param_photo_type_ChatPhoto' => 'Photo', 'object_channel_param_date_type_int' => 'Date', 'object_channel_param_version_type_int' => 'Version', 'object_channel_param_restriction_reason_type_string' => 'Restriction reason', 'object_channel_param_admin_rights_type_ChannelAdminRights' => 'Admin rights', 'object_channel_param_banned_rights_type_ChannelBannedRights' => 'Banned rights', 'object_channel_param_participants_count_type_int' => 'Participants count', 'object_channelForbidden' => 'Forbidden channel', 'object_channelForbidden_param_broadcast_type_true' => 'Broadcast?', 'object_channelForbidden_param_megagroup_type_true' => 'Megagroup?', 'object_channelForbidden_param_id_type_int' => 'ID', 'object_channelForbidden_param_access_hash_type_long' => 'Access hash', 'object_channelForbidden_param_title_type_string' => 'Title', 'object_channelForbidden_param_until_date_type_int' => 'Until date', 'object_chatFull' => 'Chat full', 'object_chatFull_param_id_type_int' => 'ID', 'object_chatFull_param_participants_type_ChatParticipants' => 'Participants', 'object_chatFull_param_chat_photo_type_Photo' => 'Chat photo', 'object_chatFull_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_chatFull_param_exported_invite_type_ExportedChatInvite' => 'Exported invite', 'object_chatFull_param_bot_info_type_Vector t' => 'Bot info', 'object_channelFull' => 'Full channel', 'object_channelFull_param_can_view_participants_type_true' => 'Can view participants?', 'object_channelFull_param_can_set_username_type_true' => 'Can set username?', 'object_channelFull_param_can_set_stickers_type_true' => 'Can set group stickerset?', 'object_channelFull_param_hidden_prehistory_type_true' => 'Hidden prehistory?', 'object_channelFull_param_id_type_int' => 'ID', 'object_channelFull_param_about_type_string' => 'About', 'object_channelFull_param_participants_count_type_int' => 'Participants count', 'object_channelFull_param_admins_count_type_int' => 'Admins count', 'object_channelFull_param_kicked_count_type_int' => 'Kicked count', 'object_channelFull_param_banned_count_type_int' => 'Banned count', 'object_channelFull_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_channelFull_param_read_outbox_max_id_type_int' => 'Read outbox max ID', 'object_channelFull_param_unread_count_type_int' => 'Unread count', 'object_channelFull_param_chat_photo_type_Photo' => 'Chat photo', 'object_channelFull_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_channelFull_param_exported_invite_type_ExportedChatInvite' => 'Exported invite', 'object_channelFull_param_bot_info_type_Vector t' => 'Bot info', 'object_channelFull_param_migrated_from_chat_id_type_int' => 'Migrated from chat ID', 'object_channelFull_param_migrated_from_max_id_type_int' => 'Migrated from max ID', 'object_channelFull_param_pinned_msg_id_type_int' => 'Pinned msg ID', 'object_channelFull_param_stickerset_type_StickerSet' => 'Stickerset', 'object_channelFull_param_available_min_id_type_int' => 'Available min ID', 'object_chatParticipant' => 'Chat participant', 'object_chatParticipant_param_user_id_type_int' => 'User ID', 'object_chatParticipant_param_inviter_id_type_int' => 'Inviter ID', 'object_chatParticipant_param_date_type_int' => 'Date', 'object_chatParticipantCreator' => 'Chat participant creator', 'object_chatParticipantCreator_param_user_id_type_int' => 'User ID', 'object_chatParticipantAdmin' => 'Chat participant admin', 'object_chatParticipantAdmin_param_user_id_type_int' => 'User ID', 'object_chatParticipantAdmin_param_inviter_id_type_int' => 'Inviter ID', 'object_chatParticipantAdmin_param_date_type_int' => 'Date', 'object_chatParticipantsForbidden' => 'Chat participants forbidden', 'object_chatParticipantsForbidden_param_chat_id_type_int' => 'Chat ID', 'object_chatParticipantsForbidden_param_self_participant_type_ChatParticipant' => 'Self participant', 'object_chatParticipants' => 'Chat participants', 'object_chatParticipants_param_chat_id_type_int' => 'Chat ID', 'object_chatParticipants_param_participants_type_Vector t' => 'Participants', 'object_chatParticipants_param_version_type_int' => 'Version', 'object_chatPhotoEmpty' => 'Empty chat photo', 'object_chatPhoto' => 'Chat photo', 'object_chatPhoto_param_photo_small_type_FileLocation' => 'Photo small', 'object_chatPhoto_param_photo_big_type_FileLocation' => 'Photo big', 'object_messageEmpty' => 'Empty message', 'object_messageEmpty_param_id_type_int' => 'ID', 'object_message' => 'Message', 'object_message_param_out_type_true' => 'Out?', 'object_message_param_mentioned_type_true' => 'Mentioned?', 'object_message_param_media_unread_type_true' => 'Media unread?', 'object_message_param_silent_type_true' => 'Silent?', 'object_message_param_post_type_true' => 'Post?', 'object_message_param_id_type_int' => 'ID', 'object_message_param_from_id_type_int' => 'From ID', 'object_message_param_to_id_type_Peer' => 'To ID', 'object_message_param_fwd_from_type_MessageFwdHeader' => 'Forwarded from', 'object_message_param_via_bot_id_type_int' => 'Via bot ID', 'object_message_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_message_param_date_type_int' => 'Date', 'object_message_param_message_type_string' => 'Message', 'object_message_param_media_type_MessageMedia' => 'Media', 'object_message_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_message_param_entities_type_Vector t' => 'Entities', 'object_message_param_views_type_int' => 'Views', 'object_message_param_edit_date_type_int' => 'Edit date', 'object_message_param_post_author_type_string' => 'Post author', 'object_message_param_grouped_id_type_long' => 'Grouped ID', 'object_messageService' => 'Message service', 'object_messageService_param_out_type_true' => 'Out?', 'object_messageService_param_mentioned_type_true' => 'Mentioned?', 'object_messageService_param_media_unread_type_true' => 'Media unread?', 'object_messageService_param_silent_type_true' => 'Silent?', 'object_messageService_param_post_type_true' => 'Post?', 'object_messageService_param_id_type_int' => 'ID', 'object_messageService_param_from_id_type_int' => 'From ID', 'object_messageService_param_to_id_type_Peer' => 'To ID', 'object_messageService_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_messageService_param_date_type_int' => 'Date', 'object_messageService_param_action_type_MessageAction' => 'Action', 'object_messageMediaEmpty' => 'Empty message media', 'object_messageMediaPhoto' => 'Message media photo', 'object_messageMediaPhoto_param_photo_type_Photo' => 'Photo', 'object_messageMediaPhoto_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_messageMediaGeo' => 'Message media geo', 'object_messageMediaGeo_param_geo_type_GeoPoint' => 'Geo', 'object_messageMediaContact' => 'Message media contact', 'object_messageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_messageMediaContact_param_first_name_type_string' => 'First name', 'object_messageMediaContact_param_last_name_type_string' => 'Last name', 'object_messageMediaContact_param_user_id_type_int' => 'User ID', 'object_messageMediaUnsupported' => 'Message media unsupported', 'object_messageMediaDocument' => 'Message media document', 'object_messageMediaDocument_param_document_type_Document' => 'Document', 'object_messageMediaDocument_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_messageMediaWebPage' => 'Message media web page', 'object_messageMediaWebPage_param_webpage_type_WebPage' => 'Webpage', 'object_messageMediaVenue' => 'Message media venue', 'object_messageMediaVenue_param_geo_type_GeoPoint' => 'Geo', 'object_messageMediaVenue_param_title_type_string' => 'Title', 'object_messageMediaVenue_param_address_type_string' => 'Address', 'object_messageMediaVenue_param_provider_type_string' => 'Provider', 'object_messageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_messageMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_messageMediaGame' => 'Message media game', 'object_messageMediaGame_param_game_type_Game' => 'Game', 'object_messageMediaInvoice' => 'Message media invoice', 'object_messageMediaInvoice_param_shipping_address_requested_type_true' => 'Shipping address requested?', 'object_messageMediaInvoice_param_test_type_true' => 'Test?', 'object_messageMediaInvoice_param_title_type_string' => 'Title', 'object_messageMediaInvoice_param_description_type_string' => 'Description', 'object_messageMediaInvoice_param_photo_type_WebDocument' => 'Photo', 'object_messageMediaInvoice_param_receipt_msg_id_type_int' => 'Receipt msg ID', 'object_messageMediaInvoice_param_currency_type_string' => 'Currency', 'object_messageMediaInvoice_param_total_amount_type_long' => 'Total amount', 'object_messageMediaInvoice_param_start_param_type_string' => 'Start param', 'object_messageMediaGeoLive' => 'Message media geo live', 'object_messageMediaGeoLive_param_geo_type_GeoPoint' => 'Geo', 'object_messageMediaGeoLive_param_period_type_int' => 'Period', 'object_messageActionEmpty' => 'Empty message action', 'object_messageActionChatCreate' => 'Message action chat create', 'object_messageActionChatCreate_param_title_type_string' => 'Title', 'object_messageActionChatCreate_param_users_type_Vector t' => 'Users', 'object_messageActionChatEditTitle' => 'Message action chat edit title', 'object_messageActionChatEditTitle_param_title_type_string' => 'Title', 'object_messageActionChatEditPhoto' => 'Message action chat edit photo', 'object_messageActionChatEditPhoto_param_photo_type_Photo' => 'Photo', 'object_messageActionChatDeletePhoto' => 'Message action chat delete photo', 'object_messageActionChatAddUser' => 'Message action chat add user', 'object_messageActionChatAddUser_param_users_type_Vector t' => 'Users', 'object_messageActionChatDeleteUser' => 'Message action chat delete user', 'object_messageActionChatDeleteUser_param_user_id_type_int' => 'User ID', 'object_messageActionChatJoinedByLink' => 'Message action chat joined by link', 'object_messageActionChatJoinedByLink_param_inviter_id_type_int' => 'Inviter ID', 'object_messageActionChannelCreate' => 'Message action channel create', 'object_messageActionChannelCreate_param_title_type_string' => 'Title', 'object_messageActionChatMigrateTo' => 'Message action chat migrate to', 'object_messageActionChatMigrateTo_param_channel_id_type_int' => 'Channel ID', 'object_messageActionChannelMigrateFrom' => 'Message action channel migrate from', 'object_messageActionChannelMigrateFrom_param_title_type_string' => 'Title', 'object_messageActionChannelMigrateFrom_param_chat_id_type_int' => 'Chat ID', 'object_messageActionPinMessage' => 'Message action pin message', 'object_messageActionHistoryClear' => 'Message action history clear', 'object_messageActionGameScore' => 'Message action game score', 'object_messageActionGameScore_param_game_id_type_long' => 'Game ID', 'object_messageActionGameScore_param_score_type_int' => 'Score', 'object_messageActionPaymentSentMe' => 'Message action payment sent me', 'object_messageActionPaymentSentMe_param_currency_type_string' => 'Currency', 'object_messageActionPaymentSentMe_param_total_amount_type_long' => 'Total amount', 'object_messageActionPaymentSentMe_param_payload_type_bytes' => 'Payload', 'object_messageActionPaymentSentMe_param_info_type_PaymentRequestedInfo' => 'Info', 'object_messageActionPaymentSentMe_param_shipping_option_id_type_string' => 'Shipping option ID', 'object_messageActionPaymentSentMe_param_charge_type_PaymentCharge' => 'Charge', 'object_messageActionPaymentSent' => 'Message action payment sent', 'object_messageActionPaymentSent_param_currency_type_string' => 'Currency', 'object_messageActionPaymentSent_param_total_amount_type_long' => 'Total amount', 'object_messageActionPhoneCall' => 'Message action phone call', 'object_messageActionPhoneCall_param_call_id_type_long' => 'Call ID', 'object_messageActionPhoneCall_param_reason_type_PhoneCallDiscardReason' => 'Reason', 'object_messageActionPhoneCall_param_duration_type_int' => 'Duration', 'object_messageActionScreenshotTaken' => 'Message action screenshot taken', 'object_messageActionCustomAction' => 'Message action custom action', 'object_messageActionCustomAction_param_message_type_string' => 'Message', 'object_dialog' => 'Dialog', 'object_dialog_param_pinned_type_true' => 'Pinned?', 'object_dialog_param_peer_type_Peer' => 'Peer', 'object_dialog_param_top_message_type_int' => 'Top message', 'object_dialog_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_dialog_param_read_outbox_max_id_type_int' => 'Read outbox max ID', 'object_dialog_param_unread_count_type_int' => 'Unread count', 'object_dialog_param_unread_mentions_count_type_int' => 'Unread mentions count', 'object_dialog_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_dialog_param_pts_type_int' => 'Pts', 'object_dialog_param_draft_type_DraftMessage' => 'Draft', 'object_photoEmpty' => 'Empty photo', 'object_photoEmpty_param_id_type_long' => 'ID', 'object_photo' => 'Photo', 'object_photo_param_has_stickers_type_true' => 'Has stickers?', 'object_photo_param_id_type_long' => 'ID', 'object_photo_param_access_hash_type_long' => 'Access hash', 'object_photo_param_date_type_int' => 'Date', 'object_photo_param_sizes_type_Vector t' => 'Sizes', 'object_photoSizeEmpty' => 'Empty photo size', 'object_photoSizeEmpty_param_type_type_string' => 'Type', 'object_photoSize' => 'Photo size', 'object_photoSize_param_type_type_string' => 'Type', 'object_photoSize_param_location_type_FileLocation' => 'Location', 'object_photoSize_param_w_type_int' => 'Width', 'object_photoSize_param_h_type_int' => 'Height', 'object_photoSize_param_size_type_int' => 'Size', 'object_photoCachedSize' => 'Photo cached size', 'object_photoCachedSize_param_type_type_string' => 'Type', 'object_photoCachedSize_param_location_type_FileLocation' => 'Location', 'object_photoCachedSize_param_w_type_int' => 'Width', 'object_photoCachedSize_param_h_type_int' => 'Height', 'object_photoCachedSize_param_bytes_type_bytes' => 'Bytes', 'object_geoPointEmpty' => 'Empty geo point', 'object_geoPoint' => 'Geo point', 'object_geoPoint_param_long_type_double' => 'Long', 'object_geoPoint_param_lat_type_double' => 'Lat', 'object_auth.checkedPhone' => 'Checked phone', 'object_auth.checkedPhone_param_phone_registered_type_Bool' => 'Phone registered?', 'object_auth.sentCode' => 'Sent code', 'object_auth.sentCode_param_phone_registered_type_true' => 'Phone registered?', 'object_auth.sentCode_param_type_type_auth.SentCodeType' => 'Type', 'object_auth.sentCode_param_phone_code_hash_type_string' => 'Phone code hash', 'object_auth.sentCode_param_next_type_type_auth.CodeType' => 'Next type', 'object_auth.sentCode_param_timeout_type_int' => 'Timeout', 'object_auth.authorization' => 'Authorization', 'object_auth.authorization_param_tmp_sessions_type_int' => 'Temporary sessions', 'object_auth.authorization_param_user_type_User' => 'User', 'object_auth.exportedAuthorization' => 'Exported authorization', 'object_auth.exportedAuthorization_param_id_type_int' => 'ID', 'object_auth.exportedAuthorization_param_bytes_type_bytes' => 'Bytes', 'object_inputNotifyPeer' => 'Notify peer', 'object_inputNotifyPeer_param_peer_type_InputPeer' => 'Peer', 'object_inputNotifyUsers' => 'Notify users', 'object_inputNotifyChats' => 'Notify chats', 'object_inputNotifyAll' => 'Notify all', 'object_inputPeerNotifyEventsEmpty' => 'Empty input peer notify events', 'object_inputPeerNotifyEventsAll' => 'Peer notify events all', 'object_inputPeerNotifySettings' => 'Peer notify settings', 'object_inputPeerNotifySettings_param_show_previews_type_true' => 'Show previews?', 'object_inputPeerNotifySettings_param_silent_type_true' => 'Silent?', 'object_inputPeerNotifySettings_param_mute_until_type_int' => 'Mute until', 'object_inputPeerNotifySettings_param_sound_type_string' => 'Sound', 'object_peerNotifyEventsEmpty' => 'Empty peer notify events', 'object_peerNotifyEventsAll' => 'Peer notify events all', 'object_peerNotifySettingsEmpty' => 'Empty peer notify settings', 'object_peerNotifySettings' => 'Peer notify settings', 'object_peerNotifySettings_param_show_previews_type_true' => 'Show previews?', 'object_peerNotifySettings_param_silent_type_true' => 'Silent?', 'object_peerNotifySettings_param_mute_until_type_int' => 'Mute until', 'object_peerNotifySettings_param_sound_type_string' => 'Sound', 'object_peerSettings' => 'Peer settings', 'object_peerSettings_param_report_spam_type_true' => 'Report spam?', 'object_wallPaper' => 'Wall paper', 'object_wallPaper_param_id_type_int' => 'ID', 'object_wallPaper_param_title_type_string' => 'Title', 'object_wallPaper_param_sizes_type_Vector t' => 'Sizes', 'object_wallPaper_param_color_type_int' => 'Color', 'object_wallPaperSolid' => 'Wall paper solid', 'object_wallPaperSolid_param_id_type_int' => 'ID', 'object_wallPaperSolid_param_title_type_string' => 'Title', 'object_wallPaperSolid_param_bg_color_type_int' => 'Bg color', 'object_wallPaperSolid_param_color_type_int' => 'Color', 'object_inputReportReasonSpam' => 'Report reason spam', 'object_inputReportReasonViolence' => 'Report reason violence', 'object_inputReportReasonPornography' => 'Report reason pornography', 'object_inputReportReasonOther' => 'Report reason other', 'object_inputReportReasonOther_param_text_type_string' => 'Text', 'object_userFull' => 'User full', 'object_userFull_param_blocked_type_true' => 'Blocked?', 'object_userFull_param_phone_calls_available_type_true' => 'Phone calls available?', 'object_userFull_param_phone_calls_private_type_true' => 'Phone calls private?', 'object_userFull_param_user_type_User' => 'User', 'object_userFull_param_about_type_string' => 'About', 'object_userFull_param_link_type_contacts.Link' => 'Link', 'object_userFull_param_profile_photo_type_Photo' => 'Profile photo', 'object_userFull_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_userFull_param_bot_info_type_BotInfo' => 'Bot info', 'object_userFull_param_common_chats_count_type_int' => 'Common chats count', 'object_contact' => 'Contact', 'object_contact_param_user_id_type_int' => 'User ID', 'object_contact_param_mutual_type_Bool' => 'Mutual?', 'object_importedContact' => 'Imported contact', 'object_importedContact_param_user_id_type_int' => 'User ID', 'object_importedContact_param_client_id_type_long' => 'Client ID', 'object_contactBlocked' => 'Contact blocked', 'object_contactBlocked_param_user_id_type_int' => 'User ID', 'object_contactBlocked_param_date_type_int' => 'Date', 'object_contactStatus' => 'Contact status', 'object_contactStatus_param_user_id_type_int' => 'User ID', 'object_contactStatus_param_status_type_UserStatus' => 'Status', 'object_contacts.link' => 'Link', 'object_contacts.link_param_my_link_type_ContactLink' => 'My link', 'object_contacts.link_param_foreign_link_type_ContactLink' => 'Foreign link', 'object_contacts.link_param_user_type_User' => 'User', 'object_contacts.contactsNotModified' => 'Contacts not modified', 'object_contacts.contacts' => 'Contacts', 'object_contacts.contacts_param_contacts_type_Vector t' => 'Contacts', 'object_contacts.contacts_param_saved_count_type_int' => 'Saved count', 'object_contacts.contacts_param_users_type_Vector t' => 'Users', 'object_contacts.importedContacts' => 'Imported contacts', 'object_contacts.importedContacts_param_imported_type_Vector t' => 'Imported', 'object_contacts.importedContacts_param_popular_invites_type_Vector t' => 'Popular invites', 'object_contacts.importedContacts_param_retry_contacts_type_Vector t' => 'Retry importing contacts whose client IDs appear here', 'object_contacts.importedContacts_param_users_type_Vector t' => 'Users', 'object_contacts.blocked' => 'Blocked', 'object_contacts.blocked_param_blocked_type_Vector t' => 'Blocked', 'object_contacts.blocked_param_users_type_Vector t' => 'Users', 'object_contacts.blockedSlice' => 'Blocked slice', 'object_contacts.blockedSlice_param_count_type_int' => 'Count', 'object_contacts.blockedSlice_param_blocked_type_Vector t' => 'Blocked', 'object_contacts.blockedSlice_param_users_type_Vector t' => 'Users', 'object_messages.dialogs' => 'Dialogs', 'object_messages.dialogs_param_dialogs_type_Vector t' => 'Dialogs', 'object_messages.dialogs_param_messages_type_Vector t' => 'Messages', 'object_messages.dialogs_param_chats_type_Vector t' => 'Chats', 'object_messages.dialogs_param_users_type_Vector t' => 'Users', 'object_messages.dialogsSlice' => 'Dialogs slice', 'object_messages.dialogsSlice_param_count_type_int' => 'Count', 'object_messages.dialogsSlice_param_dialogs_type_Vector t' => 'Dialogs', 'object_messages.dialogsSlice_param_messages_type_Vector t' => 'Messages', 'object_messages.dialogsSlice_param_chats_type_Vector t' => 'Chats', 'object_messages.dialogsSlice_param_users_type_Vector t' => 'Users', 'object_messages.messages' => 'Messages', 'object_messages.messages_param_messages_type_Vector t' => 'Messages', 'object_messages.messages_param_chats_type_Vector t' => 'Chats', 'object_messages.messages_param_users_type_Vector t' => 'Users', 'object_messages.messagesSlice' => 'Messages slice', 'object_messages.messagesSlice_param_count_type_int' => 'Count', 'object_messages.messagesSlice_param_messages_type_Vector t' => 'Messages', 'object_messages.messagesSlice_param_chats_type_Vector t' => 'Chats', 'object_messages.messagesSlice_param_users_type_Vector t' => 'Users', 'object_messages.channelMessages' => 'Channel messages', 'object_messages.channelMessages_param_pts_type_int' => 'Pts', 'object_messages.channelMessages_param_count_type_int' => 'Count', 'object_messages.channelMessages_param_messages_type_Vector t' => 'Messages', 'object_messages.channelMessages_param_chats_type_Vector t' => 'Chats', 'object_messages.channelMessages_param_users_type_Vector t' => 'Users', 'object_messages.messagesNotModified' => 'Messages not modified', 'object_messages.messagesNotModified_param_count_type_int' => 'Count', 'object_messages.chats' => 'Chats', 'object_messages.chats_param_chats_type_Vector t' => 'Chats', 'object_messages.chatsSlice' => 'Chats slice', 'object_messages.chatsSlice_param_count_type_int' => 'Count', 'object_messages.chatsSlice_param_chats_type_Vector t' => 'Chats', 'object_messages.chatFull' => 'Chat full', 'object_messages.chatFull_param_full_chat_type_ChatFull' => 'Full chat', 'object_messages.chatFull_param_chats_type_Vector t' => 'Chats', 'object_messages.chatFull_param_users_type_Vector t' => 'Users', 'object_messages.affectedHistory' => 'Affected history', 'object_messages.affectedHistory_param_pts_type_int' => 'Pts', 'object_messages.affectedHistory_param_pts_count_type_int' => 'Pts count', 'object_messages.affectedHistory_param_offset_type_int' => 'Offset', 'object_inputMessagesFilterEmpty' => 'Empty input messages filter', 'object_inputMessagesFilterPhotos' => 'Messages filter photos', 'object_inputMessagesFilterVideo' => 'Messages filter video', 'object_inputMessagesFilterPhotoVideo' => 'Messages filter photo video', 'object_inputMessagesFilterDocument' => 'Messages filter document', 'object_inputMessagesFilterUrl' => 'Messages filter URL', 'object_inputMessagesFilterGif' => 'Messages filter gif', 'object_inputMessagesFilterVoice' => 'Messages filter voice', 'object_inputMessagesFilterMusic' => 'Messages filter music', 'object_inputMessagesFilterChatPhotos' => 'Messages filter chat photos', 'object_inputMessagesFilterPhoneCalls' => 'Messages filter phone calls', 'object_inputMessagesFilterPhoneCalls_param_missed_type_true' => 'Missed?', 'object_inputMessagesFilterRoundVoice' => 'Messages filter round voice', 'object_inputMessagesFilterRoundVideo' => 'Messages filter round video', 'object_inputMessagesFilterMyMentions' => 'Messages filter my mentions', 'object_inputMessagesFilterGeo' => 'Messages filter geo', 'object_inputMessagesFilterContacts' => 'Messages filter contacts', 'object_updateNewMessage' => 'Update new message', 'object_updateNewMessage_param_message_type_Message' => 'Message', 'object_updateNewMessage_param_pts_type_int' => 'Pts', 'object_updateNewMessage_param_pts_count_type_int' => 'Pts count', 'object_updateMessageID' => 'Update message ID', 'object_updateMessageID_param_id_type_int' => 'ID', 'object_updateDeleteMessages' => 'Update delete messages', 'object_updateDeleteMessages_param_messages_type_Vector t' => 'Messages', 'object_updateDeleteMessages_param_pts_type_int' => 'Pts', 'object_updateDeleteMessages_param_pts_count_type_int' => 'Pts count', 'object_updateUserTyping' => 'Update user typing', 'object_updateUserTyping_param_user_id_type_int' => 'User ID', 'object_updateUserTyping_param_action_type_SendMessageAction' => 'Action', 'object_updateChatUserTyping' => 'Update chat user typing', 'object_updateChatUserTyping_param_chat_id_type_int' => 'Chat ID', 'object_updateChatUserTyping_param_user_id_type_int' => 'User ID', 'object_updateChatUserTyping_param_action_type_SendMessageAction' => 'Action', 'object_updateChatParticipants' => 'Update chat participants', 'object_updateChatParticipants_param_participants_type_ChatParticipants' => 'Participants', 'object_updateUserName' => 'Update user name', 'object_updateUserName_param_user_id_type_int' => 'User ID', 'object_updateUserName_param_first_name_type_string' => 'First name', 'object_updateUserName_param_last_name_type_string' => 'Last name', 'object_updateUserName_param_username_type_string' => 'Username', 'object_updateUserPhoto' => 'Update user photo', 'object_updateUserPhoto_param_user_id_type_int' => 'User ID', 'object_updateUserPhoto_param_date_type_int' => 'Date', 'object_updateUserPhoto_param_photo_type_UserProfilePhoto' => 'Photo', 'object_updateUserPhoto_param_previous_type_Bool' => 'Previous?', 'object_updateContactRegistered' => 'Update contact registered', 'object_updateContactRegistered_param_user_id_type_int' => 'User ID', 'object_updateContactRegistered_param_date_type_int' => 'Date', 'object_updateContactLink' => 'Update contact link', 'object_updateContactLink_param_user_id_type_int' => 'User ID', 'object_updateContactLink_param_my_link_type_ContactLink' => 'My link', 'object_updateContactLink_param_foreign_link_type_ContactLink' => 'Foreign link', 'object_updateNewEncryptedMessage' => 'Update new encrypted message', 'object_updateNewEncryptedMessage_param_message_type_EncryptedMessage' => 'Message', 'object_updateNewEncryptedMessage_param_qts_type_int' => 'Qts', 'object_updateEncryptedChatTyping' => 'Update encrypted chat typing', 'object_updateEncryptedChatTyping_param_chat_id_type_int' => 'Chat ID', 'object_updateEncryption' => 'Update encryption', 'object_updateEncryption_param_chat_type_EncryptedChat' => 'Chat', 'object_updateEncryption_param_date_type_int' => 'Date', 'object_updateEncryptedMessagesRead' => 'Update encrypted messages read', 'object_updateEncryptedMessagesRead_param_chat_id_type_int' => 'Chat ID', 'object_updateEncryptedMessagesRead_param_max_date_type_int' => 'Max date', 'object_updateEncryptedMessagesRead_param_date_type_int' => 'Date', 'object_updateChatParticipantAdd' => 'Update chat participant add', 'object_updateChatParticipantAdd_param_chat_id_type_int' => 'Chat ID', 'object_updateChatParticipantAdd_param_user_id_type_int' => 'User ID', 'object_updateChatParticipantAdd_param_inviter_id_type_int' => 'Inviter ID', 'object_updateChatParticipantAdd_param_date_type_int' => 'Date', 'object_updateChatParticipantAdd_param_version_type_int' => 'Version', 'object_updateChatParticipantDelete' => 'Update chat participant delete', 'object_updateChatParticipantDelete_param_chat_id_type_int' => 'Chat ID', 'object_updateChatParticipantDelete_param_user_id_type_int' => 'User ID', 'object_updateChatParticipantDelete_param_version_type_int' => 'Version', 'object_updateDcOptions' => 'Update DC options', 'object_updateDcOptions_param_dc_options_type_Vector t' => 'DC options', 'object_updateUserBlocked' => 'Update user blocked', 'object_updateUserBlocked_param_user_id_type_int' => 'User ID', 'object_updateUserBlocked_param_blocked_type_Bool' => 'Blocked?', 'object_updateNotifySettings' => 'Update notify settings', 'object_updateNotifySettings_param_peer_type_NotifyPeer' => 'Peer', 'object_updateNotifySettings_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_updateServiceNotification' => 'Update service notification', 'object_updateServiceNotification_param_popup_type_true' => 'Popup?', 'object_updateServiceNotification_param_inbox_date_type_int' => 'Inbox date', 'object_updateServiceNotification_param_type_type_string' => 'Type', 'object_updateServiceNotification_param_message_type_string' => 'Message', 'object_updateServiceNotification_param_media_type_MessageMedia' => 'Media', 'object_updateServiceNotification_param_entities_type_Vector t' => 'Entities', 'object_updatePrivacy' => 'Update privacy', 'object_updatePrivacy_param_key_type_PrivacyKey' => 'Key', 'object_updatePrivacy_param_rules_type_Vector t' => 'Rules', 'object_updateUserPhone' => 'Update user phone', 'object_updateUserPhone_param_user_id_type_int' => 'User ID', 'object_updateUserPhone_param_phone_type_string' => 'Phone', 'object_updateReadHistoryInbox' => 'Update read history inbox', 'object_updateReadHistoryInbox_param_peer_type_Peer' => 'Peer', 'object_updateReadHistoryInbox_param_max_id_type_int' => 'Max ID', 'object_updateReadHistoryInbox_param_pts_type_int' => 'Pts', 'object_updateReadHistoryInbox_param_pts_count_type_int' => 'Pts count', 'object_updateReadHistoryOutbox' => 'Update read history outbox', 'object_updateReadHistoryOutbox_param_peer_type_Peer' => 'Peer', 'object_updateReadHistoryOutbox_param_max_id_type_int' => 'Max ID', 'object_updateReadHistoryOutbox_param_pts_type_int' => 'Pts', 'object_updateReadHistoryOutbox_param_pts_count_type_int' => 'Pts count', 'object_updateWebPage' => 'Update web page', 'object_updateWebPage_param_webpage_type_WebPage' => 'Webpage', 'object_updateWebPage_param_pts_type_int' => 'Pts', 'object_updateWebPage_param_pts_count_type_int' => 'Pts count', 'object_updateReadMessagesContents' => 'Update read messages contents', 'object_updateReadMessagesContents_param_messages_type_Vector t' => 'Messages', 'object_updateReadMessagesContents_param_pts_type_int' => 'Pts', 'object_updateReadMessagesContents_param_pts_count_type_int' => 'Pts count', 'object_updateChannelTooLong' => 'Update channel too long', 'object_updateChannelTooLong_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelTooLong_param_pts_type_int' => 'Pts', 'object_updateChannel' => 'Update channel', 'object_updateChannel_param_channel_id_type_int' => 'Channel ID', 'object_updateNewChannelMessage' => 'Update new channel message', 'object_updateNewChannelMessage_param_message_type_Message' => 'Message', 'object_updateNewChannelMessage_param_pts_type_int' => 'Pts', 'object_updateNewChannelMessage_param_pts_count_type_int' => 'Pts count', 'object_updateReadChannelInbox' => 'Update read channel inbox', 'object_updateReadChannelInbox_param_channel_id_type_int' => 'Channel ID', 'object_updateReadChannelInbox_param_max_id_type_int' => 'Max ID', 'object_updateDeleteChannelMessages' => 'Update delete channel messages', 'object_updateDeleteChannelMessages_param_channel_id_type_int' => 'Channel ID', 'object_updateDeleteChannelMessages_param_messages_type_Vector t' => 'Messages', 'object_updateDeleteChannelMessages_param_pts_type_int' => 'Pts', 'object_updateDeleteChannelMessages_param_pts_count_type_int' => 'Pts count', 'object_updateChannelMessageViews' => 'Update channel message views', 'object_updateChannelMessageViews_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelMessageViews_param_id_type_int' => 'ID', 'object_updateChannelMessageViews_param_views_type_int' => 'Views', 'object_updateChatAdmins' => 'Update chat admins', 'object_updateChatAdmins_param_chat_id_type_int' => 'Chat ID', 'object_updateChatAdmins_param_enabled_type_Bool' => 'Enabled?', 'object_updateChatAdmins_param_version_type_int' => 'Version', 'object_updateChatParticipantAdmin' => 'Update chat participant admin', 'object_updateChatParticipantAdmin_param_chat_id_type_int' => 'Chat ID', 'object_updateChatParticipantAdmin_param_user_id_type_int' => 'User ID', 'object_updateChatParticipantAdmin_param_is_admin_type_Bool' => 'Is admin?', 'object_updateChatParticipantAdmin_param_version_type_int' => 'Version', 'object_updateNewStickerSet' => 'Update new sticker set', 'object_updateNewStickerSet_param_stickerset_type_messages.StickerSet' => 'Stickerset', 'object_updateStickerSetsOrder' => 'Update sticker sets order', 'object_updateStickerSetsOrder_param_masks_type_true' => 'Masks?', 'object_updateStickerSetsOrder_param_order_type_Vector t' => 'Order', 'object_updateStickerSets' => 'Update sticker sets', 'object_updateSavedGifs' => 'Update saved gifs', 'object_updateBotInlineQuery' => 'Update bot inline query', 'object_updateBotInlineQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotInlineQuery_param_user_id_type_int' => 'User ID', 'object_updateBotInlineQuery_param_query_type_string' => 'Query', 'object_updateBotInlineQuery_param_geo_type_GeoPoint' => 'Geo', 'object_updateBotInlineQuery_param_offset_type_string' => 'Offset', 'object_updateBotInlineSend' => 'Update bot inline send', 'object_updateBotInlineSend_param_user_id_type_int' => 'User ID', 'object_updateBotInlineSend_param_query_type_string' => 'Query', 'object_updateBotInlineSend_param_geo_type_GeoPoint' => 'Geo', 'object_updateBotInlineSend_param_id_type_string' => 'ID', 'object_updateBotInlineSend_param_msg_id_type_InputBotInlineMessageID' => 'Msg ID', 'object_updateEditChannelMessage' => 'Update edit channel message', 'object_updateEditChannelMessage_param_message_type_Message' => 'Message', 'object_updateEditChannelMessage_param_pts_type_int' => 'Pts', 'object_updateEditChannelMessage_param_pts_count_type_int' => 'Pts count', 'object_updateChannelPinnedMessage' => 'Update channel pinned message', 'object_updateChannelPinnedMessage_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelPinnedMessage_param_id_type_int' => 'ID', 'object_updateBotCallbackQuery' => 'Update bot callback query', 'object_updateBotCallbackQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotCallbackQuery_param_user_id_type_int' => 'User ID', 'object_updateBotCallbackQuery_param_peer_type_Peer' => 'Peer', 'object_updateBotCallbackQuery_param_msg_id_type_int' => 'Msg ID', 'object_updateBotCallbackQuery_param_chat_instance_type_long' => 'Chat instance', 'object_updateBotCallbackQuery_param_data_type_bytes' => 'Data', 'object_updateBotCallbackQuery_param_game_short_name_type_string' => 'Game short name', 'object_updateEditMessage' => 'Update edit message', 'object_updateEditMessage_param_message_type_Message' => 'Message', 'object_updateEditMessage_param_pts_type_int' => 'Pts', 'object_updateEditMessage_param_pts_count_type_int' => 'Pts count', 'object_updateInlineBotCallbackQuery' => 'Update inline bot callback query', 'object_updateInlineBotCallbackQuery_param_query_id_type_long' => 'Query ID', 'object_updateInlineBotCallbackQuery_param_user_id_type_int' => 'User ID', 'object_updateInlineBotCallbackQuery_param_msg_id_type_InputBotInlineMessageID' => 'Msg ID', 'object_updateInlineBotCallbackQuery_param_chat_instance_type_long' => 'Chat instance', 'object_updateInlineBotCallbackQuery_param_data_type_bytes' => 'Data', 'object_updateInlineBotCallbackQuery_param_game_short_name_type_string' => 'Game short name', 'object_updateReadChannelOutbox' => 'Update read channel outbox', 'object_updateReadChannelOutbox_param_channel_id_type_int' => 'Channel ID', 'object_updateReadChannelOutbox_param_max_id_type_int' => 'Max ID', 'object_updateDraftMessage' => 'Update draft message', 'object_updateDraftMessage_param_peer_type_Peer' => 'Peer', 'object_updateDraftMessage_param_draft_type_DraftMessage' => 'Draft', 'object_updateReadFeaturedStickers' => 'Update read featured stickers', 'object_updateRecentStickers' => 'Update recent stickers', 'object_updateConfig' => 'Update config', 'object_updatePtsChanged' => 'Update pts changed', 'object_updateChannelWebPage' => 'Update channel web page', 'object_updateChannelWebPage_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelWebPage_param_webpage_type_WebPage' => 'Webpage', 'object_updateChannelWebPage_param_pts_type_int' => 'Pts', 'object_updateChannelWebPage_param_pts_count_type_int' => 'Pts count', 'object_updateDialogPinned' => 'Update dialog pinned', 'object_updateDialogPinned_param_pinned_type_true' => 'Pinned?', 'object_updateDialogPinned_param_peer_type_Peer' => 'Peer', 'object_updatePinnedDialogs' => 'Update pinned dialogs', 'object_updatePinnedDialogs_param_order_type_Vector t' => 'Order', 'object_updateBotWebhookJSON' => 'Update bot webhook json', 'object_updateBotWebhookJSON_param_data_type_DataJSON' => 'Data', 'object_updateBotWebhookJSONQuery' => 'Update bot webhook json query', 'object_updateBotWebhookJSONQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotWebhookJSONQuery_param_data_type_DataJSON' => 'Data', 'object_updateBotWebhookJSONQuery_param_timeout_type_int' => 'Timeout', 'object_updateBotShippingQuery' => 'Update bot shipping query', 'object_updateBotShippingQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotShippingQuery_param_user_id_type_int' => 'User ID', 'object_updateBotShippingQuery_param_payload_type_bytes' => 'Payload', 'object_updateBotShippingQuery_param_shipping_address_type_PostAddress' => 'Shipping address', 'object_updateBotPrecheckoutQuery' => 'Update bot precheckout query', 'object_updateBotPrecheckoutQuery_param_query_id_type_long' => 'Query ID', 'object_updateBotPrecheckoutQuery_param_user_id_type_int' => 'User ID', 'object_updateBotPrecheckoutQuery_param_payload_type_bytes' => 'Payload', 'object_updateBotPrecheckoutQuery_param_info_type_PaymentRequestedInfo' => 'Info', 'object_updateBotPrecheckoutQuery_param_shipping_option_id_type_string' => 'Shipping option ID', 'object_updateBotPrecheckoutQuery_param_currency_type_string' => 'Currency', 'object_updateBotPrecheckoutQuery_param_total_amount_type_long' => 'Total amount', 'object_updatePhoneCall' => 'Update phone call', 'object_updatePhoneCall_param_phone_call_type_PhoneCall' => 'Phone call', 'object_updateLangPackTooLong' => 'Update lang pack too long', 'object_updateLangPack' => 'Update lang pack', 'object_updateLangPack_param_difference_type_LangPackDifference' => 'Difference', 'object_updateFavedStickers' => 'Update faved stickers', 'object_updateChannelReadMessagesContents' => 'Update channel read messages contents', 'object_updateChannelReadMessagesContents_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelReadMessagesContents_param_messages_type_Vector t' => 'Messages', 'object_updateContactsReset' => 'Update contacts reset', 'object_updateChannelAvailableMessages' => 'Update channel available messages', 'object_updateChannelAvailableMessages_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelAvailableMessages_param_available_min_id_type_int' => 'Available min ID', 'object_updates.state' => 'State', 'object_updates.state_param_pts_type_int' => 'Pts', 'object_updates.state_param_qts_type_int' => 'Qts', 'object_updates.state_param_date_type_int' => 'Date', 'object_updates.state_param_seq_type_int' => 'Seq', 'object_updates.state_param_unread_count_type_int' => 'Unread count', 'object_updates.differenceEmpty' => 'Empty difference', 'object_updates.differenceEmpty_param_date_type_int' => 'Date', 'object_updates.differenceEmpty_param_seq_type_int' => 'Seq', 'object_updates.difference' => 'Difference', 'object_updates.difference_param_new_messages_type_Vector t' => 'New messages', 'object_updates.difference_param_new_encrypted_messages_type_Vector t' => 'New encrypted messages', 'object_updates.difference_param_other_updates_type_Vector t' => 'Other updates', 'object_updates.difference_param_chats_type_Vector t' => 'Chats', 'object_updates.difference_param_users_type_Vector t' => 'Users', 'object_updates.difference_param_state_type_updates.State' => 'State', 'object_updates.differenceSlice' => 'Difference slice', 'object_updates.differenceSlice_param_new_messages_type_Vector t' => 'New messages', 'object_updates.differenceSlice_param_new_encrypted_messages_type_Vector t' => 'New encrypted messages', 'object_updates.differenceSlice_param_other_updates_type_Vector t' => 'Other updates', 'object_updates.differenceSlice_param_chats_type_Vector t' => 'Chats', 'object_updates.differenceSlice_param_users_type_Vector t' => 'Users', 'object_updates.differenceSlice_param_intermediate_state_type_updates.State' => 'Intermediate state', 'object_updates.differenceTooLong' => 'Difference too long', 'object_updates.differenceTooLong_param_pts_type_int' => 'Pts', 'object_updatesTooLong' => 'Updates too long', 'object_updateShortMessage' => 'Update short message', 'object_updateShortMessage_param_out_type_true' => 'Out?', 'object_updateShortMessage_param_mentioned_type_true' => 'Mentioned?', 'object_updateShortMessage_param_media_unread_type_true' => 'Media unread?', 'object_updateShortMessage_param_silent_type_true' => 'Silent?', 'object_updateShortMessage_param_id_type_int' => 'ID', 'object_updateShortMessage_param_user_id_type_int' => 'User ID', 'object_updateShortMessage_param_message_type_string' => 'Message', 'object_updateShortMessage_param_pts_type_int' => 'Pts', 'object_updateShortMessage_param_pts_count_type_int' => 'Pts count', 'object_updateShortMessage_param_date_type_int' => 'Date', 'object_updateShortMessage_param_fwd_from_type_MessageFwdHeader' => 'Fwd from', 'object_updateShortMessage_param_via_bot_id_type_int' => 'Via bot ID', 'object_updateShortMessage_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_updateShortMessage_param_entities_type_Vector t' => 'Entities', 'object_updateShortChatMessage' => 'Update short chat message', 'object_updateShortChatMessage_param_out_type_true' => 'Out?', 'object_updateShortChatMessage_param_mentioned_type_true' => 'Mentioned?', 'object_updateShortChatMessage_param_media_unread_type_true' => 'Media unread?', 'object_updateShortChatMessage_param_silent_type_true' => 'Silent?', 'object_updateShortChatMessage_param_id_type_int' => 'ID', 'object_updateShortChatMessage_param_from_id_type_int' => 'From ID', 'object_updateShortChatMessage_param_chat_id_type_int' => 'Chat ID', 'object_updateShortChatMessage_param_message_type_string' => 'Message', 'object_updateShortChatMessage_param_pts_type_int' => 'Pts', 'object_updateShortChatMessage_param_pts_count_type_int' => 'Pts count', 'object_updateShortChatMessage_param_date_type_int' => 'Date', 'object_updateShortChatMessage_param_fwd_from_type_MessageFwdHeader' => 'Fwd from', 'object_updateShortChatMessage_param_via_bot_id_type_int' => 'Via bot ID', 'object_updateShortChatMessage_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_updateShortChatMessage_param_entities_type_Vector t' => 'Entities', 'object_updateShort' => 'Update short', 'object_updateShort_param_update_type_Update' => 'Update', 'object_updateShort_param_date_type_int' => 'Date', 'object_updatesCombined' => 'Updates combined', 'object_updatesCombined_param_updates_type_Vector t' => 'Updates', 'object_updatesCombined_param_users_type_Vector t' => 'Users', 'object_updatesCombined_param_chats_type_Vector t' => 'Chats', 'object_updatesCombined_param_date_type_int' => 'Date', 'object_updatesCombined_param_seq_start_type_int' => 'Seq start', 'object_updatesCombined_param_seq_type_int' => 'Seq', 'object_updates' => 'Updates', 'object_updates_param_updates_type_Vector t' => 'Updates', 'object_updates_param_users_type_Vector t' => 'Users', 'object_updates_param_chats_type_Vector t' => 'Chats', 'object_updates_param_date_type_int' => 'Date', 'object_updates_param_seq_type_int' => 'Seq', 'object_updateShortSentMessage' => 'Update short sent message', 'object_updateShortSentMessage_param_out_type_true' => 'Out?', 'object_updateShortSentMessage_param_id_type_int' => 'ID', 'object_updateShortSentMessage_param_pts_type_int' => 'Pts', 'object_updateShortSentMessage_param_pts_count_type_int' => 'Pts count', 'object_updateShortSentMessage_param_date_type_int' => 'Date', 'object_updateShortSentMessage_param_media_type_MessageMedia' => 'Media', 'object_updateShortSentMessage_param_entities_type_Vector t' => 'Entities', 'object_photos.photos' => 'Photos', 'object_photos.photos_param_photos_type_Vector t' => 'Photos', 'object_photos.photos_param_users_type_Vector t' => 'Users', 'object_photos.photosSlice' => 'Photos slice', 'object_photos.photosSlice_param_count_type_int' => 'Count', 'object_photos.photosSlice_param_photos_type_Vector t' => 'Photos', 'object_photos.photosSlice_param_users_type_Vector t' => 'Users', 'object_photos.photo' => 'Photo', 'object_photos.photo_param_photo_type_Photo' => 'Photo', 'object_photos.photo_param_users_type_Vector t' => 'Users', 'object_upload.file' => 'File', 'object_upload.file_param_type_type_storage.FileType' => 'Type', 'object_upload.file_param_mtime_type_int' => 'Mtime', 'object_upload.file_param_bytes_type_bytes' => 'Bytes', 'object_upload.fileCdnRedirect' => 'File cdn redirect', 'object_upload.fileCdnRedirect_param_dc_id_type_int' => 'DC ID', 'object_upload.fileCdnRedirect_param_file_token_type_bytes' => 'File token', 'object_upload.fileCdnRedirect_param_encryption_key_type_bytes' => 'Encryption key', 'object_upload.fileCdnRedirect_param_encryption_iv_type_bytes' => 'Encryption iv', 'object_upload.fileCdnRedirect_param_cdn_file_hashes_type_Vector t' => 'Cdn file hashes', 'object_dcOption' => 'DC option', 'object_dcOption_param_ipv6_type_true' => 'Ipv6?', 'object_dcOption_param_media_only_type_true' => 'Media only?', 'object_dcOption_param_tcpo_only_type_true' => 'Tcpo only?', 'object_dcOption_param_cdn_type_true' => 'Cdn?', 'object_dcOption_param_static_type_true' => 'Static?', 'object_dcOption_param_id_type_int' => 'ID', 'object_dcOption_param_ip_address_type_string' => 'Ip address', 'object_dcOption_param_port_type_int' => 'Port', 'object_config' => 'Config', 'object_config_param_phonecalls_enabled_type_true' => 'Phonecalls enabled?', 'object_config_param_default_p2p_contacts_type_true' => 'Default p2p contacts?', 'object_config_param_date_type_int' => 'Date', 'object_config_param_expires_type_int' => 'Expires', 'object_config_param_test_mode_type_Bool' => 'Test mode?', 'object_config_param_this_dc_type_int' => 'This DC', 'object_config_param_dc_options_type_Vector t' => 'DC options', 'object_config_param_chat_size_max_type_int' => 'Chat size max', 'object_config_param_megagroup_size_max_type_int' => 'Megagroup size max', 'object_config_param_forwarded_count_max_type_int' => 'Forwarded count max', 'object_config_param_online_update_period_ms_type_int' => 'Online update period ms', 'object_config_param_offline_blur_timeout_ms_type_int' => 'Offline blur timeout ms', 'object_config_param_offline_idle_timeout_ms_type_int' => 'Offline IDle timeout ms', 'object_config_param_online_cloud_timeout_ms_type_int' => 'Online cloud timeout ms', 'object_config_param_notify_cloud_delay_ms_type_int' => 'Notify cloud delay ms', 'object_config_param_notify_default_delay_ms_type_int' => 'Notify default delay ms', 'object_config_param_chat_big_size_type_int' => 'Chat big size', 'object_config_param_push_chat_period_ms_type_int' => 'Push chat period ms', 'object_config_param_push_chat_limit_type_int' => 'Push chat limit', 'object_config_param_saved_gifs_limit_type_int' => 'Saved gifs limit', 'object_config_param_edit_time_limit_type_int' => 'Edit time limit', 'object_config_param_rating_e_decay_type_int' => 'Rating e decay', 'object_config_param_stickers_recent_limit_type_int' => 'Stickers recent limit', 'object_config_param_stickers_faved_limit_type_int' => 'Stickers faved limit', 'object_config_param_channels_read_media_period_type_int' => 'Channels read media period', 'object_config_param_tmp_sessions_type_int' => 'Tmp sessions', 'object_config_param_pinned_dialogs_count_max_type_int' => 'Pinned dialogs count max', 'object_config_param_call_receive_timeout_ms_type_int' => 'Call receive timeout ms', 'object_config_param_call_ring_timeout_ms_type_int' => 'Call ring timeout ms', 'object_config_param_call_connect_timeout_ms_type_int' => 'Call connect timeout ms', 'object_config_param_call_packet_timeout_ms_type_int' => 'Call packet timeout ms', 'object_config_param_me_url_prefix_type_string' => 'Me URL prefix', 'object_config_param_suggested_lang_code_type_string' => 'Suggested lang code', 'object_config_param_lang_pack_version_type_int' => 'Lang pack version', 'object_config_param_disabled_features_type_Vector t' => 'Disabled features', 'object_nearestDc' => 'Nearest DC', 'object_nearestDc_param_country_type_string' => 'Country', 'object_nearestDc_param_this_dc_type_int' => 'This DC', 'object_nearestDc_param_nearest_dc_type_int' => 'Nearest DC', 'object_help.appUpdate' => 'App update', 'object_help.appUpdate_param_id_type_int' => 'ID', 'object_help.appUpdate_param_critical_type_Bool' => 'Critical?', 'object_help.appUpdate_param_url_type_string' => 'URL', 'object_help.appUpdate_param_text_type_string' => 'Text', 'object_help.noAppUpdate' => 'No app update', 'object_help.inviteText' => 'Invite text', 'object_help.inviteText_param_message_type_string' => 'Message', 'object_encryptedChatEmpty' => 'Empty encrypted chat', 'object_encryptedChatEmpty_param_id_type_int' => 'ID', 'object_encryptedChatWaiting' => 'Encrypted chat waiting', 'object_encryptedChatWaiting_param_id_type_int' => 'ID', 'object_encryptedChatWaiting_param_access_hash_type_long' => 'Access hash', 'object_encryptedChatWaiting_param_date_type_int' => 'Date', 'object_encryptedChatWaiting_param_admin_id_type_int' => 'Admin ID', 'object_encryptedChatWaiting_param_participant_id_type_int' => 'Participant ID', 'object_encryptedChatRequested' => 'Encrypted chat requested', 'object_encryptedChatRequested_param_id_type_int' => 'ID', 'object_encryptedChatRequested_param_access_hash_type_long' => 'Access hash', 'object_encryptedChatRequested_param_date_type_int' => 'Date', 'object_encryptedChatRequested_param_admin_id_type_int' => 'Admin ID', 'object_encryptedChatRequested_param_participant_id_type_int' => 'Participant ID', 'object_encryptedChatRequested_param_g_a_type_bytes' => 'G a', 'object_encryptedChat' => 'Encrypted chat', 'object_encryptedChat_param_id_type_int' => 'ID', 'object_encryptedChat_param_access_hash_type_long' => 'Access hash', 'object_encryptedChat_param_date_type_int' => 'Date', 'object_encryptedChat_param_admin_id_type_int' => 'Admin ID', 'object_encryptedChat_param_participant_id_type_int' => 'Participant ID', 'object_encryptedChat_param_g_a_or_b_type_bytes' => 'G a or b', 'object_encryptedChat_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_encryptedChatDiscarded' => 'Encrypted chat discarded', 'object_encryptedChatDiscarded_param_id_type_int' => 'ID', 'object_inputEncryptedChat' => 'Encrypted chat', 'object_inputEncryptedChat_param_chat_id_type_int' => 'Chat ID', 'object_inputEncryptedChat_param_access_hash_type_long' => 'Access hash', 'object_encryptedFileEmpty' => 'Empty encrypted file', 'object_encryptedFile' => 'Encrypted file', 'object_encryptedFile_param_id_type_long' => 'ID', 'object_encryptedFile_param_access_hash_type_long' => 'Access hash', 'object_encryptedFile_param_size_type_int' => 'Size', 'object_encryptedFile_param_dc_id_type_int' => 'DC ID', 'object_encryptedFile_param_key_fingerprint_type_int' => 'Key fingerprint', 'object_inputEncryptedFileEmpty' => 'Empty input encrypted file', 'object_inputEncryptedFileUploaded' => 'Encrypted file uploaded', 'object_inputEncryptedFileUploaded_param_id_type_long' => 'ID', 'object_inputEncryptedFileUploaded_param_parts_type_int' => 'Parts', 'object_inputEncryptedFileUploaded_param_md5_checksum_type_string' => 'Md5 checksum', 'object_inputEncryptedFileUploaded_param_key_fingerprint_type_int' => 'Key fingerprint', 'object_inputEncryptedFile' => 'Encrypted file', 'object_inputEncryptedFile_param_id_type_long' => 'ID', 'object_inputEncryptedFile_param_access_hash_type_long' => 'Access hash', 'object_inputEncryptedFileBigUploaded' => 'Encrypted file big uploaded', 'object_inputEncryptedFileBigUploaded_param_id_type_long' => 'ID', 'object_inputEncryptedFileBigUploaded_param_parts_type_int' => 'Parts', 'object_inputEncryptedFileBigUploaded_param_key_fingerprint_type_int' => 'Key fingerprint', 'object_encryptedMessage' => 'Encrypted message', 'object_encryptedMessage_param_chat_id_type_int' => 'Chat ID', 'object_encryptedMessage_param_date_type_int' => 'Date', 'object_encryptedMessage_param_decrypted_message_type_DecryptedMessage' => 'Decrypted message', 'object_encryptedMessage_param_file_type_EncryptedFile' => 'File', 'object_encryptedMessageService' => 'Encrypted message service', 'object_encryptedMessageService_param_chat_id_type_int' => 'Chat ID', 'object_encryptedMessageService_param_date_type_int' => 'Date', 'object_encryptedMessageService_param_decrypted_message_type_DecryptedMessage' => 'Decrypted message', 'object_messages.dhConfigNotModified' => 'Dh config not modified', 'object_messages.dhConfigNotModified_param_random_type_bytes' => 'Random', 'object_messages.dhConfig' => 'Dh config', 'object_messages.dhConfig_param_g_type_int' => 'G', 'object_messages.dhConfig_param_p_type_bytes' => 'P', 'object_messages.dhConfig_param_version_type_int' => 'Version', 'object_messages.dhConfig_param_random_type_bytes' => 'Random', 'object_messages.sentEncryptedMessage' => 'Sent encrypted message', 'object_messages.sentEncryptedMessage_param_date_type_int' => 'Date', 'object_messages.sentEncryptedFile' => 'Sent encrypted file', 'object_messages.sentEncryptedFile_param_date_type_int' => 'Date', 'object_messages.sentEncryptedFile_param_file_type_EncryptedFile' => 'File', 'object_inputDocumentEmpty' => 'Empty input document', 'object_inputDocument' => 'Document', 'object_inputDocument_param_id_type_long' => 'ID', 'object_inputDocument_param_access_hash_type_long' => 'Access hash', 'object_documentEmpty' => 'Empty document', 'object_documentEmpty_param_id_type_long' => 'ID', 'object_document' => 'Document', 'object_document_param_id_type_long' => 'ID', 'object_document_param_access_hash_type_long' => 'Access hash', 'object_document_param_date_type_int' => 'Date', 'object_document_param_mime_type_type_string' => 'Mime type', 'object_document_param_size_type_int' => 'Size', 'object_document_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_document_param_dc_id_type_int' => 'DC ID', 'object_document_param_version_type_int' => 'Version', 'object_document_param_attributes_type_Vector t' => 'Attributes', 'object_help.support' => 'Support', 'object_help.support_param_phone_number_type_string' => 'Phone number', 'object_help.support_param_user_type_User' => 'User', 'object_notifyPeer' => 'Notify peer', 'object_notifyPeer_param_peer_type_Peer' => 'Peer', 'object_notifyUsers' => 'Notify users', 'object_notifyChats' => 'Notify chats', 'object_notifyAll' => 'Notify all', 'object_sendMessageTypingAction' => 'Send message typing action', 'object_sendMessageCancelAction' => 'Send message cancel action', 'object_sendMessageRecordVideoAction' => 'Send message record video action', 'object_sendMessageUploadVideoAction' => 'Send message upload video action', 'object_sendMessageUploadVideoAction_param_progress_type_int' => 'Progress', 'object_sendMessageRecordAudioAction' => 'Send message record audio action', 'object_sendMessageUploadAudioAction' => 'Send message upload audio action', 'object_sendMessageUploadAudioAction_param_progress_type_int' => 'Progress', 'object_sendMessageUploadPhotoAction' => 'Send message upload photo action', 'object_sendMessageUploadPhotoAction_param_progress_type_int' => 'Progress', 'object_sendMessageUploadDocumentAction' => 'Send message upload document action', 'object_sendMessageUploadDocumentAction_param_progress_type_int' => 'Progress', 'object_sendMessageGeoLocationAction' => 'Send message geo location action', 'object_sendMessageChooseContactAction' => 'Send message choose contact action', 'object_sendMessageGamePlayAction' => 'Send message game play action', 'object_sendMessageRecordRoundAction' => 'Send message record round action', 'object_sendMessageUploadRoundAction' => 'Send message upload round action', 'object_sendMessageUploadRoundAction_param_progress_type_int' => 'Progress', 'object_contacts.found' => 'Found', 'object_contacts.found_param_my_results_type_Vector t' => 'My results', 'object_contacts.found_param_results_type_Vector t' => 'Results', 'object_contacts.found_param_chats_type_Vector t' => 'Chats', 'object_contacts.found_param_users_type_Vector t' => 'Users', 'object_inputPrivacyKeyStatusTimestamp' => 'Privacy key status timestamp', 'object_inputPrivacyKeyChatInvite' => 'Privacy key chat invite', 'object_inputPrivacyKeyPhoneCall' => 'Privacy key phone call', 'object_privacyKeyStatusTimestamp' => 'Privacy key status timestamp', 'object_privacyKeyPhoneCall' => 'Privacy key phone call', 'object_inputPrivacyValueAllowContacts' => 'Privacy value allow contacts', 'object_inputPrivacyValueAllowAll' => 'Privacy value allow all', 'object_inputPrivacyValueAllowUsers' => 'Privacy value allow users', 'object_inputPrivacyValueAllowUsers_param_users_type_Vector t' => 'Users', 'object_inputPrivacyValueDisallowContacts' => 'Privacy value disallow contacts', 'object_inputPrivacyValueDisallowAll' => 'Privacy value disallow all', 'object_inputPrivacyValueDisallowUsers' => 'Privacy value disallow users', 'object_inputPrivacyValueDisallowUsers_param_users_type_Vector t' => 'Users', 'object_privacyValueAllowContacts' => 'Privacy value allow contacts', 'object_privacyValueAllowAll' => 'Privacy value allow all', 'object_privacyValueAllowUsers' => 'Privacy value allow users', 'object_privacyValueAllowUsers_param_users_type_Vector t' => 'Users', 'object_privacyValueDisallowContacts' => 'Privacy value disallow contacts', 'object_privacyValueDisallowAll' => 'Privacy value disallow all', 'object_privacyValueDisallowUsers' => 'Privacy value disallow users', 'object_privacyValueDisallowUsers_param_users_type_Vector t' => 'Users', 'object_account.privacyRules' => 'Privacy rules', 'object_account.privacyRules_param_rules_type_Vector t' => 'Rules', 'object_account.privacyRules_param_users_type_Vector t' => 'Users', 'object_accountDaysTTL' => 'Account TTL in days', 'object_accountDaysTTL_param_days_type_int' => 'Days', 'object_documentAttributeImageSize' => 'Document attribute image size', 'object_documentAttributeImageSize_param_w_type_int' => 'Width', 'object_documentAttributeImageSize_param_h_type_int' => 'Height', 'object_documentAttributeAnimated' => 'Document attribute animated', 'object_documentAttributeSticker' => 'Document attribute sticker', 'object_documentAttributeSticker_param_mask_type_true' => 'Mask?', 'object_documentAttributeSticker_param_alt_type_string' => 'Alt', 'object_documentAttributeSticker_param_stickerset_type_InputStickerSet' => 'Stickerset', 'object_documentAttributeSticker_param_mask_coords_type_MaskCoords' => 'Mask coords', 'object_documentAttributeVideo' => 'Document attribute video', 'object_documentAttributeVideo_param_round_message_type_true' => 'Round message?', 'object_documentAttributeVideo_param_supports_streaming_type_true' => 'Supports streaming?', 'object_documentAttributeVideo_param_duration_type_int' => 'Duration', 'object_documentAttributeVideo_param_w_type_int' => 'Width', 'object_documentAttributeVideo_param_h_type_int' => 'Height', 'object_documentAttributeAudio' => 'Document attribute audio', 'object_documentAttributeAudio_param_voice_type_true' => 'Voice?', 'object_documentAttributeAudio_param_duration_type_int' => 'Duration', 'object_documentAttributeAudio_param_title_type_string' => 'Title', 'object_documentAttributeAudio_param_performer_type_string' => 'Performer', 'object_documentAttributeAudio_param_waveform_type_bytes' => 'Waveform', 'object_documentAttributeFilename' => 'Document attribute filename', 'object_documentAttributeFilename_param_file_name_type_string' => 'File name', 'object_documentAttributeHasStickers' => 'Document attribute has stickers', 'object_messages.stickersNotModified' => 'Stickers not modified', 'object_messages.stickers' => 'Stickers', 'object_messages.stickers_param_hash_type_string' => 'Hash', 'object_messages.stickers_param_stickers_type_Vector t' => 'Stickers', 'object_stickerPack' => 'Sticker pack', 'object_stickerPack_param_emoticon_type_string' => 'Emoticon', 'object_stickerPack_param_documents_type_Vector t' => 'Documents', 'object_messages.allStickersNotModified' => 'All stickers not modified', 'object_messages.allStickers' => 'All stickers', 'object_messages.allStickers_param_hash_type_int' => 'Hash', 'object_messages.allStickers_param_sets_type_Vector t' => 'Sets', 'object_disabledFeature' => 'Disabled feature', 'object_disabledFeature_param_feature_type_string' => 'Feature', 'object_disabledFeature_param_description_type_string' => 'Description', 'object_messages.affectedMessages' => 'Affected messages', 'object_messages.affectedMessages_param_pts_type_int' => 'Pts', 'object_messages.affectedMessages_param_pts_count_type_int' => 'Pts count', 'object_contactLinkUnknown' => 'Contact link unknown', 'object_contactLinkNone' => 'Contact link none', 'object_contactLinkHasPhone' => 'Contact link has phone', 'object_contactLinkContact' => 'Contact link contact', 'object_webPageEmpty' => 'Empty web page', 'object_webPageEmpty_param_id_type_long' => 'ID', 'object_webPagePending' => 'Web page pending', 'object_webPagePending_param_id_type_long' => 'ID', 'object_webPagePending_param_date_type_int' => 'Date', 'object_webPage' => 'Web page', 'object_webPage_param_id_type_long' => 'ID', 'object_webPage_param_url_type_string' => 'URL', 'object_webPage_param_display_url_type_string' => 'Display URL', 'object_webPage_param_hash_type_int' => 'Hash', 'object_webPage_param_type_type_string' => 'Type', 'object_webPage_param_site_name_type_string' => 'Site name', 'object_webPage_param_title_type_string' => 'Title', 'object_webPage_param_description_type_string' => 'Description', 'object_webPage_param_photo_type_Photo' => 'Photo', 'object_webPage_param_embed_url_type_string' => 'Embed URL', 'object_webPage_param_embed_type_type_string' => 'Embed type', 'object_webPage_param_embed_width_type_int' => 'Embed width', 'object_webPage_param_embed_height_type_int' => 'Embed height', 'object_webPage_param_duration_type_int' => 'Duration', 'object_webPage_param_author_type_string' => 'Author', 'object_webPage_param_document_type_Document' => 'Document', 'object_webPage_param_cached_page_type_Page' => 'Cached page', 'object_webPageNotModified' => 'Web page not modified', 'object_authorization' => 'Authorization', 'object_authorization_param_hash_type_long' => 'Hash', 'object_authorization_param_device_model_type_string' => 'Device model', 'object_authorization_param_platform_type_string' => 'Platform', 'object_authorization_param_system_version_type_string' => 'System version', 'object_authorization_param_api_id_type_int' => 'Api ID', 'object_authorization_param_app_name_type_string' => 'App name', 'object_authorization_param_app_version_type_string' => 'App version', 'object_authorization_param_date_created_type_int' => 'Date created', 'object_authorization_param_date_active_type_int' => 'Date active', 'object_authorization_param_ip_type_string' => 'Ip', 'object_authorization_param_country_type_string' => 'Country', 'object_authorization_param_region_type_string' => 'Region', 'object_account.authorizations' => 'Authorized clients for this account', 'object_account.authorizations_param_authorizations_type_Vector t' => 'Authorizations', 'object_account.noPassword' => 'No password', 'object_account.noPassword_param_new_salt_type_bytes' => 'New salt', 'object_account.noPassword_param_email_unconfirmed_pattern_type_string' => 'Email unconfirmed pattern', 'object_account.password' => 'Password', 'object_account.password_param_current_salt_type_bytes' => 'Current salt', 'object_account.password_param_new_salt_type_bytes' => 'New salt', 'object_account.password_param_hint_type_string' => 'Hint', 'object_account.password_param_has_recovery_type_Bool' => 'Has recovery?', 'object_account.password_param_email_unconfirmed_pattern_type_string' => 'Email unconfirmed pattern', 'object_account.passwordSettings' => 'Password settings', 'object_account.passwordSettings_param_email_type_string' => 'Email', 'object_account.passwordInputSettings' => '2FA password settings', 'object_account.passwordInputSettings_param_new_salt_type_bytes' => '`$new_salt = $MadelineProto->account->getPassword()[\'new_salt\'].$MadelineProto->random(8);`', 'object_account.passwordInputSettings_param_new_password_hash_type_bytes' => '`hash(\'sha256\', $new_salt.$new_password.$new_salt, true)`', 'object_account.passwordInputSettings_param_hint_type_string' => 'Hint', 'object_account.passwordInputSettings_param_email_type_string' => 'Email', 'object_auth.passwordRecovery' => 'Password recovery', 'object_auth.passwordRecovery_param_email_pattern_type_string' => 'Email pattern', 'object_receivedNotifyMessage' => 'Received notify message', 'object_receivedNotifyMessage_param_id_type_int' => 'ID', 'object_chatInviteEmpty' => 'Empty chat invite', 'object_chatInviteExported' => 'Exported chat invite', 'object_chatInviteExported_param_link_type_string' => 'Link', 'object_chatInviteAlready' => 'Invite of a chat of which I am already member ', 'object_chatInviteAlready_param_chat_type_Chat' => 'Chat', 'object_chatInvite' => 'Chat invite', 'object_chatInvite_param_channel_type_true' => 'Channel?', 'object_chatInvite_param_broadcast_type_true' => 'Broadcast?', 'object_chatInvite_param_public_type_true' => 'Public?', 'object_chatInvite_param_megagroup_type_true' => 'Megagroup?', 'object_chatInvite_param_title_type_string' => 'Title', 'object_chatInvite_param_photo_type_ChatPhoto' => 'Photo', 'object_chatInvite_param_participants_count_type_int' => 'Participants count', 'object_chatInvite_param_participants_type_Vector t' => 'Participants', 'object_inputStickerSetEmpty' => 'Empty input sticker set', 'object_inputStickerSetID' => 'Sticker set ID', 'object_inputStickerSetID_param_id_type_long' => 'ID', 'object_inputStickerSetID_param_access_hash_type_long' => 'Access hash', 'object_inputStickerSetShortName' => 'Sticker set short name', 'object_inputStickerSetShortName_param_short_name_type_string' => 'Short name', 'object_stickerSet' => 'Sticker set', 'object_stickerSet_param_installed_type_true' => 'Installed?', 'object_stickerSet_param_archived_type_true' => 'Archived?', 'object_stickerSet_param_official_type_true' => 'Official?', 'object_stickerSet_param_masks_type_true' => 'Masks?', 'object_stickerSet_param_id_type_long' => 'ID', 'object_stickerSet_param_access_hash_type_long' => 'Access hash', 'object_stickerSet_param_title_type_string' => 'Title', 'object_stickerSet_param_short_name_type_string' => 'Short name', 'object_stickerSet_param_count_type_int' => 'Count', 'object_stickerSet_param_hash_type_int' => 'Hash', 'object_messages.stickerSet' => 'Sticker set', 'object_messages.stickerSet_param_set_type_StickerSet' => 'Set', 'object_messages.stickerSet_param_packs_type_Vector t' => 'Packs', 'object_messages.stickerSet_param_documents_type_Vector t' => 'Documents', 'object_botInfo' => 'Bot info', 'object_botInfo_param_user_id_type_int' => 'User ID', 'object_botInfo_param_description_type_string' => 'Description', 'object_botInfo_param_commands_type_Vector t' => 'Commands', 'object_keyboardButton' => 'Keyboard button', 'object_keyboardButton_param_text_type_string' => 'Text', 'object_keyboardButtonUrl' => 'Keyboard button URL', 'object_keyboardButtonUrl_param_text_type_string' => 'Text', 'object_keyboardButtonUrl_param_url_type_string' => 'URL', 'object_keyboardButtonCallback' => 'Keyboard button callback', 'object_keyboardButtonCallback_param_text_type_string' => 'Text', 'object_keyboardButtonCallback_param_data_type_bytes' => 'Data', 'object_keyboardButtonRequestPhone' => 'Keyboard button request phone', 'object_keyboardButtonRequestPhone_param_text_type_string' => 'Text', 'object_keyboardButtonRequestGeoLocation' => 'Keyboard button request geo location', 'object_keyboardButtonRequestGeoLocation_param_text_type_string' => 'Text', 'object_keyboardButtonSwitchInline' => 'Keyboard button switch inline', 'object_keyboardButtonSwitchInline_param_same_peer_type_true' => 'Same peer?', 'object_keyboardButtonSwitchInline_param_text_type_string' => 'Text', 'object_keyboardButtonSwitchInline_param_query_type_string' => 'Query', 'object_keyboardButtonGame' => 'Keyboard button game', 'object_keyboardButtonGame_param_text_type_string' => 'Text', 'object_keyboardButtonBuy' => 'Keyboard button buy', 'object_keyboardButtonBuy_param_text_type_string' => 'Text', 'object_keyboardButtonRow' => 'Keyboard button row', 'object_keyboardButtonRow_param_buttons_type_Vector t' => 'Buttons', 'object_replyKeyboardHide' => 'Reply keyboard hide', 'object_replyKeyboardHide_param_selective_type_true' => 'Selective?', 'object_replyKeyboardForceReply' => 'Reply keyboard force reply', 'object_replyKeyboardForceReply_param_single_use_type_true' => 'Single use?', 'object_replyKeyboardForceReply_param_selective_type_true' => 'Selective?', 'object_replyKeyboardMarkup' => 'Reply keyboard markup', 'object_replyKeyboardMarkup_param_resize_type_true' => 'Resize?', 'object_replyKeyboardMarkup_param_single_use_type_true' => 'Single use?', 'object_replyKeyboardMarkup_param_selective_type_true' => 'Selective?', 'object_replyKeyboardMarkup_param_rows_type_Vector t' => 'Rows', 'object_replyInlineMarkup' => 'Reply inline markup', 'object_replyInlineMarkup_param_rows_type_Vector t' => 'Rows', 'object_messageEntityUnknown' => 'Message entity unknown', 'object_messageEntityUnknown_param_offset_type_int' => 'Offset', 'object_messageEntityUnknown_param_length_type_int' => 'Length', 'object_messageEntityMention' => 'Message entity mention', 'object_messageEntityMention_param_offset_type_int' => 'Offset', 'object_messageEntityMention_param_length_type_int' => 'Length', 'object_messageEntityHashtag' => 'Message entity hashtag', 'object_messageEntityHashtag_param_offset_type_int' => 'Offset', 'object_messageEntityHashtag_param_length_type_int' => 'Length', 'object_messageEntityBotCommand' => 'Message entity bot command', 'object_messageEntityBotCommand_param_offset_type_int' => 'Offset', 'object_messageEntityBotCommand_param_length_type_int' => 'Length', 'object_messageEntityUrl' => 'Message entity URL', 'object_messageEntityUrl_param_offset_type_int' => 'Offset', 'object_messageEntityUrl_param_length_type_int' => 'Length', 'object_messageEntityEmail' => 'Message entity email', 'object_messageEntityEmail_param_offset_type_int' => 'Offset', 'object_messageEntityEmail_param_length_type_int' => 'Length', 'object_messageEntityBold' => 'Message entity bold', 'object_messageEntityBold_param_offset_type_int' => 'Offset', 'object_messageEntityBold_param_length_type_int' => 'Length', 'object_messageEntityItalic' => 'Message entity italic', 'object_messageEntityItalic_param_offset_type_int' => 'Offset', 'object_messageEntityItalic_param_length_type_int' => 'Length', 'object_messageEntityCode' => 'Message entity code', 'object_messageEntityCode_param_offset_type_int' => 'Offset', 'object_messageEntityCode_param_length_type_int' => 'Length', 'object_messageEntityPre' => 'Message entity pre', 'object_messageEntityPre_param_offset_type_int' => 'Offset', 'object_messageEntityPre_param_length_type_int' => 'Length', 'object_messageEntityPre_param_language_type_string' => 'Language', 'object_messageEntityTextUrl' => 'Message entity text URL', 'object_messageEntityTextUrl_param_offset_type_int' => 'Offset', 'object_messageEntityTextUrl_param_length_type_int' => 'Length', 'object_messageEntityTextUrl_param_url_type_string' => 'URL', 'object_messageEntityMentionName' => 'Message entity mention name', 'object_messageEntityMentionName_param_offset_type_int' => 'Offset', 'object_messageEntityMentionName_param_length_type_int' => 'Length', 'object_messageEntityMentionName_param_user_id_type_int' => 'User ID', 'object_inputMessageEntityMentionName' => 'Message entity mention name', 'object_inputMessageEntityMentionName_param_offset_type_int' => 'Offset', 'object_inputMessageEntityMentionName_param_length_type_int' => 'Length', 'object_inputMessageEntityMentionName_param_user_id_type_InputUser' => 'User ID', 'object_inputChannelEmpty' => 'Empty input channel', 'object_inputChannel' => 'Channel', 'object_inputChannel_param_channel_id_type_int' => 'Channel ID', 'object_inputChannel_param_access_hash_type_long' => 'Access hash', 'object_contacts.resolvedPeer' => 'Resolved peer', 'object_contacts.resolvedPeer_param_peer_type_Peer' => 'Peer', 'object_contacts.resolvedPeer_param_chats_type_Vector t' => 'Chats', 'object_contacts.resolvedPeer_param_users_type_Vector t' => 'Users', 'object_messageRange' => 'Message range', 'object_messageRange_param_min_id_type_int' => 'Min ID', 'object_messageRange_param_max_id_type_int' => 'Max ID', 'object_updates.channelDifferenceEmpty' => 'Empty channel difference', 'object_updates.channelDifferenceEmpty_param_final_type_true' => 'Final?', 'object_updates.channelDifferenceEmpty_param_pts_type_int' => 'Pts', 'object_updates.channelDifferenceEmpty_param_timeout_type_int' => 'Timeout', 'object_updates.channelDifferenceTooLong' => 'Channel difference too long', 'object_updates.channelDifferenceTooLong_param_final_type_true' => 'Final?', 'object_updates.channelDifferenceTooLong_param_pts_type_int' => 'Pts', 'object_updates.channelDifferenceTooLong_param_timeout_type_int' => 'Timeout', 'object_updates.channelDifferenceTooLong_param_top_message_type_int' => 'Top message', 'object_updates.channelDifferenceTooLong_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_updates.channelDifferenceTooLong_param_read_outbox_max_id_type_int' => 'Read outbox max ID', 'object_updates.channelDifferenceTooLong_param_unread_count_type_int' => 'Unread count', 'object_updates.channelDifferenceTooLong_param_unread_mentions_count_type_int' => 'Unread mentions count', 'object_updates.channelDifferenceTooLong_param_messages_type_Vector t' => 'Messages', 'object_updates.channelDifferenceTooLong_param_chats_type_Vector t' => 'Chats', 'object_updates.channelDifferenceTooLong_param_users_type_Vector t' => 'Users', 'object_updates.channelDifference' => 'Channel difference', 'object_updates.channelDifference_param_final_type_true' => 'Final?', 'object_updates.channelDifference_param_pts_type_int' => 'Pts', 'object_updates.channelDifference_param_timeout_type_int' => 'Timeout', 'object_updates.channelDifference_param_new_messages_type_Vector t' => 'New messages', 'object_updates.channelDifference_param_other_updates_type_Vector t' => 'Other updates', 'object_updates.channelDifference_param_chats_type_Vector t' => 'Chats', 'object_updates.channelDifference_param_users_type_Vector t' => 'Users', 'object_channelMessagesFilterEmpty' => 'Empty channel messages filter', 'object_channelMessagesFilter' => 'Channel messages filter', 'object_channelMessagesFilter_param_exclude_new_messages_type_true' => 'Exclude new messages?', 'object_channelMessagesFilter_param_ranges_type_Vector t' => 'Ranges', 'object_channelParticipant' => 'Channel participant', 'object_channelParticipant_param_user_id_type_int' => 'User ID', 'object_channelParticipant_param_date_type_int' => 'Date', 'object_channelParticipantSelf' => 'Channel participant self', 'object_channelParticipantSelf_param_user_id_type_int' => 'User ID', 'object_channelParticipantSelf_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantSelf_param_date_type_int' => 'Date', 'object_channelParticipantCreator' => 'Channel participant creator', 'object_channelParticipantCreator_param_user_id_type_int' => 'User ID', 'object_channelParticipantAdmin' => 'Channel participant admin', 'object_channelParticipantAdmin_param_can_edit_type_true' => 'Can edit?', 'object_channelParticipantAdmin_param_user_id_type_int' => 'User ID', 'object_channelParticipantAdmin_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantAdmin_param_promoted_by_type_int' => 'Promoted by', 'object_channelParticipantAdmin_param_date_type_int' => 'Date', 'object_channelParticipantAdmin_param_admin_rights_type_ChannelAdminRights' => 'Admin rights', 'object_channelParticipantBanned' => 'Channel participant banned', 'object_channelParticipantBanned_param_left_type_true' => 'Left?', 'object_channelParticipantBanned_param_user_id_type_int' => 'User ID', 'object_channelParticipantBanned_param_kicked_by_type_int' => 'Kicked by', 'object_channelParticipantBanned_param_date_type_int' => 'Date', 'object_channelParticipantBanned_param_banned_rights_type_ChannelBannedRights' => 'Banned rights', 'object_channelParticipantsRecent' => 'Channel participants recent', 'object_channelParticipantsAdmins' => 'Channel participants admins', 'object_channelParticipantsKicked' => 'Channel participants kicked', 'object_channelParticipantsKicked_param_q_type_string' => 'Query', 'object_channelParticipantsBots' => 'Channel participants bots', 'object_channelParticipantsBanned' => 'Channel participants banned', 'object_channelParticipantsBanned_param_q_type_string' => 'Query', 'object_channelParticipantsSearch' => 'Channel participants search', 'object_channelParticipantsSearch_param_q_type_string' => 'Query', 'object_channels.channelParticipants' => 'Channel participants', 'object_channels.channelParticipants_param_count_type_int' => 'Count', 'object_channels.channelParticipants_param_participants_type_Vector t' => 'Participants', 'object_channels.channelParticipants_param_users_type_Vector t' => 'Users', 'object_channels.channelParticipantsNotModified' => 'Channel participants not modified', 'object_channels.channelParticipant' => 'Channel participant', 'object_channels.channelParticipant_param_participant_type_ChannelParticipant' => 'Participant', 'object_channels.channelParticipant_param_users_type_Vector t' => 'Users', 'object_help.termsOfService' => 'Terms of service', 'object_help.termsOfService_param_text_type_string' => 'Text', 'object_foundGif' => 'Found gif', 'object_foundGif_param_url_type_string' => 'URL', 'object_foundGif_param_thumb_url_type_string' => 'Thumbnail URL', 'object_foundGif_param_content_url_type_string' => 'Content URL', 'object_foundGif_param_content_type_type_string' => 'Content type', 'object_foundGif_param_w_type_int' => 'Width', 'object_foundGif_param_h_type_int' => 'Height', 'object_foundGifCached' => 'Found gif cached', 'object_foundGifCached_param_url_type_string' => 'URL', 'object_foundGifCached_param_photo_type_Photo' => 'Photo', 'object_foundGifCached_param_document_type_Document' => 'Document', 'object_messages.foundGifs' => 'Found gifs', 'object_messages.foundGifs_param_next_offset_type_int' => 'Next offset', 'object_messages.foundGifs_param_results_type_Vector t' => 'Results', 'object_messages.savedGifsNotModified' => 'Saved gifs not modified', 'object_messages.savedGifs' => 'Saved gifs', 'object_messages.savedGifs_param_hash_type_int' => 'Hash', 'object_messages.savedGifs_param_gifs_type_Vector t' => 'Gifs', 'object_inputBotInlineMessageMediaAuto' => 'Bot inline message media auto', 'object_inputBotInlineMessageMediaAuto_param_message_type_string' => 'Message', 'object_inputBotInlineMessageMediaAuto_param_entities_type_Vector t' => 'Entities', 'object_inputBotInlineMessageMediaAuto_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageText' => 'Bot inline message text', 'object_inputBotInlineMessageText_param_no_webpage_type_true' => 'No webpage?', 'object_inputBotInlineMessageText_param_message_type_string' => 'Message', 'object_inputBotInlineMessageText_param_entities_type_Vector t' => 'Entities', 'object_inputBotInlineMessageText_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageMediaGeo' => 'Bot inline message media geo', 'object_inputBotInlineMessageMediaGeo_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputBotInlineMessageMediaGeo_param_period_type_int' => 'Period', 'object_inputBotInlineMessageMediaGeo_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageMediaVenue' => 'Bot inline message media venue', 'object_inputBotInlineMessageMediaVenue_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputBotInlineMessageMediaVenue_param_title_type_string' => 'Title', 'object_inputBotInlineMessageMediaVenue_param_address_type_string' => 'Address', 'object_inputBotInlineMessageMediaVenue_param_provider_type_string' => 'Provider', 'object_inputBotInlineMessageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_inputBotInlineMessageMediaVenue_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageMediaContact' => 'Bot inline message media contact', 'object_inputBotInlineMessageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_inputBotInlineMessageMediaContact_param_first_name_type_string' => 'First name', 'object_inputBotInlineMessageMediaContact_param_last_name_type_string' => 'Last name', 'object_inputBotInlineMessageMediaContact_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineMessageGame' => 'Bot inline message game', 'object_inputBotInlineMessageGame_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_inputBotInlineResult' => 'Bot inline result', 'object_inputBotInlineResult_param_id_type_string' => 'ID', 'object_inputBotInlineResult_param_type_type_string' => 'Type', 'object_inputBotInlineResult_param_title_type_string' => 'Title', 'object_inputBotInlineResult_param_description_type_string' => 'Description', 'object_inputBotInlineResult_param_url_type_string' => 'URL', 'object_inputBotInlineResult_param_thumb_url_type_string' => 'Thumbnail URL', 'object_inputBotInlineResult_param_content_url_type_string' => 'Content URL', 'object_inputBotInlineResult_param_content_type_type_string' => 'Content type', 'object_inputBotInlineResult_param_w_type_int' => 'Width', 'object_inputBotInlineResult_param_h_type_int' => 'Height', 'object_inputBotInlineResult_param_duration_type_int' => 'Duration', 'object_inputBotInlineResult_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_inputBotInlineResultPhoto' => 'Bot inline result photo', 'object_inputBotInlineResultPhoto_param_id_type_string' => 'ID', 'object_inputBotInlineResultPhoto_param_type_type_string' => 'Type', 'object_inputBotInlineResultPhoto_param_photo_type_InputPhoto' => 'Photo', 'object_inputBotInlineResultPhoto_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_inputBotInlineResultDocument' => 'Bot inline result document', 'object_inputBotInlineResultDocument_param_id_type_string' => 'ID', 'object_inputBotInlineResultDocument_param_type_type_string' => 'Type', 'object_inputBotInlineResultDocument_param_title_type_string' => 'Title', 'object_inputBotInlineResultDocument_param_description_type_string' => 'Description', 'object_inputBotInlineResultDocument_param_document_type_InputDocument' => 'Document', 'object_inputBotInlineResultDocument_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_inputBotInlineResultGame' => 'Bot inline result game', 'object_inputBotInlineResultGame_param_id_type_string' => 'ID', 'object_inputBotInlineResultGame_param_short_name_type_string' => 'Short name', 'object_inputBotInlineResultGame_param_send_message_type_InputBotInlineMessage' => 'Message to send', 'object_botInlineMessageMediaAuto' => 'Bot inline message media auto', 'object_botInlineMessageMediaAuto_param_message_type_string' => 'Message', 'object_botInlineMessageMediaAuto_param_entities_type_Vector t' => 'Entities', 'object_botInlineMessageMediaAuto_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageText' => 'Bot inline message text', 'object_botInlineMessageText_param_no_webpage_type_true' => 'No webpage?', 'object_botInlineMessageText_param_message_type_string' => 'Message', 'object_botInlineMessageText_param_entities_type_Vector t' => 'Entities', 'object_botInlineMessageText_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageMediaGeo' => 'Bot inline message media geo', 'object_botInlineMessageMediaGeo_param_geo_type_GeoPoint' => 'Geo', 'object_botInlineMessageMediaGeo_param_period_type_int' => 'Period', 'object_botInlineMessageMediaGeo_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageMediaVenue' => 'Bot inline message media venue', 'object_botInlineMessageMediaVenue_param_geo_type_GeoPoint' => 'Geo', 'object_botInlineMessageMediaVenue_param_title_type_string' => 'Title', 'object_botInlineMessageMediaVenue_param_address_type_string' => 'Address', 'object_botInlineMessageMediaVenue_param_provider_type_string' => 'Provider', 'object_botInlineMessageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_botInlineMessageMediaVenue_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineMessageMediaContact' => 'Bot inline message media contact', 'object_botInlineMessageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_botInlineMessageMediaContact_param_first_name_type_string' => 'First name', 'object_botInlineMessageMediaContact_param_last_name_type_string' => 'Last name', 'object_botInlineMessageMediaContact_param_reply_markup_type_ReplyMarkup' => 'Reply markup', 'object_botInlineResult' => 'Bot inline result', 'object_botInlineResult_param_id_type_string' => 'ID', 'object_botInlineResult_param_type_type_string' => 'Type', 'object_botInlineResult_param_title_type_string' => 'Title', 'object_botInlineResult_param_description_type_string' => 'Description', 'object_botInlineResult_param_url_type_string' => 'URL', 'object_botInlineResult_param_thumb_url_type_string' => 'Thumbnail URL', 'object_botInlineResult_param_content_url_type_string' => 'Content URL', 'object_botInlineResult_param_content_type_type_string' => 'Content type', 'object_botInlineResult_param_w_type_int' => 'Width', 'object_botInlineResult_param_h_type_int' => 'Height', 'object_botInlineResult_param_duration_type_int' => 'Duration', 'object_botInlineResult_param_send_message_type_BotInlineMessage' => 'Message to send', 'object_botInlineMediaResult' => 'Bot inline media result', 'object_botInlineMediaResult_param_id_type_string' => 'ID', 'object_botInlineMediaResult_param_type_type_string' => 'Type', 'object_botInlineMediaResult_param_photo_type_Photo' => 'Photo', 'object_botInlineMediaResult_param_document_type_Document' => 'Document', 'object_botInlineMediaResult_param_title_type_string' => 'Title', 'object_botInlineMediaResult_param_description_type_string' => 'Description', 'object_botInlineMediaResult_param_send_message_type_BotInlineMessage' => 'Send message', 'object_messages.botResults' => 'Bot results', 'object_messages.botResults_param_gallery_type_true' => 'Gallery?', 'object_messages.botResults_param_query_id_type_long' => 'Query ID', 'object_messages.botResults_param_next_offset_type_string' => 'Next offset', 'object_messages.botResults_param_switch_pm_type_InlineBotSwitchPM' => 'Switch pm', 'object_messages.botResults_param_results_type_Vector t' => 'Results', 'object_messages.botResults_param_cache_time_type_int' => 'Cache time', 'object_messages.botResults_param_users_type_Vector t' => 'Users', 'object_exportedMessageLink' => 'Exported message link', 'object_exportedMessageLink_param_link_type_string' => 'Link', 'object_exportedMessageLink_param_html_type_string' => 'Html', 'object_messageFwdHeader' => 'Forwarded message info', 'object_messageFwdHeader_param_from_id_type_int' => 'From ID', 'object_messageFwdHeader_param_date_type_int' => 'Date', 'object_messageFwdHeader_param_channel_id_type_int' => 'Channel ID', 'object_messageFwdHeader_param_channel_post_type_int' => 'Channel post', 'object_messageFwdHeader_param_post_author_type_string' => 'Post author', 'object_messageFwdHeader_param_saved_from_peer_type_Peer' => 'Saved from peer', 'object_messageFwdHeader_param_saved_from_msg_id_type_int' => 'Saved from msg ID', 'object_auth.codeTypeSms' => 'Auth code type: SMS', 'object_auth.codeTypeCall' => 'Auth code type: call', 'object_auth.codeTypeFlashCall' => 'Auth code type: flash call', 'object_auth.sentCodeTypeApp' => 'Sent code type app', 'object_auth.sentCodeTypeApp_param_length_type_int' => 'Length', 'object_auth.sentCodeTypeSms' => 'Sent code type sms', 'object_auth.sentCodeTypeSms_param_length_type_int' => 'Length', 'object_auth.sentCodeTypeCall' => 'Sent code type call', 'object_auth.sentCodeTypeCall_param_length_type_int' => 'Length', 'object_auth.sentCodeTypeFlashCall' => 'Sent code type flash call', 'object_auth.sentCodeTypeFlashCall_param_pattern_type_string' => 'Pattern', 'object_messages.botCallbackAnswer' => 'Bot callback answer', 'object_messages.botCallbackAnswer_param_alert_type_true' => 'Alert?', 'object_messages.botCallbackAnswer_param_has_url_type_true' => 'Has URL?', 'object_messages.botCallbackAnswer_param_native_ui_type_true' => 'Native ui?', 'object_messages.botCallbackAnswer_param_message_type_string' => 'Message', 'object_messages.botCallbackAnswer_param_url_type_string' => 'URL', 'object_messages.botCallbackAnswer_param_cache_time_type_int' => 'Cache time', 'object_messages.messageEditData' => 'Message edit data', 'object_messages.messageEditData_param_caption_type_true' => 'Caption?', 'object_inputBotInlineMessageID' => 'Bot inline message ID', 'object_inputBotInlineMessageID_param_dc_id_type_int' => 'DC ID', 'object_inputBotInlineMessageID_param_id_type_long' => 'ID', 'object_inputBotInlineMessageID_param_access_hash_type_long' => 'Access hash', 'object_inlineBotSwitchPM' => 'Inline bot switch pm', 'object_inlineBotSwitchPM_param_text_type_string' => 'Text', 'object_inlineBotSwitchPM_param_start_param_type_string' => 'Start param', 'object_messages.peerDialogs' => 'Peer dialogs', 'object_messages.peerDialogs_param_dialogs_type_Vector t' => 'Dialogs', 'object_messages.peerDialogs_param_messages_type_Vector t' => 'Messages', 'object_messages.peerDialogs_param_chats_type_Vector t' => 'Chats', 'object_messages.peerDialogs_param_users_type_Vector t' => 'Users', 'object_messages.peerDialogs_param_state_type_updates.State' => 'State', 'object_topPeer' => 'Top peer', 'object_topPeer_param_peer_type_Peer' => 'Peer', 'object_topPeer_param_rating_type_double' => 'Rating', 'object_topPeerCategoryBotsPM' => 'Top peer category bots pm', 'object_topPeerCategoryBotsInline' => 'Top peer category bots inline', 'object_topPeerCategoryCorrespondents' => 'Top peer category correspondents', 'object_topPeerCategoryGroups' => 'Top peer category groups', 'object_topPeerCategoryChannels' => 'Top peer category channels', 'object_topPeerCategoryPhoneCalls' => 'Top peer category phone calls', 'object_topPeerCategoryPeers' => 'Top peer category peers', 'object_topPeerCategoryPeers_param_category_type_TopPeerCategory' => 'Category', 'object_topPeerCategoryPeers_param_count_type_int' => 'Count', 'object_topPeerCategoryPeers_param_peers_type_Vector t' => 'Peers', 'object_contacts.topPeersNotModified' => 'Top peers not modified', 'object_contacts.topPeers' => 'Top peers', 'object_contacts.topPeers_param_categories_type_Vector t' => 'Categories', 'object_contacts.topPeers_param_chats_type_Vector t' => 'Chats', 'object_contacts.topPeers_param_users_type_Vector t' => 'Users', 'object_draftMessageEmpty' => 'Empty draft message', 'object_draftMessage' => 'Draft message', 'object_draftMessage_param_no_webpage_type_true' => 'No webpage?', 'object_draftMessage_param_reply_to_msg_id_type_int' => 'Reply to msg ID', 'object_draftMessage_param_message_type_string' => 'Message', 'object_draftMessage_param_entities_type_Vector t' => 'Entities', 'object_draftMessage_param_date_type_int' => 'Date', 'object_messages.featuredStickersNotModified' => 'Featured stickers not modified', 'object_messages.featuredStickers' => 'Featured stickers', 'object_messages.featuredStickers_param_hash_type_int' => 'Hash', 'object_messages.featuredStickers_param_sets_type_Vector t' => 'Sets', 'object_messages.featuredStickers_param_unread_type_Vector t' => 'Unread', 'object_messages.recentStickersNotModified' => 'Recent stickers not modified', 'object_messages.recentStickers' => 'Recent stickers', 'object_messages.recentStickers_param_hash_type_int' => 'Hash', 'object_messages.recentStickers_param_stickers_type_Vector t' => 'Stickers', 'object_messages.archivedStickers' => 'Archived stickers', 'object_messages.archivedStickers_param_count_type_int' => 'Count', 'object_messages.archivedStickers_param_sets_type_Vector t' => 'Sets', 'object_messages.stickerSetInstallResultSuccess' => 'Sticker set install result success', 'object_messages.stickerSetInstallResultArchive' => 'Sticker set install result archive', 'object_messages.stickerSetInstallResultArchive_param_sets_type_Vector t' => 'Sets', 'object_stickerSetCovered' => 'Sticker set covered', 'object_stickerSetCovered_param_set_type_StickerSet' => 'Set', 'object_stickerSetCovered_param_cover_type_Document' => 'Cover', 'object_stickerSetMultiCovered' => 'Sticker set multi covered', 'object_stickerSetMultiCovered_param_set_type_StickerSet' => 'Set', 'object_stickerSetMultiCovered_param_covers_type_Vector t' => 'Covers', 'object_maskCoords' => 'Mask coords', 'object_maskCoords_param_n_type_int' => 'N', 'object_maskCoords_param_x_type_double' => 'X', 'object_maskCoords_param_y_type_double' => 'Y', 'object_maskCoords_param_zoom_type_double' => 'Zoom', 'object_inputStickeredMediaPhoto' => 'Stickered media photo', 'object_inputStickeredMediaPhoto_param_id_type_InputPhoto' => 'ID', 'object_inputStickeredMediaDocument' => 'Stickered media document', 'object_inputStickeredMediaDocument_param_id_type_InputDocument' => 'ID', 'object_game' => 'Game', 'object_game_param_id_type_long' => 'ID', 'object_game_param_access_hash_type_long' => 'Access hash', 'object_game_param_short_name_type_string' => 'Short name', 'object_game_param_title_type_string' => 'Title', 'object_game_param_description_type_string' => 'Description', 'object_game_param_photo_type_Photo' => 'Photo', 'object_game_param_document_type_Document' => 'Document', 'object_inputGameID' => 'Game ID', 'object_inputGameID_param_id_type_long' => 'ID', 'object_inputGameID_param_access_hash_type_long' => 'Access hash', 'object_inputGameShortName' => 'Game short name', 'object_inputGameShortName_param_bot_id_type_InputUser' => 'Bot ID', 'object_inputGameShortName_param_short_name_type_string' => 'Short name', 'object_highScore' => 'High score', 'object_highScore_param_pos_type_int' => 'Pos', 'object_highScore_param_user_id_type_int' => 'User ID', 'object_highScore_param_score_type_int' => 'Score', 'object_messages.highScores' => 'High scores', 'object_messages.highScores_param_scores_type_Vector t' => 'Scores', 'object_messages.highScores_param_users_type_Vector t' => 'Users', 'object_textEmpty' => 'Empty text', 'object_textPlain' => 'Text plain', 'object_textPlain_param_text_type_string' => 'Text', 'object_textBold' => 'Text bold', 'object_textBold_param_text_type_RichText' => 'Text', 'object_textItalic' => 'Text italic', 'object_textItalic_param_text_type_RichText' => 'Text', 'object_textUnderline' => 'Text underline', 'object_textUnderline_param_text_type_RichText' => 'Text', 'object_textStrike' => 'Text strike', 'object_textStrike_param_text_type_RichText' => 'Text', 'object_textFixed' => 'Text fixed', 'object_textFixed_param_text_type_RichText' => 'Text', 'object_textUrl' => 'Text URL', 'object_textUrl_param_text_type_RichText' => 'Text', 'object_textUrl_param_url_type_string' => 'URL', 'object_textUrl_param_webpage_id_type_long' => 'Webpage ID', 'object_textEmail' => 'Text email', 'object_textEmail_param_text_type_RichText' => 'Text', 'object_textEmail_param_email_type_string' => 'Email', 'object_textConcat' => 'Text concat', 'object_textConcat_param_texts_type_Vector t' => 'Texts', 'object_pageBlockUnsupported' => 'Page block unsupported', 'object_pageBlockTitle' => 'Page block title', 'object_pageBlockTitle_param_text_type_RichText' => 'Text', 'object_pageBlockSubtitle' => 'Page block subtitle', 'object_pageBlockSubtitle_param_text_type_RichText' => 'Text', 'object_pageBlockAuthorDate' => 'Page block author date', 'object_pageBlockAuthorDate_param_author_type_RichText' => 'Author', 'object_pageBlockAuthorDate_param_published_date_type_int' => 'Published date', 'object_pageBlockHeader' => 'Page block header', 'object_pageBlockHeader_param_text_type_RichText' => 'Text', 'object_pageBlockSubheader' => 'Page block subheader', 'object_pageBlockSubheader_param_text_type_RichText' => 'Text', 'object_pageBlockFooter' => 'Page block footer', 'object_pageBlockFooter_param_text_type_RichText' => 'Text', 'object_pageBlockList' => 'Page block list', 'object_pageBlockList_param_ordered_type_Bool' => 'Ordered?', 'object_pageBlockList_param_items_type_Vector t' => 'Items', 'object_pageBlockBlockquote' => 'Page block blockquote', 'object_pageBlockBlockquote_param_text_type_RichText' => 'Text', 'object_pageBlockBlockquote_param_caption_type_RichText' => 'Caption', 'object_pageBlockPullquote' => 'Page block pullquote', 'object_pageBlockPullquote_param_text_type_RichText' => 'Text', 'object_pageBlockPullquote_param_caption_type_RichText' => 'Caption', 'object_pageBlockPhoto' => 'Page block photo', 'object_pageBlockPhoto_param_photo_id_type_long' => 'Photo ID', 'object_pageBlockPhoto_param_caption_type_RichText' => 'Caption', 'object_pageBlockVideo' => 'Page block video', 'object_pageBlockVideo_param_autoplay_type_true' => 'Autoplay?', 'object_pageBlockVideo_param_loop_type_true' => 'Loop?', 'object_pageBlockVideo_param_video_id_type_long' => 'Video ID', 'object_pageBlockVideo_param_caption_type_RichText' => 'Caption', 'object_pageBlockEmbed' => 'Page block embed', 'object_pageBlockEmbed_param_full_width_type_true' => 'Full width?', 'object_pageBlockEmbed_param_allow_scrolling_type_true' => 'Allow scrolling?', 'object_pageBlockEmbed_param_url_type_string' => 'URL', 'object_pageBlockEmbed_param_html_type_string' => 'Html', 'object_pageBlockEmbed_param_poster_photo_id_type_long' => 'Poster photo ID', 'object_pageBlockEmbed_param_w_type_int' => 'Width', 'object_pageBlockEmbed_param_h_type_int' => 'Height', 'object_pageBlockEmbed_param_caption_type_RichText' => 'Caption', 'object_pageBlockEmbedPost' => 'Page block embed post', 'object_pageBlockEmbedPost_param_url_type_string' => 'URL', 'object_pageBlockEmbedPost_param_webpage_id_type_long' => 'Webpage ID', 'object_pageBlockEmbedPost_param_author_photo_id_type_long' => 'Author photo ID', 'object_pageBlockEmbedPost_param_author_type_string' => 'Author', 'object_pageBlockEmbedPost_param_date_type_int' => 'Date', 'object_pageBlockEmbedPost_param_blocks_type_Vector t' => 'Blocks', 'object_pageBlockEmbedPost_param_caption_type_RichText' => 'Caption', 'object_pageBlockCollage' => 'Page block collage', 'object_pageBlockCollage_param_items_type_Vector t' => 'Items', 'object_pageBlockCollage_param_caption_type_RichText' => 'Caption', 'object_pageBlockSlideshow' => 'Page block slideshow', 'object_pageBlockSlideshow_param_items_type_Vector t' => 'Items', 'object_pageBlockSlideshow_param_caption_type_RichText' => 'Caption', 'object_pageBlockChannel' => 'Page block channel', 'object_pageBlockChannel_param_channel_type_Chat' => 'Channel', 'object_pageBlockAudio' => 'Page block audio', 'object_pageBlockAudio_param_audio_id_type_long' => 'Audio ID', 'object_pageBlockAudio_param_caption_type_RichText' => 'Caption', 'object_pagePart' => 'Page part', 'object_pagePart_param_blocks_type_Vector t' => 'Blocks', 'object_pagePart_param_photos_type_Vector t' => 'Photos', 'object_pagePart_param_documents_type_Vector t' => 'Documents', 'object_pageFull' => 'Page full', 'object_pageFull_param_blocks_type_Vector t' => 'Blocks', 'object_pageFull_param_photos_type_Vector t' => 'Photos', 'object_pageFull_param_documents_type_Vector t' => 'Documents', 'object_phoneCallDiscardReasonMissed' => 'Phone call discard reason missed', 'object_phoneCallDiscardReasonDisconnect' => 'Phone call discard reason disconnect', 'object_phoneCallDiscardReasonHangup' => 'Phone call discard reason hangup', 'object_phoneCallDiscardReasonBusy' => 'Phone call discard reason busy', 'object_dataJSON' => 'Data json', 'object_dataJSON_param_data_type_string' => 'Data', 'object_labeledPrice' => 'Labeled price', 'object_labeledPrice_param_label_type_string' => 'Label', 'object_labeledPrice_param_amount_type_long' => 'Amount', 'object_invoice' => 'Invoice', 'object_invoice_param_test_type_true' => 'Test?', 'object_invoice_param_name_requested_type_true' => 'Name requested?', 'object_invoice_param_phone_requested_type_true' => 'Phone requested?', 'object_invoice_param_email_requested_type_true' => 'Email requested?', 'object_invoice_param_shipping_address_requested_type_true' => 'Shipping address requested?', 'object_invoice_param_flexible_type_true' => 'Flexible?', 'object_invoice_param_phone_to_provider_type_true' => 'Phone to provider?', 'object_invoice_param_email_to_provider_type_true' => 'Email to provider?', 'object_invoice_param_currency_type_string' => 'Currency', 'object_invoice_param_prices_type_Vector t' => 'Prices', 'object_paymentCharge' => 'Payment charge', 'object_paymentCharge_param_id_type_string' => 'ID', 'object_paymentCharge_param_provider_charge_id_type_string' => 'Provider charge ID', 'object_postAddress' => 'Post address', 'object_postAddress_param_street_line1_type_string' => 'Street line1', 'object_postAddress_param_street_line2_type_string' => 'Street line2', 'object_postAddress_param_city_type_string' => 'City', 'object_postAddress_param_state_type_string' => 'State', 'object_postAddress_param_country_iso2_type_string' => 'Country iso2', 'object_postAddress_param_post_code_type_string' => 'Post code', 'object_paymentRequestedInfo' => 'Payment requested info', 'object_paymentRequestedInfo_param_name_type_string' => 'Name', 'object_paymentRequestedInfo_param_phone_type_string' => 'Phone', 'object_paymentRequestedInfo_param_email_type_string' => 'Email', 'object_paymentRequestedInfo_param_shipping_address_type_PostAddress' => 'Shipping address', 'object_paymentSavedCredentialsCard' => 'Payment saved credentials card', 'object_paymentSavedCredentialsCard_param_id_type_string' => 'ID', 'object_paymentSavedCredentialsCard_param_title_type_string' => 'Title', 'object_webDocument' => 'Web document', 'object_webDocument_param_url_type_string' => 'URL', 'object_webDocument_param_access_hash_type_long' => 'Access hash', 'object_webDocument_param_size_type_int' => 'Size', 'object_webDocument_param_mime_type_type_string' => 'Mime type', 'object_webDocument_param_attributes_type_Vector t' => 'Attributes', 'object_webDocument_param_dc_id_type_int' => 'DC ID', 'object_inputWebDocument' => 'Web document', 'object_inputWebDocument_param_url_type_string' => 'URL', 'object_inputWebDocument_param_size_type_int' => 'Size', 'object_inputWebDocument_param_mime_type_type_string' => 'Mime type', 'object_inputWebDocument_param_attributes_type_Vector t' => 'Attributes', 'object_inputWebFileLocation' => 'Web file location', 'object_inputWebFileLocation_param_url_type_string' => 'URL', 'object_inputWebFileLocation_param_access_hash_type_long' => 'Access hash', 'object_upload.webFile' => 'Web file', 'object_upload.webFile_param_size_type_int' => 'Size', 'object_upload.webFile_param_mime_type_type_string' => 'Mime type', 'object_upload.webFile_param_file_type_type_storage.FileType' => 'File type', 'object_upload.webFile_param_mtime_type_int' => 'Mtime', 'object_upload.webFile_param_bytes_type_bytes' => 'Bytes', 'object_payments.paymentForm' => 'Payment form', 'object_payments.paymentForm_param_can_save_credentials_type_true' => 'Can save credentials?', 'object_payments.paymentForm_param_password_missing_type_true' => 'Password missing?', 'object_payments.paymentForm_param_bot_id_type_int' => 'Bot ID', 'object_payments.paymentForm_param_invoice_type_Invoice' => 'Invoice', 'object_payments.paymentForm_param_provider_id_type_int' => 'Provider ID', 'object_payments.paymentForm_param_url_type_string' => 'URL', 'object_payments.paymentForm_param_native_provider_type_string' => 'Native provider', 'object_payments.paymentForm_param_native_params_type_DataJSON' => 'Native params', 'object_payments.paymentForm_param_saved_info_type_PaymentRequestedInfo' => 'Saved info', 'object_payments.paymentForm_param_saved_credentials_type_PaymentSavedCredentials' => 'Saved credentials', 'object_payments.paymentForm_param_users_type_Vector t' => 'Users', 'object_payments.validatedRequestedInfo' => 'Validated requested info', 'object_payments.validatedRequestedInfo_param_id_type_string' => 'ID', 'object_payments.validatedRequestedInfo_param_shipping_options_type_Vector t' => 'Shipping options', 'object_payments.paymentResult' => 'Payment result', 'object_payments.paymentResult_param_updates_type_Updates' => 'Updates', 'object_payments.paymentVerficationNeeded' => 'Payment verfication needed', 'object_payments.paymentVerficationNeeded_param_url_type_string' => 'URL', 'object_payments.paymentReceipt' => 'Payment receipt', 'object_payments.paymentReceipt_param_date_type_int' => 'Date', 'object_payments.paymentReceipt_param_bot_id_type_int' => 'Bot ID', 'object_payments.paymentReceipt_param_invoice_type_Invoice' => 'Invoice', 'object_payments.paymentReceipt_param_provider_id_type_int' => 'Provider ID', 'object_payments.paymentReceipt_param_info_type_PaymentRequestedInfo' => 'Info', 'object_payments.paymentReceipt_param_shipping_type_ShippingOption' => 'Shipping', 'object_payments.paymentReceipt_param_currency_type_string' => 'Currency', 'object_payments.paymentReceipt_param_total_amount_type_long' => 'Total amount', 'object_payments.paymentReceipt_param_credentials_title_type_string' => 'Credentials title', 'object_payments.paymentReceipt_param_users_type_Vector t' => 'Users', 'object_payments.savedInfo' => 'Saved info', 'object_payments.savedInfo_param_has_saved_credentials_type_true' => 'Has saved credentials?', 'object_payments.savedInfo_param_saved_info_type_PaymentRequestedInfo' => 'Saved info', 'object_inputPaymentCredentialsSaved' => 'Payment credentials saved', 'object_inputPaymentCredentialsSaved_param_id_type_string' => 'ID', 'object_inputPaymentCredentialsSaved_param_tmp_password_type_bytes' => 'Tmp password', 'object_inputPaymentCredentials' => 'Payment credentials', 'object_inputPaymentCredentials_param_save_type_true' => 'Save?', 'object_inputPaymentCredentials_param_data_type_DataJSON' => 'Data', 'object_inputPaymentCredentialsApplePay' => 'Payment credentials apple pay', 'object_inputPaymentCredentialsApplePay_param_payment_data_type_DataJSON' => 'Payment data', 'object_inputPaymentCredentialsAndroidPay' => 'Payment credentials android pay', 'object_inputPaymentCredentialsAndroidPay_param_payment_token_type_DataJSON' => 'Payment token', 'object_inputPaymentCredentialsAndroidPay_param_google_transaction_id_type_string' => 'Google transaction ID', 'object_account.tmpPassword' => 'Tmp password', 'object_account.tmpPassword_param_tmp_password_type_bytes' => 'Tmp password', 'object_account.tmpPassword_param_valid_until_type_int' => 'Valid until', 'object_shippingOption' => 'Shipping option', 'object_shippingOption_param_id_type_string' => 'ID', 'object_shippingOption_param_title_type_string' => 'Title', 'object_shippingOption_param_prices_type_Vector t' => 'Prices', 'object_inputStickerSetItem' => 'Sticker set item', 'object_inputStickerSetItem_param_document_type_InputDocument' => 'Document', 'object_inputStickerSetItem_param_emoji_type_string' => 'Emoji', 'object_inputStickerSetItem_param_mask_coords_type_MaskCoords' => 'Mask coords', 'object_inputPhoneCall' => 'Phone call', 'object_inputPhoneCall_param_id_type_long' => 'ID', 'object_inputPhoneCall_param_access_hash_type_long' => 'Access hash', 'object_phoneCallEmpty' => 'Empty phone call', 'object_phoneCallEmpty_param_id_type_long' => 'ID', 'object_phoneCallWaiting' => 'Phone call waiting', 'object_phoneCallWaiting_param_id_type_long' => 'ID', 'object_phoneCallWaiting_param_access_hash_type_long' => 'Access hash', 'object_phoneCallWaiting_param_date_type_int' => 'Date', 'object_phoneCallWaiting_param_admin_id_type_int' => 'Admin ID', 'object_phoneCallWaiting_param_participant_id_type_int' => 'Participant ID', 'object_phoneCallWaiting_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCallWaiting_param_receive_date_type_int' => 'Receive date', 'object_phoneCallRequested' => 'Phone call requested', 'object_phoneCallRequested_param_id_type_long' => 'ID', 'object_phoneCallRequested_param_access_hash_type_long' => 'Access hash', 'object_phoneCallRequested_param_date_type_int' => 'Date', 'object_phoneCallRequested_param_admin_id_type_int' => 'Admin ID', 'object_phoneCallRequested_param_participant_id_type_int' => 'Participant ID', 'object_phoneCallRequested_param_g_a_hash_type_bytes' => 'G a hash', 'object_phoneCallRequested_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCallAccepted' => 'Phone call accepted', 'object_phoneCallAccepted_param_id_type_long' => 'ID', 'object_phoneCallAccepted_param_access_hash_type_long' => 'Access hash', 'object_phoneCallAccepted_param_date_type_int' => 'Date', 'object_phoneCallAccepted_param_admin_id_type_int' => 'Admin ID', 'object_phoneCallAccepted_param_participant_id_type_int' => 'Participant ID', 'object_phoneCallAccepted_param_g_b_type_bytes' => 'G b', 'object_phoneCallAccepted_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCall' => 'Phone call', 'object_phoneCall_param_id_type_long' => 'ID', 'object_phoneCall_param_access_hash_type_long' => 'Access hash', 'object_phoneCall_param_date_type_int' => 'Date', 'object_phoneCall_param_admin_id_type_int' => 'Admin ID', 'object_phoneCall_param_participant_id_type_int' => 'Participant ID', 'object_phoneCall_param_g_a_or_b_type_bytes' => 'G a or b', 'object_phoneCall_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_phoneCall_param_protocol_type_PhoneCallProtocol' => 'Protocol', 'object_phoneCall_param_connection_type_PhoneConnection' => 'Connection', 'object_phoneCall_param_alternative_connections_type_Vector t' => 'Alternative connections', 'object_phoneCall_param_start_date_type_int' => 'Start date', 'object_phoneCallDiscarded' => 'Phone call discarded', 'object_phoneCallDiscarded_param_need_rating_type_true' => 'Need rating?', 'object_phoneCallDiscarded_param_need_debug_type_true' => 'Need debug?', 'object_phoneCallDiscarded_param_id_type_long' => 'ID', 'object_phoneCallDiscarded_param_reason_type_PhoneCallDiscardReason' => 'Reason', 'object_phoneCallDiscarded_param_duration_type_int' => 'Duration', 'object_phoneConnection' => 'Phone connection', 'object_phoneConnection_param_id_type_long' => 'ID', 'object_phoneConnection_param_ip_type_string' => 'Ip', 'object_phoneConnection_param_ipv6_type_string' => 'Ipv6', 'object_phoneConnection_param_port_type_int' => 'Port', 'object_phoneConnection_param_peer_tag_type_bytes' => 'Peer tag', 'object_phoneCallProtocol' => 'Phone call protocol', 'object_phoneCallProtocol_param_udp_p2p_type_true' => 'Udp p2p?', 'object_phoneCallProtocol_param_udp_reflector_type_true' => 'Udp reflector?', 'object_phoneCallProtocol_param_min_layer_type_int' => 'Min layer', 'object_phoneCallProtocol_param_max_layer_type_int' => 'Max layer', 'object_phone.phoneCall' => 'Phone call', 'object_phone.phoneCall_param_phone_call_type_PhoneCall' => 'Phone call', 'object_phone.phoneCall_param_users_type_Vector t' => 'Users', 'object_upload.cdnFileReuploadNeeded' => 'Cdn file reupload needed', 'object_upload.cdnFileReuploadNeeded_param_request_token_type_bytes' => 'Request token', 'object_upload.cdnFile' => 'Cdn file', 'object_upload.cdnFile_param_bytes_type_bytes' => 'Bytes', 'object_cdnPublicKey' => 'Cdn public key', 'object_cdnPublicKey_param_dc_id_type_int' => 'DC ID', 'object_cdnPublicKey_param_public_key_type_string' => 'Public key', 'object_cdnConfig' => 'CDN configuration', 'object_cdnConfig_param_public_keys_type_Vector t' => 'Public keys', 'object_langPackString' => 'Lang pack string', 'object_langPackString_param_key_type_string' => 'Key', 'object_langPackString_param_value_type_string' => 'Value', 'object_langPackStringPluralized' => 'Lang pack string pluralized', 'object_langPackStringPluralized_param_key_type_string' => 'Key', 'object_langPackStringPluralized_param_zero_value_type_string' => 'Zero value', 'object_langPackStringPluralized_param_one_value_type_string' => 'One value', 'object_langPackStringPluralized_param_two_value_type_string' => 'Two value', 'object_langPackStringPluralized_param_few_value_type_string' => 'Few value', 'object_langPackStringPluralized_param_many_value_type_string' => 'Many value', 'object_langPackStringPluralized_param_other_value_type_string' => 'Other value', 'object_langPackStringDeleted' => 'Lang pack string deleted', 'object_langPackStringDeleted_param_key_type_string' => 'Key', 'object_langPackDifference' => 'Lang pack difference', 'object_langPackDifference_param_lang_code_type_string' => 'Lang code', 'object_langPackDifference_param_from_version_type_int' => 'From version', 'object_langPackDifference_param_version_type_int' => 'Version', 'object_langPackDifference_param_strings_type_Vector t' => 'Strings', 'object_langPackLanguage' => 'Lang pack language', 'object_langPackLanguage_param_name_type_string' => 'Name', 'object_langPackLanguage_param_native_name_type_string' => 'Native name', 'object_langPackLanguage_param_lang_code_type_string' => 'Lang code', 'object_channelAdminRights' => 'Admin rights', 'object_channelAdminRights_param_change_info_type_true' => 'Change info', 'object_channelAdminRights_param_post_messages_type_true' => 'Post messages', 'object_channelAdminRights_param_edit_messages_type_true' => 'Edit messages', 'object_channelAdminRights_param_delete_messages_type_true' => 'Delete messages', 'object_channelAdminRights_param_ban_users_type_true' => 'Ban users', 'object_channelAdminRights_param_invite_users_type_true' => 'Invite users', 'object_channelAdminRights_param_invite_link_type_true' => 'Generate an invite link', 'object_channelAdminRights_param_pin_messages_type_true' => 'Pin messages', 'object_channelAdminRights_param_add_admins_type_true' => 'Add other admins', 'object_channelBannedRights' => 'Banned user rights (when true, the user will NOT be able to do that thing)', 'object_channelBannedRights_param_view_messages_type_true' => 'Disallow viewing messages', 'object_channelBannedRights_param_send_messages_type_true' => 'Disallow sending messages', 'object_channelBannedRights_param_send_media_type_true' => 'Disallow sending media', 'object_channelBannedRights_param_send_stickers_type_true' => 'Disallow sending stickers', 'object_channelBannedRights_param_send_gifs_type_true' => 'Disallow sending gifs', 'object_channelBannedRights_param_send_games_type_true' => 'Disallow sending games', 'object_channelBannedRights_param_send_inline_type_true' => 'Disallow sending inline keyboards', 'object_channelBannedRights_param_embed_links_type_true' => 'Disallow embedding links', 'object_channelBannedRights_param_until_date_type_int' => 'Until date', 'object_channelAdminLogEventActionChangeTitle' => 'Change title', 'object_channelAdminLogEventActionChangeTitle_param_prev_value_type_string' => 'Previous value', 'object_channelAdminLogEventActionChangeTitle_param_new_value_type_string' => 'New value', 'object_channelAdminLogEventActionChangeAbout' => 'Change about text', 'object_channelAdminLogEventActionChangeAbout_param_prev_value_type_string' => 'Previous value', 'object_channelAdminLogEventActionChangeAbout_param_new_value_type_string' => 'New value', 'object_channelAdminLogEventActionChangeUsername' => 'Change username', 'object_channelAdminLogEventActionChangeUsername_param_prev_value_type_string' => 'Prev value', 'object_channelAdminLogEventActionChangeUsername_param_new_value_type_string' => 'New value', 'object_channelAdminLogEventActionChangePhoto' => 'Change photo', 'object_channelAdminLogEventActionChangePhoto_param_prev_photo_type_ChatPhoto' => 'Previous photo', 'object_channelAdminLogEventActionChangePhoto_param_new_photo_type_ChatPhoto' => 'New photo', 'object_channelAdminLogEventActionToggleInvites' => 'Invite setting toggled', 'object_channelAdminLogEventActionToggleInvites_param_new_value_type_Bool' => 'New value', 'object_channelAdminLogEventActionToggleSignatures' => 'Toggle channel signatures', 'object_channelAdminLogEventActionToggleSignatures_param_new_value_type_Bool' => 'New value?', 'object_channelAdminLogEventActionUpdatePinned' => 'Message pinned', 'object_channelAdminLogEventActionUpdatePinned_param_message_type_Message' => 'Message', 'object_channelAdminLogEventActionEditMessage' => 'Edit message', 'object_channelAdminLogEventActionEditMessage_param_prev_message_type_Message' => 'Prev message', 'object_channelAdminLogEventActionEditMessage_param_new_message_type_Message' => 'New message', 'object_channelAdminLogEventActionDeleteMessage' => 'Delete message', 'object_channelAdminLogEventActionDeleteMessage_param_message_type_Message' => 'Message', 'object_channelAdminLogEventActionParticipantJoin' => 'Joined participant', 'object_channelAdminLogEventActionParticipantLeave' => 'Left participant', 'object_channelAdminLogEventActionParticipantInvite' => 'Invite participant', 'object_channelAdminLogEventActionParticipantInvite_param_participant_type_ChannelParticipant' => 'Participant', 'object_channelAdminLogEventActionParticipantToggleBan' => 'User banned', 'object_channelAdminLogEventActionParticipantToggleBan_param_prev_participant_type_ChannelParticipant' => 'Prev participant', 'object_channelAdminLogEventActionParticipantToggleBan_param_new_participant_type_ChannelParticipant' => 'New participant', 'object_channelAdminLogEventActionParticipantToggleAdmin' => 'Admin toggled', 'object_channelAdminLogEventActionParticipantToggleAdmin_param_prev_participant_type_ChannelParticipant' => 'Prev participant', 'object_channelAdminLogEventActionParticipantToggleAdmin_param_new_participant_type_ChannelParticipant' => 'New participant', 'object_channelAdminLogEventActionChangeStickerSet' => 'Change stickerset', 'object_channelAdminLogEventActionChangeStickerSet_param_prev_stickerset_type_InputStickerSet' => 'Previous stickerset', 'object_channelAdminLogEventActionChangeStickerSet_param_new_stickerset_type_InputStickerSet' => 'New stickerset', 'object_channelAdminLogEventActionTogglePreHistoryHidden' => 'Previous history hidden', 'object_channelAdminLogEventActionTogglePreHistoryHidden_param_new_value_type_Bool' => 'New value', 'object_channelAdminLogEvent' => 'Channel admin log event', 'object_channelAdminLogEvent_param_id_type_long' => 'ID', 'object_channelAdminLogEvent_param_date_type_int' => 'Date', 'object_channelAdminLogEvent_param_user_id_type_int' => 'User ID', 'object_channelAdminLogEvent_param_action_type_ChannelAdminLogEventAction' => 'Action', 'object_channels.adminLogResults' => 'Admin log results', 'object_channels.adminLogResults_param_events_type_Vector t' => 'Events', 'object_channels.adminLogResults_param_chats_type_Vector t' => 'Chats', 'object_channels.adminLogResults_param_users_type_Vector t' => 'Users', 'object_channelAdminLogEventsFilter' => 'Event filter', 'object_channelAdminLogEventsFilter_param_join_type_true' => 'Join users events', 'object_channelAdminLogEventsFilter_param_leave_type_true' => 'Left users events', 'object_channelAdminLogEventsFilter_param_invite_type_true' => 'Invite users events', 'object_channelAdminLogEventsFilter_param_ban_type_true' => 'Ban events', 'object_channelAdminLogEventsFilter_param_unban_type_true' => 'Unban events', 'object_channelAdminLogEventsFilter_param_kick_type_true' => 'Kicked users events', 'object_channelAdminLogEventsFilter_param_unkick_type_true' => 'Unkick events', 'object_channelAdminLogEventsFilter_param_promote_type_true' => 'Admin promotion events', 'object_channelAdminLogEventsFilter_param_demote_type_true' => 'Demote admin events', 'object_channelAdminLogEventsFilter_param_info_type_true' => 'Change info events', 'object_channelAdminLogEventsFilter_param_settings_type_true' => 'Setting changes', 'object_channelAdminLogEventsFilter_param_pinned_type_true' => 'Pinned message events', 'object_channelAdminLogEventsFilter_param_edit_type_true' => 'Edit message events', 'object_channelAdminLogEventsFilter_param_delete_type_true' => 'Delete message events', 'object_popularContact' => 'Popular contact', 'object_popularContact_param_client_id_type_long' => 'Client ID', 'object_popularContact_param_importers_type_int' => 'Importers', 'object_cdnFileHash' => 'CDN file hash', 'object_cdnFileHash_param_offset_type_int' => 'Offset', 'object_cdnFileHash_param_limit_type_int' => 'Limit', 'object_cdnFileHash_param_hash_type_bytes' => 'Hash', 'object_messages.favedStickersNotModified' => 'Faved stickers not modified', 'object_messages.favedStickers' => 'Faved stickers', 'object_messages.favedStickers_param_hash_type_int' => 'Hash', 'object_messages.favedStickers_param_packs_type_Vector t' => 'Packs', 'object_messages.favedStickers_param_stickers_type_Vector t' => 'Stickers', 'object_recentMeUrlUnknown' => 'Recent me URL unknown', 'object_recentMeUrlUnknown_param_url_type_string' => 'URL', 'object_recentMeUrlUser' => 'Recent me URL user', 'object_recentMeUrlUser_param_url_type_string' => 'URL', 'object_recentMeUrlUser_param_user_id_type_int' => 'User ID', 'object_recentMeUrlChat' => 'Recent me URL chat', 'object_recentMeUrlChat_param_url_type_string' => 'URL', 'object_recentMeUrlChat_param_chat_id_type_int' => 'Chat ID', 'object_recentMeUrlChatInvite' => 'Recent me URL chat invite', 'object_recentMeUrlChatInvite_param_url_type_string' => 'URL', 'object_recentMeUrlChatInvite_param_chat_invite_type_ChatInvite' => 'Chat invite', 'object_recentMeUrlStickerSet' => 'Recent me URL sticker set', 'object_recentMeUrlStickerSet_param_url_type_string' => 'URL', 'object_recentMeUrlStickerSet_param_set_type_StickerSetCovered' => 'Set', 'object_help.recentMeUrls' => 'Recent me URLs', 'object_help.recentMeUrls_param_urls_type_Vector t' => 'URLs', 'object_help.recentMeUrls_param_chats_type_Vector t' => 'Chats', 'object_help.recentMeUrls_param_users_type_Vector t' => 'Users', 'object_inputSingleMedia' => 'Single media', 'object_inputSingleMedia_param_media_type_InputMedia' => 'Media', 'object_inputSingleMedia_param_message_type_string' => 'Message', 'object_inputSingleMedia_param_entities_type_Vector t' => 'Entities', 'object_webAuthorization' => 'Web authorization', 'object_webAuthorization_param_hash_type_long' => 'Hash', 'object_webAuthorization_param_bot_id_type_int' => 'Bot ID', 'object_webAuthorization_param_domain_type_string' => 'Domain', 'object_webAuthorization_param_browser_type_string' => 'Browser', 'object_webAuthorization_param_platform_type_string' => 'Platform', 'object_webAuthorization_param_date_created_type_int' => 'Date created', 'object_webAuthorization_param_date_active_type_int' => 'Date active', 'object_webAuthorization_param_ip_type_string' => 'Ip', 'object_webAuthorization_param_region_type_string' => 'Region', 'object_account.webAuthorizations' => 'Telegram login authorizations', 'object_account.webAuthorizations_param_authorizations_type_Vector t' => 'Authorizations', 'object_account.webAuthorizations_param_users_type_Vector t' => 'Users', 'object_inputMessageID' => 'Message ID', 'object_inputMessageID_param_id_type_int' => 'ID', 'object_inputMessageReplyTo' => 'Message reply to', 'object_inputMessageReplyTo_param_id_type_int' => 'ID', 'object_inputMessagePinned' => 'Message pinned', 'object_decryptedDataBlock' => 'Decrypted data block', 'object_decryptedDataBlock_param_voice_call_id_type_int128' => 'Voice call ID', 'object_decryptedDataBlock_param_in_seq_no_type_int' => 'In seq no', 'object_decryptedDataBlock_param_out_seq_no_type_int' => 'Out seq no', 'object_decryptedDataBlock_param_recent_received_mask_type_int' => 'Recent received mask', 'object_decryptedDataBlock_param_proto_type_int' => 'Proto', 'object_decryptedDataBlock_param_extra_type_string' => 'Extra', 'object_decryptedDataBlock_param_raw_data_type_string' => 'Raw data', 'object_simpleDataBlock' => 'Simple data block', 'object_simpleDataBlock_param_raw_data_type_string' => 'Raw data', 'object_decryptedMessage' => 'Decrypted message', 'object_decryptedMessage_param_message_type_string' => 'Message', 'object_decryptedMessage_param_media_type_DecryptedMessageMedia' => 'Media', 'object_decryptedMessageService' => 'Decrypted message service', 'object_decryptedMessageService_param_action_type_DecryptedMessageAction' => 'Action', 'object_decryptedMessageMediaEmpty' => 'Empty decrypted message media', 'object_decryptedMessageMediaPhoto' => 'Decrypted message media photo', 'object_decryptedMessageMediaPhoto_param_thumb_type_bytes' => 'Thumbnail', 'object_decryptedMessageMediaPhoto_param_thumb_w_type_int' => 'Thumbnail width', 'object_decryptedMessageMediaPhoto_param_thumb_h_type_int' => 'Thumbnail height', 'object_decryptedMessageMediaPhoto_param_w_type_int' => 'Width', 'object_decryptedMessageMediaPhoto_param_h_type_int' => 'Height', 'object_decryptedMessageMediaPhoto_param_size_type_int' => 'Size', 'object_decryptedMessageMediaPhoto_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaPhoto_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageMediaVideo' => 'Decrypted message media video', 'object_decryptedMessageMediaVideo_param_thumb_type_bytes' => 'Thumbnail', 'object_decryptedMessageMediaVideo_param_thumb_w_type_int' => 'Thumbnail width', 'object_decryptedMessageMediaVideo_param_thumb_h_type_int' => 'Thumbnail height', 'object_decryptedMessageMediaVideo_param_duration_type_int' => 'Duration', 'object_decryptedMessageMediaVideo_param_w_type_int' => 'Width', 'object_decryptedMessageMediaVideo_param_h_type_int' => 'Height', 'object_decryptedMessageMediaVideo_param_size_type_int' => 'Size', 'object_decryptedMessageMediaVideo_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaVideo_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageMediaGeoPoint' => 'Decrypted message media geo point', 'object_decryptedMessageMediaGeoPoint_param_lat_type_double' => 'Lat', 'object_decryptedMessageMediaGeoPoint_param_long_type_double' => 'Long', 'object_decryptedMessageMediaContact' => 'Decrypted message media contact', 'object_decryptedMessageMediaContact_param_phone_number_type_string' => 'Phone number', 'object_decryptedMessageMediaContact_param_first_name_type_string' => 'First name', 'object_decryptedMessageMediaContact_param_last_name_type_string' => 'Last name', 'object_decryptedMessageMediaContact_param_user_id_type_int' => 'User ID', 'object_decryptedMessageActionSetMessageTTL' => 'Decrypted message action set message ttl', 'object_decryptedMessageActionSetMessageTTL_param_ttl_seconds_type_int' => 'Ttl seconds', 'object_decryptedMessageMediaDocument' => 'Decrypted message media document', 'object_decryptedMessageMediaDocument_param_thumb_type_bytes' => 'Thumbnail', 'object_decryptedMessageMediaDocument_param_thumb_w_type_int' => 'Thumbnail w', 'object_decryptedMessageMediaDocument_param_thumb_h_type_int' => 'Thumbnail h', 'object_decryptedMessageMediaDocument_param_file_name_type_string' => 'File name', 'object_decryptedMessageMediaDocument_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageMediaDocument_param_size_type_int' => 'Size', 'object_decryptedMessageMediaDocument_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaDocument_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageMediaAudio' => 'Decrypted message media audio', 'object_decryptedMessageMediaAudio_param_duration_type_int' => 'Duration', 'object_decryptedMessageMediaAudio_param_size_type_int' => 'Size', 'object_decryptedMessageMediaAudio_param_key_type_bytes' => 'Key', 'object_decryptedMessageMediaAudio_param_iv_type_bytes' => 'Iv', 'object_decryptedMessageActionReadMessages' => 'Decrypted message action read messages', 'object_decryptedMessageActionReadMessages_param_random_ids_type_Vector t' => 'Random IDs', 'object_decryptedMessageActionDeleteMessages' => 'Decrypted message action delete messages', 'object_decryptedMessageActionDeleteMessages_param_random_ids_type_Vector t' => 'Random IDs', 'object_decryptedMessageActionScreenshotMessages' => 'Decrypted message action screenshot messages', 'object_decryptedMessageActionScreenshotMessages_param_random_ids_type_Vector t' => 'Random IDs', 'object_decryptedMessageActionFlushHistory' => 'Decrypted message action flush history', 'object_decryptedMessage_param_ttl_type_int' => 'Ttl', 'object_decryptedMessageMediaVideo_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageMediaAudio_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageLayer' => 'Decrypted message layer', 'object_decryptedMessageLayer_param_layer_type_int' => 'Layer', 'object_decryptedMessageLayer_param_in_seq_no_type_int' => 'In seq no', 'object_decryptedMessageLayer_param_out_seq_no_type_int' => 'Out seq no', 'object_decryptedMessageLayer_param_message_type_DecryptedMessage' => 'Message', 'object_decryptedMessageActionResend' => 'Decrypted message action resend', 'object_decryptedMessageActionResend_param_start_seq_no_type_int' => 'Start seq no', 'object_decryptedMessageActionResend_param_end_seq_no_type_int' => 'End seq no', 'object_decryptedMessageActionNotifyLayer' => 'Decrypted message action notify layer', 'object_decryptedMessageActionNotifyLayer_param_layer_type_int' => 'Layer', 'object_decryptedMessageActionTyping' => 'Decrypted message action typing', 'object_decryptedMessageActionTyping_param_action_type_SendMessageAction' => 'Action', 'object_decryptedMessageActionRequestKey' => 'Decrypted message action request key', 'object_decryptedMessageActionRequestKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionRequestKey_param_g_a_type_bytes' => 'G a', 'object_decryptedMessageActionAcceptKey' => 'Decrypted message action accept key', 'object_decryptedMessageActionAcceptKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionAcceptKey_param_g_b_type_bytes' => 'G b', 'object_decryptedMessageActionAcceptKey_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_decryptedMessageActionAbortKey' => 'Decrypted message action abort key', 'object_decryptedMessageActionAbortKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionCommitKey' => 'Decrypted message action commit key', 'object_decryptedMessageActionCommitKey_param_exchange_id_type_long' => 'Exchange ID', 'object_decryptedMessageActionCommitKey_param_key_fingerprint_type_long' => 'Key fingerprint', 'object_decryptedMessageActionNoop' => 'Decrypted message action noop', 'object_decryptedMessageMediaExternalDocument' => 'Decrypted message media external document', 'object_decryptedMessageMediaExternalDocument_param_id_type_long' => 'ID', 'object_decryptedMessageMediaExternalDocument_param_access_hash_type_long' => 'Access hash', 'object_decryptedMessageMediaExternalDocument_param_date_type_int' => 'Date', 'object_decryptedMessageMediaExternalDocument_param_mime_type_type_string' => 'Mime type', 'object_decryptedMessageMediaExternalDocument_param_size_type_int' => 'Size', 'object_decryptedMessageMediaExternalDocument_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_decryptedMessageMediaExternalDocument_param_dc_id_type_int' => 'DC ID', 'object_decryptedMessageMediaExternalDocument_param_attributes_type_Vector t' => 'Attributes', 'object_decryptedMessage_param_entities_type_Vector t' => 'Entities', 'object_decryptedMessage_param_via_bot_name_type_string' => 'Via bot name', 'object_decryptedMessage_param_reply_to_random_id_type_long' => 'Reply to random ID', 'object_decryptedMessageMediaPhoto_param_caption_type_string' => 'Caption', 'object_decryptedMessageMediaVideo_param_caption_type_string' => 'Caption', 'object_decryptedMessageMediaDocument_param_attributes_type_Vector t' => 'Attributes', 'object_decryptedMessageMediaDocument_param_caption_type_string' => 'Caption', 'object_decryptedMessageMediaVenue' => 'Decrypted message media venue', 'object_decryptedMessageMediaVenue_param_lat_type_double' => 'Lat', 'object_decryptedMessageMediaVenue_param_long_type_double' => 'Long', 'object_decryptedMessageMediaVenue_param_title_type_string' => 'Title', 'object_decryptedMessageMediaVenue_param_address_type_string' => 'Address', 'object_decryptedMessageMediaVenue_param_provider_type_string' => 'Provider', 'object_decryptedMessageMediaVenue_param_venue_id_type_string' => 'Venue ID', 'object_decryptedMessageMediaWebPage' => 'Decrypted message media web page', 'object_decryptedMessageMediaWebPage_param_url_type_string' => 'URL', 'object_decryptedMessage_param_grouped_id_type_long' => 'Grouped ID', 'object_inputPeerContact' => 'Peer contact', 'object_inputPeerContact_param_user_id_type_int' => 'User ID', 'object_inputPeerForeign' => 'Peer foreign', 'object_inputPeerForeign_param_user_id_type_int' => 'User ID', 'object_inputPeerForeign_param_access_hash_type_long' => 'Access hash', 'object_inputUserContact' => 'User contact', 'object_inputUserContact_param_user_id_type_int' => 'User ID', 'object_inputUserForeign' => 'User foreign', 'object_inputUserForeign_param_user_id_type_int' => 'User ID', 'object_inputUserForeign_param_access_hash_type_long' => 'Access hash', 'object_inputMediaUploadedVideo' => 'Media uploaded video', 'object_inputMediaUploadedVideo_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedVideo_param_duration_type_int' => 'Duration', 'object_inputMediaUploadedVideo_param_w_type_int' => 'Width', 'object_inputMediaUploadedVideo_param_h_type_int' => 'Height', 'object_inputMediaUploadedVideo_param_mime_type_type_string' => 'Mime type', 'object_inputMediaUploadedThumbVideo' => 'Media uploaded thumb video', 'object_inputMediaUploadedThumbVideo_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedThumbVideo_param_thumb_type_InputFile' => 'Thumbnail', 'object_inputMediaUploadedThumbVideo_param_duration_type_int' => 'Duration', 'object_inputMediaUploadedThumbVideo_param_w_type_int' => 'Width', 'object_inputMediaUploadedThumbVideo_param_h_type_int' => 'Height', 'object_inputMediaUploadedThumbVideo_param_mime_type_type_string' => 'Mime type', 'object_inputMediaVideo' => 'Media video', 'object_inputMediaVideo_param_id_type_InputVideo' => 'ID', 'object_inputChatUploadedPhoto_param_crop_type_InputPhotoCrop' => 'Crop', 'object_inputChatPhoto_param_crop_type_InputPhotoCrop' => 'Crop', 'object_inputVideoEmpty' => 'Empty input video', 'object_inputVideo' => 'Video', 'object_inputVideo_param_id_type_long' => 'ID', 'object_inputVideo_param_access_hash_type_long' => 'Access hash', 'object_inputVideoFileLocation' => 'Video file location', 'object_inputVideoFileLocation_param_id_type_long' => 'ID', 'object_inputVideoFileLocation_param_access_hash_type_long' => 'Access hash', 'object_inputPhotoCropAuto' => 'Photo crop auto', 'object_inputPhotoCrop' => 'Photo crop', 'object_inputPhotoCrop_param_crop_left_type_double' => 'Crop left', 'object_inputPhotoCrop_param_crop_top_type_double' => 'Crop top', 'object_inputPhotoCrop_param_crop_width_type_double' => 'Crop width', 'object_userSelf' => 'User self', 'object_userSelf_param_id_type_int' => 'ID', 'object_userSelf_param_first_name_type_string' => 'First name', 'object_userSelf_param_last_name_type_string' => 'Last name', 'object_userSelf_param_username_type_string' => 'Username', 'object_userSelf_param_phone_type_string' => 'Phone', 'object_userSelf_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userSelf_param_status_type_UserStatus' => 'Status', 'object_userSelf_param_inactive_type_Bool' => 'Inactive?', 'object_userContact' => 'User contact', 'object_userContact_param_id_type_int' => 'ID', 'object_userContact_param_first_name_type_string' => 'First name', 'object_userContact_param_last_name_type_string' => 'Last name', 'object_userContact_param_username_type_string' => 'Username', 'object_userContact_param_access_hash_type_long' => 'Access hash', 'object_userContact_param_phone_type_string' => 'Phone', 'object_userContact_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userContact_param_status_type_UserStatus' => 'Status', 'object_userRequest' => 'User request', 'object_userRequest_param_id_type_int' => 'ID', 'object_userRequest_param_first_name_type_string' => 'First name', 'object_userRequest_param_last_name_type_string' => 'Last name', 'object_userRequest_param_username_type_string' => 'Username', 'object_userRequest_param_access_hash_type_long' => 'Access hash', 'object_userRequest_param_phone_type_string' => 'Phone', 'object_userRequest_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userRequest_param_status_type_UserStatus' => 'Status', 'object_userForeign' => 'User foreign', 'object_userForeign_param_id_type_int' => 'ID', 'object_userForeign_param_first_name_type_string' => 'First name', 'object_userForeign_param_last_name_type_string' => 'Last name', 'object_userForeign_param_username_type_string' => 'Username', 'object_userForeign_param_access_hash_type_long' => 'Access hash', 'object_userForeign_param_photo_type_UserProfilePhoto' => 'Photo', 'object_userForeign_param_status_type_UserStatus' => 'Status', 'object_userDeleted' => 'User deleted', 'object_userDeleted_param_id_type_int' => 'ID', 'object_userDeleted_param_first_name_type_string' => 'First name', 'object_userDeleted_param_last_name_type_string' => 'Last name', 'object_userDeleted_param_username_type_string' => 'Username', 'object_userStatusEmpty' => 'Empty user status', 'object_userStatusOnline' => 'User status online', 'object_userStatusOnline_param_expires_type_int' => 'Expires', 'object_userStatusOffline' => 'User status offline', 'object_userStatusOffline_param_was_online_type_int' => 'Was online', 'object_chat_param_left_type_Bool' => 'Left?', 'object_chatForbidden_param_date_type_int' => 'Date', 'object_chatParticipants_param_admin_id_type_int' => 'Admin ID', 'object_messageForwarded' => 'Message forwarded', 'object_messageForwarded_param_id_type_int' => 'ID', 'object_messageForwarded_param_fwd_from_id_type_int' => 'Forwarded from ID', 'object_messageForwarded_param_fwd_date_type_int' => 'Forwarded date', 'object_messageForwarded_param_from_id_type_int' => 'From ID', 'object_messageForwarded_param_to_id_type_Peer' => 'To ID', 'object_messageForwarded_param_date_type_int' => 'Date', 'object_messageForwarded_param_message_type_string' => 'Message', 'object_messageForwarded_param_media_type_MessageMedia' => 'Media', 'object_messageMediaVideo' => 'Message media video', 'object_messageMediaVideo_param_video_type_Video' => 'Video', 'object_messageMediaUnsupported_param_bytes_type_bytes' => 'Bytes', 'object_messageActionChatAddUser_param_user_id_type_int' => 'User ID', 'object_photo_param_user_id_type_int' => 'User ID', 'object_photo_param_caption_type_string' => 'Caption', 'object_photo_param_geo_type_GeoPoint' => 'Geo', 'object_videoEmpty' => 'Empty video', 'object_videoEmpty_param_id_type_long' => 'ID', 'object_video' => 'Video', 'object_video_param_id_type_long' => 'ID', 'object_video_param_access_hash_type_long' => 'Access hash', 'object_video_param_user_id_type_int' => 'User ID', 'object_video_param_date_type_int' => 'Date', 'object_video_param_caption_type_string' => 'Caption', 'object_video_param_duration_type_int' => 'Duration', 'object_video_param_mime_type_type_string' => 'Mime type', 'object_video_param_size_type_int' => 'Size', 'object_video_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_video_param_dc_id_type_int' => 'DC ID', 'object_video_param_w_type_int' => 'Width', 'object_video_param_h_type_int' => 'Height', 'object_auth.checkedPhone_param_phone_invited_type_Bool' => 'Phone invited?', 'object_auth.sentCode_param_phone_registered_type_Bool' => 'Phone registered?', 'object_auth.sentCode_param_send_call_timeout_type_int' => 'Send call timeout', 'object_auth.sentCode_param_is_password_type_Bool' => 'Is password?', 'object_auth.authorization_param_expires_type_int' => 'Expiration date', 'object_inputPeerNotifySettings_param_show_previews_type_Bool' => 'Show previews?', 'object_inputPeerNotifySettings_param_events_mask_type_int' => 'Events mask', 'object_peerNotifySettings_param_show_previews_type_Bool' => 'Show previews?', 'object_peerNotifySettings_param_events_mask_type_int' => 'Events mask', 'object_userFull_param_blocked_type_Bool' => 'Blocked?', 'object_userFull_param_real_first_name_type_string' => 'Real first name', 'object_userFull_param_real_last_name_type_string' => 'Real last name', 'object_contactSuggested' => 'Contact suggested', 'object_contactSuggested_param_user_id_type_int' => 'User ID', 'object_contactSuggested_param_mutual_contacts_type_int' => 'Mutual contacts', 'object_contactStatus_param_expires_type_int' => 'Expires', 'object_contacts.foreignLinkUnknown' => 'Foreign link unknown', 'object_contacts.foreignLinkRequested' => 'Foreign link requested', 'object_contacts.foreignLinkRequested_param_has_phone_type_Bool' => 'Has phone?', 'object_contacts.foreignLinkMutual' => 'Foreign link mutual', 'object_contacts.myLinkEmpty' => 'Empty my link', 'object_contacts.myLinkRequested' => 'My link requested', 'object_contacts.myLinkRequested_param_contact_type_Bool' => 'Contact?', 'object_contacts.myLinkContact' => 'My link contact', 'object_contacts.link_param_my_link_type_contacts.MyLink' => 'My link', 'object_contacts.link_param_foreign_link_type_contacts.ForeignLink' => 'Foreign link', 'object_contacts.suggested' => 'Suggested', 'object_contacts.suggested_param_results_type_Vector t' => 'Results', 'object_contacts.suggested_param_users_type_Vector t' => 'Users', 'object_messages.statedMessages' => 'Stated messages', 'object_messages.statedMessages_param_messages_type_Vector t' => 'Messages', 'object_messages.statedMessages_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessages_param_users_type_Vector t' => 'Users', 'object_messages.statedMessages_param_pts_type_int' => 'Pts', 'object_messages.statedMessages_param_seq_type_int' => 'Seq', 'object_messages.statedMessage' => 'Stated message', 'object_messages.statedMessage_param_message_type_Message' => 'Message', 'object_messages.statedMessage_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessage_param_users_type_Vector t' => 'Users', 'object_messages.statedMessage_param_pts_type_int' => 'Pts', 'object_messages.statedMessage_param_seq_type_int' => 'Seq', 'object_messages.sentMessage' => 'Sent message', 'object_messages.sentMessage_param_id_type_int' => 'ID', 'object_messages.sentMessage_param_date_type_int' => 'Date', 'object_messages.sentMessage_param_pts_type_int' => 'Pts', 'object_messages.sentMessage_param_seq_type_int' => 'Seq', 'object_messages.chats_param_users_type_Vector t' => 'Users', 'object_messages.affectedHistory_param_seq_type_int' => 'Seq', 'object_inputMessagesFilterPhotoVideoDocuments' => 'Messages filter photo video documents', 'object_inputMessagesFilterAudio' => 'Messages filter audio', 'object_inputMessagesFilterAudioDocuments' => 'Messages filter audio documents', 'object_updateReadMessages' => 'Update read messages', 'object_updateReadMessages_param_messages_type_Vector t' => 'Messages', 'object_updateReadMessages_param_pts_type_int' => 'Pts', 'object_updateUserStatus' => 'Update user status', 'object_updateUserStatus_param_user_id_type_int' => 'User ID', 'object_updateUserStatus_param_status_type_UserStatus' => 'Status', 'object_updateContactLink_param_my_link_type_contacts.MyLink' => 'My link', 'object_updateContactLink_param_foreign_link_type_contacts.ForeignLink' => 'Foreign link', 'object_updateNewAuthorization' => 'Update new authorization', 'object_updateNewAuthorization_param_auth_key_id_type_long' => 'Auth key ID', 'object_updateNewAuthorization_param_date_type_int' => 'Date', 'object_updateNewAuthorization_param_device_type_string' => 'Device', 'object_updateNewAuthorization_param_location_type_string' => 'Location', 'object_updateShortMessage_param_from_id_type_int' => 'From ID', 'object_updateShortMessage_param_seq_type_int' => 'Seq', 'object_updateShortChatMessage_param_seq_type_int' => 'Seq', 'object_dcOption_param_hostname_type_string' => 'Hostname', 'object_config_param_broadcast_size_max_type_int' => 'Broadcast size max', 'object_messages.statedMessagesLinks' => 'Stated messages links', 'object_messages.statedMessagesLinks_param_messages_type_Vector t' => 'Messages', 'object_messages.statedMessagesLinks_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessagesLinks_param_users_type_Vector t' => 'Users', 'object_messages.statedMessagesLinks_param_links_type_Vector t' => 'Links', 'object_messages.statedMessagesLinks_param_pts_type_int' => 'Pts', 'object_messages.statedMessagesLinks_param_seq_type_int' => 'Seq', 'object_messages.statedMessageLink' => 'Stated message link', 'object_messages.statedMessageLink_param_message_type_Message' => 'Message', 'object_messages.statedMessageLink_param_chats_type_Vector t' => 'Chats', 'object_messages.statedMessageLink_param_users_type_Vector t' => 'Users', 'object_messages.statedMessageLink_param_links_type_Vector t' => 'Links', 'object_messages.statedMessageLink_param_pts_type_int' => 'Pts', 'object_messages.statedMessageLink_param_seq_type_int' => 'Seq', 'object_messages.sentMessageLink' => 'Sent message link', 'object_messages.sentMessageLink_param_id_type_int' => 'ID', 'object_messages.sentMessageLink_param_date_type_int' => 'Date', 'object_messages.sentMessageLink_param_pts_type_int' => 'Pts', 'object_messages.sentMessageLink_param_seq_type_int' => 'Seq', 'object_messages.sentMessageLink_param_links_type_Vector t' => 'Links', 'object_inputMediaUploadedAudio' => 'Media uploaded audio', 'object_inputMediaUploadedAudio_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedAudio_param_duration_type_int' => 'Duration', 'object_inputMediaUploadedAudio_param_mime_type_type_string' => 'Mime type', 'object_inputMediaAudio' => 'Media audio', 'object_inputMediaAudio_param_id_type_InputAudio' => 'ID', 'object_inputMediaUploadedDocument_param_file_name_type_string' => 'File name', 'object_inputMediaUploadedThumbDocument' => 'Media uploaded thumb document', 'object_inputMediaUploadedThumbDocument_param_file_type_InputFile' => 'File', 'object_inputMediaUploadedThumbDocument_param_thumb_type_InputFile' => 'Thumbnail', 'object_inputMediaUploadedThumbDocument_param_file_name_type_string' => 'File name', 'object_inputMediaUploadedThumbDocument_param_mime_type_type_string' => 'Mime type', 'object_messageMediaAudio' => 'Message media audio', 'object_messageMediaAudio_param_audio_type_Audio' => 'Audio', 'object_inputAudioEmpty' => 'Empty input audio', 'object_inputAudio' => 'Audio', 'object_inputAudio_param_id_type_long' => 'ID', 'object_inputAudio_param_access_hash_type_long' => 'Access hash', 'object_inputAudioFileLocation' => 'Audio file location', 'object_inputAudioFileLocation_param_id_type_long' => 'ID', 'object_inputAudioFileLocation_param_access_hash_type_long' => 'Access hash', 'object_audioEmpty' => 'Empty audio', 'object_audioEmpty_param_id_type_long' => 'ID', 'object_audio' => 'Audio', 'object_audio_param_id_type_long' => 'ID', 'object_audio_param_access_hash_type_long' => 'Access hash', 'object_audio_param_user_id_type_int' => 'User ID', 'object_audio_param_date_type_int' => 'Date', 'object_audio_param_duration_type_int' => 'Duration', 'object_audio_param_mime_type_type_string' => 'Mime type', 'object_audio_param_size_type_int' => 'Size', 'object_audio_param_dc_id_type_int' => 'DC ID', 'object_document_param_user_id_type_int' => 'User ID', 'object_document_param_file_name_type_string' => 'File name', 'object_auth.sentAppCode' => 'Sent app code', 'object_auth.sentAppCode_param_phone_registered_type_Bool' => 'Phone registered?', 'object_auth.sentAppCode_param_phone_code_hash_type_string' => 'Phone code hash', 'object_auth.sentAppCode_param_send_call_timeout_type_int' => 'Send call timeout', 'object_auth.sentAppCode_param_is_password_type_Bool' => 'Is password?', 'object_contactFound' => 'Contact found', 'object_contactFound_param_user_id_type_int' => 'User ID', 'object_updateServiceNotification_param_popup_type_Bool' => 'Popup?', 'object_inputMediaUploadedThumbDocument_param_attributes_type_Vector t' => 'Attributes', 'object_userStatusRecently' => 'User status recently', 'object_userStatusLastWeek' => 'User status last week', 'object_userStatusLastMonth' => 'User status last month', 'object_account.sentChangePhoneCode' => 'Sent change phone code', 'object_account.sentChangePhoneCode_param_phone_code_hash_type_string' => 'Phone code hash', 'object_account.sentChangePhoneCode_param_send_call_timeout_type_int' => 'Send call timeout', 'object_messages.allStickers_param_hash_type_string' => 'Hash', 'object_messages.allStickers_param_packs_type_Vector t' => 'Packs', 'object_messages.allStickers_param_documents_type_Vector t' => 'Documents', 'object_message_param_fwd_from_id_type_int' => 'Forwarded from ID', 'object_message_param_fwd_date_type_int' => 'Forwarded date', 'object_chatLocated' => 'Chat located', 'object_chatLocated_param_chat_id_type_int' => 'Chat ID', 'object_chatLocated_param_distance_type_int' => 'Distance', 'object_messages.messageEmpty' => 'Empty message', 'object_messages.statedMessages_param_pts_count_type_int' => 'Pts count', 'object_messages.statedMessage_param_pts_count_type_int' => 'Pts count', 'object_messages.sentMessage_param_pts_count_type_int' => 'Pts count', 'object_updateReadMessages_param_pts_count_type_int' => 'Pts count', 'object_updateShortMessage_param_fwd_from_id_type_int' => 'Fwd from ID', 'object_updateShortMessage_param_fwd_date_type_int' => 'Fwd date', 'object_updateShortChatMessage_param_fwd_from_id_type_int' => 'Fwd from ID', 'object_updateShortChatMessage_param_fwd_date_type_int' => 'Fwd date', 'object_messages.statedMessagesLinks_param_pts_count_type_int' => 'Pts count', 'object_messages.statedMessageLink_param_pts_count_type_int' => 'Pts count', 'object_messages.sentMessageLink_param_pts_count_type_int' => 'Pts count', 'object_inputGeoChat' => 'Geo chat', 'object_inputGeoChat_param_chat_id_type_int' => 'Chat ID', 'object_inputGeoChat_param_access_hash_type_long' => 'Access hash', 'object_inputNotifyGeoChatPeer' => 'Notify geo chat peer', 'object_inputNotifyGeoChatPeer_param_peer_type_InputGeoChat' => 'Peer', 'object_geoChat' => 'Geo chat', 'object_geoChat_param_id_type_int' => 'ID', 'object_geoChat_param_access_hash_type_long' => 'Access hash', 'object_geoChat_param_title_type_string' => 'Title', 'object_geoChat_param_address_type_string' => 'Address', 'object_geoChat_param_venue_type_string' => 'Venue', 'object_geoChat_param_geo_type_GeoPoint' => 'Geo', 'object_geoChat_param_photo_type_ChatPhoto' => 'Photo', 'object_geoChat_param_participants_count_type_int' => 'Participants count', 'object_geoChat_param_date_type_int' => 'Date', 'object_geoChat_param_checked_in_type_Bool' => 'Checked in?', 'object_geoChat_param_version_type_int' => 'Version', 'object_geoChatMessageEmpty' => 'Empty geo chat message', 'object_geoChatMessageEmpty_param_chat_id_type_int' => 'Chat ID', 'object_geoChatMessageEmpty_param_id_type_int' => 'ID', 'object_geoChatMessage' => 'Geo chat message', 'object_geoChatMessage_param_chat_id_type_int' => 'Chat ID', 'object_geoChatMessage_param_id_type_int' => 'ID', 'object_geoChatMessage_param_from_id_type_int' => 'From ID', 'object_geoChatMessage_param_date_type_int' => 'Date', 'object_geoChatMessage_param_message_type_string' => 'Message', 'object_geoChatMessage_param_media_type_MessageMedia' => 'Media', 'object_geoChatMessageService' => 'Geo chat message service', 'object_geoChatMessageService_param_chat_id_type_int' => 'Chat ID', 'object_geoChatMessageService_param_id_type_int' => 'ID', 'object_geoChatMessageService_param_from_id_type_int' => 'From ID', 'object_geoChatMessageService_param_date_type_int' => 'Date', 'object_geoChatMessageService_param_action_type_MessageAction' => 'Action', 'object_geochats.statedMessage' => 'Stated message', 'object_geochats.statedMessage_param_message_type_GeoChatMessage' => 'Message', 'object_geochats.statedMessage_param_chats_type_Vector t' => 'Chats', 'object_geochats.statedMessage_param_users_type_Vector t' => 'Users', 'object_geochats.statedMessage_param_seq_type_int' => 'Seq', 'object_geochats.located' => 'Located', 'object_geochats.located_param_results_type_Vector t' => 'Results', 'object_geochats.located_param_messages_type_Vector t' => 'Messages', 'object_geochats.located_param_chats_type_Vector t' => 'Chats', 'object_geochats.located_param_users_type_Vector t' => 'Users', 'object_geochats.messages' => 'Messages', 'object_geochats.messages_param_messages_type_Vector t' => 'Messages', 'object_geochats.messages_param_chats_type_Vector t' => 'Chats', 'object_geochats.messages_param_users_type_Vector t' => 'Users', 'object_geochats.messagesSlice' => 'Messages slice', 'object_geochats.messagesSlice_param_count_type_int' => 'Count', 'object_geochats.messagesSlice_param_messages_type_Vector t' => 'Messages', 'object_geochats.messagesSlice_param_chats_type_Vector t' => 'Chats', 'object_geochats.messagesSlice_param_users_type_Vector t' => 'Users', 'object_messageActionGeoChatCreate' => 'Message action geo chat create', 'object_messageActionGeoChatCreate_param_title_type_string' => 'Title', 'object_messageActionGeoChatCreate_param_address_type_string' => 'Address', 'object_messageActionGeoChatCheckin' => 'Message action geo chat checkin', 'object_updateNewGeoChatMessage' => 'Update new geo chat message', 'object_updateNewGeoChatMessage_param_message_type_GeoChatMessage' => 'Message', 'object_messages.sentMessage_param_media_type_MessageMedia' => 'Media', 'object_messages.sentMessageLink_param_media_type_MessageMedia' => 'Media', 'object_inputMediaUploadedPhoto_param_caption_type_string' => 'Caption', 'object_inputMediaPhoto_param_caption_type_string' => 'Caption', 'object_inputMediaUploadedVideo_param_caption_type_string' => 'Caption', 'object_inputMediaUploadedThumbVideo_param_caption_type_string' => 'Caption', 'object_inputMediaVideo_param_caption_type_string' => 'Caption', 'object_messageMediaPhoto_param_caption_type_string' => 'Caption', 'object_messageMediaVideo_param_caption_type_string' => 'Caption', 'object_botCommand' => 'Bot command', 'object_botCommand_param_command_type_string' => 'Command', 'object_botCommand_param_description_type_string' => 'Description', 'object_botInfoEmpty' => 'Empty bot info', 'object_botInfo_param_version_type_int' => 'Version', 'object_botInfo_param_share_text_type_string' => 'Share text', 'object_help.appChangelogEmpty' => 'Empty app changelog', 'object_help.appChangelog' => 'App changelog', 'object_help.appChangelog_param_text_type_string' => 'Text', 'object_message_param_fwd_from_id_type_Peer' => 'Forwarded from ID', 'object_updateShortMessage_param_fwd_from_id_type_Peer' => 'Fwd from ID', 'object_updateShortChatMessage_param_fwd_from_id_type_Peer' => 'Fwd from ID', 'object_channelFull_param_unread_important_count_type_int' => 'Unread important count', 'object_dialogChannel' => 'Dialog channel', 'object_dialogChannel_param_peer_type_Peer' => 'Peer', 'object_dialogChannel_param_top_message_type_int' => 'Top message', 'object_dialogChannel_param_top_important_message_type_int' => 'Top important message', 'object_dialogChannel_param_read_inbox_max_id_type_int' => 'Read inbox max ID', 'object_dialogChannel_param_unread_count_type_int' => 'Unread count', 'object_dialogChannel_param_unread_important_count_type_int' => 'Unread important count', 'object_dialogChannel_param_notify_settings_type_PeerNotifySettings' => 'Notify settings', 'object_dialogChannel_param_pts_type_int' => 'Pts', 'object_messageGroup' => 'Message group', 'object_messageGroup_param_min_id_type_int' => 'Min ID', 'object_messageGroup_param_max_id_type_int' => 'Max ID', 'object_messageGroup_param_count_type_int' => 'Count', 'object_messageGroup_param_date_type_int' => 'Date', 'object_messages.channelMessages_param_collapsed_type_Vector t' => 'Collapsed', 'object_updateChannelGroup' => 'Update channel group', 'object_updateChannelGroup_param_channel_id_type_int' => 'Channel ID', 'object_updateChannelGroup_param_group_type_MessageGroup' => 'Group', 'object_updates.channelDifferenceTooLong_param_top_important_message_type_int' => 'Top important message', 'object_updates.channelDifferenceTooLong_param_unread_important_count_type_int' => 'Unread important count', 'object_channelMessagesFilterCollapsed' => 'Channel messages filter collapsed', 'object_channelParticipantModerator' => 'Channel participant moderator', 'object_channelParticipantModerator_param_user_id_type_int' => 'User ID', 'object_channelParticipantModerator_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantModerator_param_date_type_int' => 'Date', 'object_channelParticipantEditor' => 'Channel participant editor', 'object_channelParticipantEditor_param_user_id_type_int' => 'User ID', 'object_channelParticipantEditor_param_inviter_id_type_int' => 'Inviter ID', 'object_channelParticipantEditor_param_date_type_int' => 'Date', 'object_channelParticipantKicked' => 'Channel participant kicked', 'object_channelParticipantKicked_param_user_id_type_int' => 'User ID', 'object_channelParticipantKicked_param_kicked_by_type_int' => 'Kicked by', 'object_channelParticipantKicked_param_date_type_int' => 'Date', 'object_channelRoleEmpty' => 'Empty channel role', 'object_channelRoleModerator' => 'Channel role moderator', 'object_channelRoleEditor' => 'Channel role editor', 'object_inputChatEmpty' => 'Empty input chat', 'object_inputChat' => 'Chat', 'object_inputChat_param_chat_id_type_int' => 'Chat ID', 'object_updateReadChannelInbox_param_peer_type_Peer' => 'Peer', 'object_updateDeleteChannelMessages_param_peer_type_Peer' => 'Peer', 'object_message_param_unread_type_true' => 'Unread?', 'object_messageService_param_unread_type_true' => 'Unread?', 'object_updateShortMessage_param_unread_type_true' => 'Unread?', 'object_updateShortChatMessage_param_unread_type_true' => 'Unread?', 'object_stickerSet_param_disabled_type_true' => 'Disabled?', 'object_updateShortSentMessage_param_unread_type_true' => 'Unread?', 'object_channel_param_kicked_type_true' => 'Kicked?', 'object_channel_param_moderator_type_true' => 'Moderator?', 'object_channelMessagesFilter_param_important_only_type_true' => 'Important only?', 'object_messageActionChatDeactivate' => 'Message action chat deactivate', 'object_messageActionChatActivate' => 'Message action chat activate', 'object_user_param_restiction_reason_type_string' => 'Restiction reason', 'object_channel_param_restiction_reason_type_string' => 'Restiction reason', 'object_webPageExternal' => 'Web page external', 'object_webPageExternal_param_url_type_string' => 'URL', 'object_webPageExternal_param_display_url_type_string' => 'Display URL', 'object_webPageExternal_param_type_type_string' => 'Type', 'object_webPageExternal_param_title_type_string' => 'Title', 'object_webPageExternal_param_description_type_string' => 'Description', 'object_webPageExternal_param_thumb_url_type_string' => 'Thumbnail URL', 'object_webPageExternal_param_content_url_type_string' => 'Content URL', 'object_webPageExternal_param_w_type_int' => 'Width', 'object_webPageExternal_param_h_type_int' => 'Height', 'object_webPageExternal_param_duration_type_int' => 'Duration', 'object_foundGif_param_webpage_type_WebPage' => 'Webpage', 'object_inputMediaUploadedDocument_param_caption_type_string' => 'Caption', 'object_inputMediaUploadedThumbDocument_param_caption_type_string' => 'Caption', 'object_inputMediaDocument_param_caption_type_string' => 'Caption', 'object_messageMediaDocument_param_caption_type_string' => 'Caption', 'object_inputBotInlineMessageMediaAuto_param_caption_type_string' => 'Caption', 'object_botInlineMessageMediaAuto_param_caption_type_string' => 'Caption', 'object_botInlineMediaResultDocument' => 'Bot inline media result document', 'object_botInlineMediaResultDocument_param_id_type_string' => 'ID', 'object_botInlineMediaResultDocument_param_type_type_string' => 'Type', 'object_botInlineMediaResultDocument_param_document_type_Document' => 'Document', 'object_botInlineMediaResultDocument_param_send_message_type_BotInlineMessage' => 'Send message', 'object_botInlineMediaResultPhoto' => 'Bot inline media result photo', 'object_botInlineMediaResultPhoto_param_id_type_string' => 'ID', 'object_botInlineMediaResultPhoto_param_type_type_string' => 'Type', 'object_botInlineMediaResultPhoto_param_photo_type_Photo' => 'Photo', 'object_botInlineMediaResultPhoto_param_send_message_type_BotInlineMessage' => 'Send message', 'object_inputMediaVideo_param_video_type_InputVideo' => 'Video', 'object_inputMediaAudio_param_audio_type_InputAudio' => 'Audio', 'object_inputMediaDocument_param_document_id_type_InputDocument' => 'Document ID', 'object_inputGeoPoint_param_latitude_type_double' => 'Latitude', 'object_inputGeoPoint_param_longitude_type_double' => 'Longitude', 'object_geoPoint_param_longitude_type_double' => 'Longitude', 'object_geoPoint_param_latitude_type_double' => 'Latitude', 'object_updateNewEncryptedMessage_param_encr_message_type_EncryptedMessage' => 'Encr message', 'object_updateEncryption_param_encr_chat_type_EncryptedChat' => 'Encr chat', 'object_updateNotifySettings_param_notify_peer_type_NotifyPeer' => 'Notify peer', 'object_updateServiceNotification_param_message_text_type_string' => 'Message text', 'object_updateNewChannelMessage_param_channel_pts_type_int' => 'Channel pts', 'object_updateNewChannelMessage_param_channel_pts_count_type_int' => 'Channel pts count', 'object_updateDeleteChannelMessages_param_channel_pts_type_int' => 'Channel pts', 'object_updateDeleteChannelMessages_param_channel_pts_count_type_int' => 'Channel pts count', 'object_updates.channelDifferenceEmpty_param_channel_pts_type_int' => 'Channel pts', 'object_updates.channelDifferenceTooLong_param_channel_pts_type_int' => 'Channel pts', 'object_updates.channelDifference_param_channel_pts_type_int' => 'Channel pts', 'object_privacyKeyChatInvite' => 'Privacy key chat invite', 'object_inputMediaUploadedThumbDocument_param_stickers_type_Vector t' => 'Stickers', 'object_inputMediaPhotoExternal_param_caption_type_string' => 'Caption', 'object_inputMediaDocumentExternal_param_caption_type_string' => 'Caption', 'object_destroy_auth_key_ok' => 'Destroy auth key ok', 'object_destroy_auth_key_none' => 'Destroy auth key none', 'object_destroy_auth_key_fail' => 'Destroy auth key fail', 'object_help.appChangelog_param_message_type_string' => 'Message', 'object_help.appChangelog_param_media_type_MessageMedia' => 'Media', 'object_help.appChangelog_param_entities_type_Vector t' => 'Entities', 'object_pageBlockParagraph' => 'Page block paragraph', 'object_pageBlockParagraph_param_text_type_RichText' => 'Text', 'object_pageBlockPreformatted' => 'Page block preformatted', 'object_pageBlockPreformatted_param_text_type_RichText' => 'Text', 'object_pageBlockPreformatted_param_language_type_string' => 'Language', 'object_pageBlockDivider' => 'Page block divider', 'object_pageBlockAnchor' => 'Page block anchor', 'object_pageBlockAnchor_param_name_type_string' => 'Name', 'object_pageBlockCover' => 'Page block cover', 'object_pageBlockCover_param_cover_type_PageBlock' => 'Cover', 'object_pagePart_param_videos_type_Vector t' => 'Videos', 'object_pageFull_param_videos_type_Vector t' => 'Videos', 'object_phoneCallRequested_param_g_a_type_bytes' => 'G a', 'object_resPQ_param_pq_type_string' => 'Pq', 'object_p_q_inner_data_param_pq_type_string' => 'Pq', 'object_p_q_inner_data_param_p_type_string' => 'P', 'object_p_q_inner_data_param_q_type_string' => 'Q', 'object_server_DH_params_ok_param_encrypted_answer_type_string' => 'Encrypted answer', 'object_server_DH_inner_data_param_dh_prime_type_string' => 'Dh prime', 'object_server_DH_inner_data_param_g_a_type_string' => 'G a', 'object_client_DH_inner_data_param_g_b_type_string' => 'G b', 'object_msgs_state_info_param_info_type_string' => 'Info', 'object_msgs_all_info_param_info_type_string' => 'Info', 'object_http_wait' => 'Http wait', 'object_http_wait_param_max_delay_type_int' => 'Max delay', 'object_http_wait_param_wait_after_type_int' => 'Wait after', 'object_http_wait_param_max_wait_type_int' => 'Max wait', 'object_ipPort' => 'Ip port', 'object_ipPort_param_ipv4_type_int' => 'Ipv4', 'object_ipPort_param_port_type_int' => 'Port', 'object_help.configSimple' => 'Config simple', 'object_help.configSimple_param_date_type_int' => 'Date', 'object_help.configSimple_param_expires_type_int' => 'Expires', 'object_help.configSimple_param_dc_id_type_int' => 'DC ID', 'object_help.configSimple_param_ip_port_list_type_Vector t' => 'Ip port list', 'object_inputMessagesFilterMyMentionsUnread' => 'Messages filter my mentions unread', 'method_initConnection_param_proxy_type_InputClientProxy' => 'The current proxy', 'method_account.registerDevice_param_secret_type_bytes' => 'Secret', 'method_account.getAllSecureValues' => 'Get all secure telegram passport values', 'method_account.getSecureValue' => 'Get secure value for telegram passport', 'method_account.getSecureValue_param_types_type_Vector t' => 'Get telegram passport secure parameters', 'method_account.saveSecureValue' => 'Save telegram passport secure value', 'method_account.saveSecureValue_param_value_type_InputSecureValue' => 'Encrypted value', 'method_account.saveSecureValue_param_secure_secret_id_type_long' => 'Secret', 'method_account.deleteSecureValue' => 'Delete secure telegram passport value', 'method_account.deleteSecureValue_param_types_type_Vector t' => 'The values to delete', 'method_account.getAuthorizationForm' => 'Bots only: get telegram passport authorization form', 'method_account.getAuthorizationForm_param_bot_id_type_int' => 'Bot ID', 'method_account.getAuthorizationForm_param_scope_type_string' => 'Scope', 'method_account.getAuthorizationForm_param_public_key_type_string' => 'Bot\'s public key', 'method_account.acceptAuthorization' => 'Accept telegram passport authorization', 'method_account.acceptAuthorization_param_bot_id_type_int' => 'Bot ID', 'method_account.acceptAuthorization_param_scope_type_string' => 'Scope', 'method_account.acceptAuthorization_param_public_key_type_string' => 'The bot\'s RSA public key', 'method_account.acceptAuthorization_param_value_hashes_type_Vector t' => 'Hashes of the encrypted credentials', 'method_account.acceptAuthorization_param_credentials_type_SecureCredentialsEncrypted' => 'Encrypted secure credentials', 'method_account.sendVerifyPhoneCode' => 'Send phone verification code', 'method_account.sendVerifyPhoneCode_param_allow_flashcall_type_true' => 'Allow phone calls?', 'method_account.sendVerifyPhoneCode_param_phone_number_type_string' => 'The phone number', 'method_account.sendVerifyPhoneCode_param_current_number_type_Bool' => 'Is this the current number?', 'method_account.verifyPhone' => 'Verify phone number', 'method_account.verifyPhone_param_phone_number_type_string' => 'The phone number', 'method_account.verifyPhone_param_phone_code_hash_type_string' => 'The phone code hash returned by account.sendVerifyPhoneCode', 'method_account.verifyPhone_param_phone_code_type_string' => 'The phone code type returned by account.sendVerifyPhoneCode', 'method_account.sendVerifyEmailCode' => 'Send email verification code', 'method_account.sendVerifyEmailCode_param_email_type_string' => 'Email', 'method_account.verifyEmail' => 'Verify email address', 'method_account.verifyEmail_param_email_type_string' => 'The email address', 'method_account.verifyEmail_param_code_type_string' => 'The received code', 'method_users.setSecureValueErrors' => 'Set secure value error for telegram passport', 'method_users.setSecureValueErrors_param_id_type_InputUser' => 'The user ID', 'method_users.setSecureValueErrors_param_errors_type_Vector t' => 'The errors', 'method_messages.search_param_hash_type_int' => 'IDs of messages you already fetched', 'method_messages.report' => 'Report a message', 'method_messages.report_param_peer_type_InputPeer' => 'The user that sent the messages', 'method_messages.report_param_id_type_Vector t' => 'The messages to report', 'method_messages.report_param_reason_type_ReportReason' => 'The reason why you\'re sending this report', 'method_messages.getStickers_param_hash_type_int' => 'IDs of previously fetched stickers', 'method_messages.editMessage_param_media_type_InputMedia' => 'The media to substitute', 'method_messages.editInlineBotMessage_param_media_type_InputMedia' => 'The media to substitute', 'method_messages.toggleDialogPin_param_peer_type_InputDialogPeer' => 'The dialog to pin', 'method_messages.getRecentLocations_param_hash_type_int' => 'IDs of previously fetched locations', 'method_messages.searchStickerSets' => 'Find a sticker set', 'method_messages.searchStickerSets_param_exclude_featured_type_true' => 'Exclude featured sticker sets from the search?', 'method_messages.searchStickerSets_param_q_type_string' => 'The search query', 'method_messages.searchStickerSets_param_hash_type_int' => 'Ids of stickers you already cached', 'method_upload.getFileHashes' => 'Get file hashes', 'method_upload.getFileHashes_param_location_type_InputFileLocation' => 'The file', 'method_upload.getFileHashes_param_offset_type_int' => 'Offset', 'method_help.getProxyData' => 'Get information about the current proxy', 'method_help.getTermsOfServiceUpdate' => 'Get updated TOS', 'method_help.acceptTermsOfService' => 'Accept telegram\'s TOS', 'method_help.acceptTermsOfService_param_id_type_DataJSON' => 'TOS', 'method_help.getDeepLinkInfo' => 'Get deep link info', 'method_help.getDeepLinkInfo_param_path_type_string' => 'Deep link', 'object_inputSecureFileLocation' => 'Secure file location', 'object_inputSecureFileLocation_param_id_type_long' => 'ID', 'object_inputSecureFileLocation_param_access_hash_type_long' => 'Access hash', 'object_messageActionBotAllowed' => 'Message action bot allowed', 'object_messageActionBotAllowed_param_domain_type_string' => 'Domain', 'object_messageActionSecureValuesSentMe' => 'Message action secure values sent me', 'object_messageActionSecureValuesSentMe_param_values_type_Vector t' => 'Values', 'object_messageActionSecureValuesSentMe_param_credentials_type_SecureCredentialsEncrypted' => 'Credentials', 'object_messageActionSecureValuesSent' => 'Message action secure values sent', 'object_messageActionSecureValuesSent_param_types_type_Vector t' => 'Types', 'object_auth.sentCode_param_terms_of_service_type_help.TermsOfService' => 'Terms of service', 'object_inputPeerNotifySettings_param_silent_type_Bool' => 'Silent?', 'object_peerNotifySettings_param_silent_type_Bool' => 'Silent?', 'object_updateDialogPinned_param_peer_type_DialogPeer' => 'Peer', 'object_upload.fileCdnRedirect_param_file_hashes_type_Vector t' => 'File hashes', 'object_dcOption_param_secret_type_bytes' => 'Secret', 'object_config_param_preload_featured_stickers_type_true' => 'Preload featured stickers?', 'object_config_param_ignore_phone_entities_type_true' => 'Ignore phone entities?', 'object_config_param_revoke_pm_inbox_type_true' => 'Revoke pm inbox?', 'object_config_param_blocked_mode_type_true' => 'Blocked mode?', 'object_config_param_revoke_time_limit_type_int' => 'Revoke time limit', 'object_config_param_revoke_pm_time_limit_type_int' => 'Revoke pm time limit', 'object_config_param_autoupdate_url_prefix_type_string' => 'Autoupdate URL prefix', 'object_messages.stickers_param_hash_type_int' => 'Hash', 'object_account.noPassword_param_new_secure_salt_type_bytes' => 'New secure salt', 'object_account.noPassword_param_secure_random_type_bytes' => 'Secure random', 'object_account.password_param_has_recovery_type_true' => 'Has recovery?', 'object_account.password_param_has_secure_values_type_true' => 'Has secure values?', 'object_account.password_param_new_secure_salt_type_bytes' => 'New secure salt', 'object_account.password_param_secure_random_type_bytes' => 'Secure random', 'object_account.passwordSettings_param_secure_salt_type_bytes' => 'Secure salt', 'object_account.passwordSettings_param_secure_secret_type_bytes' => 'Secure secret', 'object_account.passwordSettings_param_secure_secret_id_type_long' => 'Secure secret ID', 'object_account.passwordInputSettings_param_new_secure_salt_type_bytes' => 'New secure salt', 'object_account.passwordInputSettings_param_new_secure_secret_type_bytes' => 'New secure secret', 'object_account.passwordInputSettings_param_new_secure_secret_id_type_long' => 'New secure secret ID', 'object_stickerSet_param_installed_date_type_int' => 'Installed date', 'object_messageEntityPhone' => 'Message entity phone', 'object_messageEntityPhone_param_offset_type_int' => 'Offset', 'object_messageEntityPhone_param_length_type_int' => 'Length', 'object_messageEntityCashtag' => 'Message entity cashtag', 'object_messageEntityCashtag_param_offset_type_int' => 'Offset', 'object_messageEntityCashtag_param_length_type_int' => 'Length', 'object_help.termsOfService_param_popup_type_true' => 'Popup?', 'object_help.termsOfService_param_id_type_DataJSON' => 'ID', 'object_help.termsOfService_param_entities_type_Vector t' => 'Entities', 'object_help.termsOfService_param_min_age_confirm_type_int' => 'Min age confirm', 'object_inputBotInlineMessageMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_inputBotInlineResult_param_thumb_type_InputWebDocument' => 'Thumbnail', 'object_inputBotInlineResult_param_content_type_InputWebDocument' => 'Content', 'object_botInlineMessageMediaVenue_param_venue_type_type_string' => 'Venue type', 'object_botInlineResult_param_thumb_type_WebDocument' => 'Thumbnailnail', 'object_botInlineResult_param_content_type_WebDocument' => 'Content', 'object_messages.recentStickers_param_packs_type_Vector t' => 'Packs', 'object_messages.recentStickers_param_dates_type_Vector t' => 'Dates', 'object_webDocumentNoProxy' => 'Web document no proxy', 'object_webDocumentNoProxy_param_url_type_string' => 'URL', 'object_webDocumentNoProxy_param_size_type_int' => 'Size', 'object_webDocumentNoProxy_param_mime_type_type_string' => 'Mime type', 'object_webDocumentNoProxy_param_attributes_type_Vector t' => 'Attributes', 'object_inputWebFileGeoPointLocation' => 'Web file geo point location', 'object_inputWebFileGeoPointLocation_param_geo_point_type_InputGeoPoint' => 'Geo point', 'object_inputWebFileGeoPointLocation_param_w_type_int' => 'Width', 'object_inputWebFileGeoPointLocation_param_h_type_int' => 'Height', 'object_inputWebFileGeoPointLocation_param_zoom_type_int' => 'Zoom', 'object_inputWebFileGeoPointLocation_param_scale_type_int' => 'Scale', 'object_inputWebFileGeoMessageLocation' => 'Web file geo message location', 'object_inputWebFileGeoMessageLocation_param_peer_type_InputPeer' => 'Peer', 'object_inputWebFileGeoMessageLocation_param_msg_id_type_int' => 'Msg ID', 'object_inputWebFileGeoMessageLocation_param_w_type_int' => 'Width', 'object_inputWebFileGeoMessageLocation_param_h_type_int' => 'Height', 'object_inputWebFileGeoMessageLocation_param_zoom_type_int' => 'Zoom', 'object_inputWebFileGeoMessageLocation_param_scale_type_int' => 'Scale', 'object_channelAdminRights_param_manage_call_type_true' => 'Manage group calls', 'object_inputDialogPeer' => 'Dialog peer', 'object_inputDialogPeer_param_peer_type_InputPeer' => 'Peer', 'object_dialogPeer' => 'Dialog peer', 'object_dialogPeer_param_peer_type_Peer' => 'Peer', 'object_messages.foundStickerSetsNotModified' => 'Found sticker sets not modified', 'object_messages.foundStickerSets' => 'Found sticker sets', 'object_messages.foundStickerSets_param_hash_type_int' => 'Hash', 'object_messages.foundStickerSets_param_sets_type_Vector t' => 'Sets', 'object_fileHash' => 'File hash', 'object_fileHash_param_offset_type_int' => 'Offset', 'object_fileHash_param_limit_type_int' => 'Limit', 'object_fileHash_param_hash_type_bytes' => 'Hash', 'object_inputClientProxy' => 'Client proxy', 'object_inputClientProxy_param_address_type_string' => 'Address', 'object_inputClientProxy_param_port_type_int' => 'Port', 'object_help.proxyDataEmpty' => 'Empty proxy data', 'object_help.proxyDataEmpty_param_expires_type_int' => 'Expires', 'object_help.proxyDataPromo' => 'Proxy data promo', 'object_help.proxyDataPromo_param_expires_type_int' => 'Expires', 'object_help.proxyDataPromo_param_peer_type_Peer' => 'Peer', 'object_help.proxyDataPromo_param_chats_type_Vector t' => 'Chats', 'object_help.proxyDataPromo_param_users_type_Vector t' => 'Users', 'object_help.termsOfServiceUpdateEmpty' => 'Empty terms of service update', 'object_help.termsOfServiceUpdateEmpty_param_expires_type_int' => 'Expires', 'object_help.termsOfServiceUpdate' => 'Terms of service update', 'object_help.termsOfServiceUpdate_param_expires_type_int' => 'Expires', 'object_help.termsOfServiceUpdate_param_terms_of_service_type_help.TermsOfService' => 'Terms of service', 'object_inputSecureFileUploaded' => 'Secure file uploaded', 'object_inputSecureFileUploaded_param_id_type_long' => 'ID', 'object_inputSecureFileUploaded_param_parts_type_int' => 'Parts', 'object_inputSecureFileUploaded_param_md5_checksum_type_string' => 'Md5 checksum', 'object_inputSecureFileUploaded_param_file_hash_type_bytes' => 'File hash', 'object_inputSecureFileUploaded_param_secret_type_bytes' => 'Secret', 'object_inputSecureFile' => 'Secure file', 'object_inputSecureFile_param_id_type_long' => 'ID', 'object_inputSecureFile_param_access_hash_type_long' => 'Access hash', 'object_secureFileEmpty' => 'Empty secure file', 'object_secureFile' => 'Secure file', 'object_secureFile_param_id_type_long' => 'ID', 'object_secureFile_param_access_hash_type_long' => 'Access hash', 'object_secureFile_param_size_type_int' => 'Size', 'object_secureFile_param_dc_id_type_int' => 'DC ID', 'object_secureFile_param_date_type_int' => 'Date', 'object_secureFile_param_file_hash_type_bytes' => 'File hash', 'object_secureFile_param_secret_type_bytes' => 'Secret', 'object_secureData' => 'Secure data', 'object_secureData_param_data_type_bytes' => 'Data', 'object_secureData_param_data_hash_type_bytes' => 'Data hash', 'object_secureData_param_secret_type_bytes' => 'Secret', 'object_securePlainPhone' => 'Secure plain phone', 'object_securePlainPhone_param_phone_type_string' => 'Phone', 'object_securePlainEmail' => 'Secure plain email', 'object_securePlainEmail_param_email_type_string' => 'Email', 'object_secureValueTypePersonalDetails' => 'Secure value type personal details', 'object_secureValueTypePassport' => 'Secure value type passport', 'object_secureValueTypeDriverLicense' => 'Secure value type driver license', 'object_secureValueTypeIdentityCard' => 'Secure value type IDentity card', 'object_secureValueTypeInternalPassport' => 'Secure value type internal passport', 'object_secureValueTypeAddress' => 'Secure value type address', 'object_secureValueTypeUtilityBill' => 'Secure value type utility bill', 'object_secureValueTypeBankStatement' => 'Secure value type bank statement', 'object_secureValueTypeRentalAgreement' => 'Secure value type rental agreement', 'object_secureValueTypePassportRegistration' => 'Secure value type passport registration', 'object_secureValueTypeTemporaryRegistration' => 'Secure value type temporary registration', 'object_secureValueTypePhone' => 'Secure value type phone', 'object_secureValueTypeEmail' => 'Secure value type email', 'object_secureValue' => 'Secure value', 'object_secureValue_param_type_type_SecureValueType' => 'Type', 'object_secureValue_param_data_type_SecureData' => 'Data', 'object_secureValue_param_front_side_type_SecureFile' => 'Front side', 'object_secureValue_param_reverse_side_type_SecureFile' => 'Reverse side', 'object_secureValue_param_selfie_type_SecureFile' => 'Selfie', 'object_secureValue_param_files_type_Vector t' => 'Files', 'object_secureValue_param_plain_data_type_SecurePlainData' => 'Plain data', 'object_secureValue_param_hash_type_bytes' => 'Hash', 'object_inputSecureValue' => 'Secure value', 'object_inputSecureValue_param_type_type_SecureValueType' => 'Type', 'object_inputSecureValue_param_data_type_SecureData' => 'Data', 'object_inputSecureValue_param_front_side_type_InputSecureFile' => 'Front side', 'object_inputSecureValue_param_reverse_side_type_InputSecureFile' => 'Reverse side', 'object_inputSecureValue_param_selfie_type_InputSecureFile' => 'Selfie', 'object_inputSecureValue_param_files_type_Vector t' => 'Files', 'object_inputSecureValue_param_plain_data_type_SecurePlainData' => 'Plain data', 'object_secureValueHash' => 'Secure value hash', 'object_secureValueHash_param_type_type_SecureValueType' => 'Type', 'object_secureValueHash_param_hash_type_bytes' => 'Hash', 'object_secureValueErrorData' => 'Secure value error data', 'object_secureValueErrorData_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorData_param_data_hash_type_bytes' => 'Data hash', 'object_secureValueErrorData_param_field_type_string' => 'Field', 'object_secureValueErrorData_param_text_type_string' => 'Text', 'object_secureValueErrorFrontSide' => 'Secure value error front side', 'object_secureValueErrorFrontSide_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorFrontSide_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorFrontSide_param_text_type_string' => 'Text', 'object_secureValueErrorReverseSide' => 'Secure value error reverse side', 'object_secureValueErrorReverseSide_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorReverseSide_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorReverseSide_param_text_type_string' => 'Text', 'object_secureValueErrorSelfie' => 'Secure value error selfie', 'object_secureValueErrorSelfie_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorSelfie_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorSelfie_param_text_type_string' => 'Text', 'object_secureValueErrorFile' => 'Secure value error file', 'object_secureValueErrorFile_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorFile_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorFile_param_text_type_string' => 'Text', 'object_secureValueErrorFiles' => 'Secure value error files', 'object_secureValueErrorFiles_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorFiles_param_file_hash_type_Vector t' => 'File hash', 'object_secureValueErrorFiles_param_text_type_string' => 'Text', 'object_secureCredentialsEncrypted' => 'Secure credentials encrypted', 'object_secureCredentialsEncrypted_param_data_type_bytes' => 'Data', 'object_secureCredentialsEncrypted_param_hash_type_bytes' => 'Hash', 'object_secureCredentialsEncrypted_param_secret_type_bytes' => 'Secret', 'object_account.authorizationForm' => 'Telegram passport authorization form', 'object_account.authorizationForm_param_selfie_required_type_true' => 'Selfie required?', 'object_account.authorizationForm_param_required_types_type_Vector t' => 'Required types', 'object_account.authorizationForm_param_values_type_Vector t' => 'Values', 'object_account.authorizationForm_param_errors_type_Vector t' => 'Errors', 'object_account.authorizationForm_param_users_type_Vector t' => 'Users', 'object_account.authorizationForm_param_privacy_policy_url_type_string' => 'Privacy policy URL', 'object_account.sentEmailCode' => 'Sent email code', 'object_account.sentEmailCode_param_email_pattern_type_string' => 'Email pattern', 'object_account.sentEmailCode_param_length_type_int' => 'Length', 'object_help.deepLinkInfoEmpty' => 'Empty deep link info', 'object_help.deepLinkInfo' => 'Deep link info', 'object_help.deepLinkInfo_param_update_app_type_true' => 'Update app?', 'object_help.deepLinkInfo_param_message_type_string' => 'Message', 'object_help.deepLinkInfo_param_entities_type_Vector t' => 'Entities', 'method_invokeWithMessagesRange' => 'Invoke with messages range', 'method_invokeWithMessagesRange_param_range_type_MessageRange' => 'The range', 'method_invokeWithMessagesRange_param_query_type_!X' => 'The query', 'method_invokeWithTakeout' => 'Invoke method from takeout session', 'method_invokeWithTakeout_param_takeout_id_type_long' => 'The takeout session ID', 'method_invokeWithTakeout_param_query_type_!X' => 'The query', 'method_account.initTakeoutSession' => 'Start account exporting session', 'method_account.initTakeoutSession_param_contacts_type_true' => 'Export contacts?', 'method_account.initTakeoutSession_param_message_users_type_true' => 'Export users?', 'method_account.initTakeoutSession_param_message_chats_type_true' => 'Export chats?', 'method_account.initTakeoutSession_param_message_megagroups_type_true' => 'Export supergroups?', 'method_account.initTakeoutSession_param_message_channels_type_true' => 'Export channel messages?', 'method_account.initTakeoutSession_param_files_type_true' => 'Export files?', 'method_account.initTakeoutSession_param_file_max_size_type_int' => 'Export only files smaller than this size', 'method_account.finishTakeoutSession' => 'Finish account exporting session', 'method_account.finishTakeoutSession_param_success_type_true' => 'Did the data export succeed?', 'method_contacts.getSaved' => 'Get saved contacts', 'method_messages.getSplitRanges' => 'Get message ranges to fetch', 'method_channels.getLeftChannels' => 'Get all channels you left', 'method_channels.getLeftChannels_param_offset_type_int' => 'Offset', 'object_ipPortSecret' => 'Ip port secret', 'object_ipPortSecret_param_ipv4_type_int' => 'Ipv4', 'object_ipPortSecret_param_port_type_int' => 'Port', 'object_ipPortSecret_param_secret_type_bytes' => 'Secret', 'object_accessPointRule' => 'Access point rule', 'object_accessPointRule_param_phone_prefix_rules_type_string' => 'Phone prefix rules', 'object_accessPointRule_param_dc_id_type_int' => 'DC ID', 'object_accessPointRule_param_ips_type_vector' => 'Ips', 'object_help.configSimple_param_rules_type_vector' => 'Rules', 'object_inputTakeoutFileLocation' => 'Takeout file location', 'object_savedPhoneContact' => 'Saved phone contact', 'object_savedPhoneContact_param_phone_type_string' => 'Phone', 'object_savedPhoneContact_param_first_name_type_string' => 'First name', 'object_savedPhoneContact_param_last_name_type_string' => 'Last name', 'object_savedPhoneContact_param_date_type_int' => 'Date', 'object_account.takeout' => 'Takeout', 'object_account.takeout_param_id_type_long' => 'ID', 'method_contacts.toggleTopPeers' => 'Toggle top peers', 'method_contacts.toggleTopPeers_param_enabled_type_Bool' => 'Enable or disable top peer', 'method_messages.getDialogs_param_hash_type_int' => 'IDs of previously fetched dialogs', 'method_messages.markDialogUnread' => 'Mark dialog as unread ', 'method_messages.markDialogUnread_param_unread_type_true' => 'Should it be marked or unmarked as read', 'method_messages.markDialogUnread_param_peer_type_InputDialogPeer' => 'The dialog to mark as unread', 'method_messages.getDialogUnreadMarks' => 'Get dialogs marked as unread manually', 'object_inputMediaContact_param_vcard_type_string' => 'Vcard', 'object_messageMediaContact_param_vcard_type_string' => 'Vcard', 'object_dialog_param_unread_mark_type_true' => 'Unread mark?', 'object_geoPoint_param_access_hash_type_long' => 'Access hash', 'object_messages.dialogsNotModified' => 'Dialogs not modified', 'object_messages.dialogsNotModified_param_count_type_int' => 'Count', 'object_updateDialogUnreadMark' => 'Update dialog unread mark', 'object_updateDialogUnreadMark_param_unread_type_true' => 'Unread?', 'object_updateDialogUnreadMark_param_peer_type_DialogPeer' => 'Peer', 'object_config_param_dc_txt_domain_name_type_string' => 'DC txt domain name', 'object_config_param_gif_search_username_type_string' => 'Gif search username', 'object_config_param_venue_search_username_type_string' => 'Venue search username', 'object_config_param_img_search_username_type_string' => 'Img search username', 'object_config_param_static_maps_provider_type_string' => 'Static maps provider', 'object_config_param_caption_length_max_type_int' => 'Caption length max', 'object_config_param_message_length_max_type_int' => 'Message length max', 'object_config_param_webfile_dc_id_type_int' => 'Webfile DC ID', 'object_inputBotInlineMessageMediaContact_param_vcard_type_string' => 'Vcard', 'object_botInlineMessageMediaContact_param_vcard_type_string' => 'Vcard', 'object_contacts.topPeersDisabled' => 'Top peers disabled', 'object_draftMessageEmpty_param_date_type_int' => 'Date', 'object_inputWebFileGeoPointLocation_param_access_hash_type_long' => 'Access hash', 'method_contacts.getContacts_param_hash_type_Vector t' => 'User IDs of previously cached contacts', 'method_contacts.getTopPeers_param_hash_type_Vector t' => 'Peer IDs of previously cached peers', 'method_messages.getDialogs_param_hash_type_Vector t' => 'IDs of previously fetched dialogs', 'method_messages.getHistory_param_hash_type_Vector t' => 'IDs of messages you already fetched', 'method_messages.search_param_hash_type_Vector t' => 'The IDs of messages you already fetched', 'method_messages.getStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getAllStickers_param_hash_type_Vector t' => 'The hash parameter of the previous result of this method', 'method_messages.getSavedGifs_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getFeaturedStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getRecentStickers_param_hash_type_Vector t' => 'IDs the hash parameter of the previous result of this method', 'method_messages.getMaskStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getWebPage_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getFavedStickers_param_hash_type_Vector t' => ' the hash parameter of the previous result of this method', 'method_messages.getRecentLocations_param_hash_type_Vector t' => 'IDs of locations you already fetched', 'method_messages.searchStickerSets_param_hash_type_Vector t' => 'The IDs of stickersets you already fetched', 'method_channels.getParticipants_param_hash_type_Vector t' => 'IDs of previously fetched participants', 'method_auth.checkPassword_param_password_type_InputCheckPasswordSRP' => 'You cannot use this method directly, use the complete_2fa_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_account.getPasswordSettings_param_password_type_InputCheckPasswordSRP' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'method_account.updatePasswordSettings_param_password_type_InputCheckPasswordSRP' => 'You cannot use this method directly; use $MadelineProto->update_2fa($params), instead (see https://docs.madelineproto.xyz for more info)', 'method_account.getTmpPassword_param_password_type_InputCheckPasswordSRP' => 'Password', 'method_account.confirmPasswordEmail' => 'Confirm password recovery using email', 'method_account.confirmPasswordEmail_param_code_type_string' => 'Code', 'method_account.resendPasswordEmail' => 'Resend password recovery email', 'method_account.cancelPasswordEmail' => 'Cancel password recovery email', 'method_account.getContactSignUpNotification' => 'Contact signup notification setting value', 'method_account.setContactSignUpNotification' => 'Set contact sign up notification', 'method_account.setContactSignUpNotification_param_silent_type_Bool' => 'Silent?', 'method_account.getNotifyExceptions' => 'Get notification exceptions', 'method_account.getNotifyExceptions_param_compare_sound_type_true' => 'Compare sound?', 'method_account.getNotifyExceptions_param_peer_type_InputNotifyPeer' => 'Peer', 'method_contacts.getContactIDs' => 'Get contacts by IDs', 'method_contacts.getContactIDs_param_hash_type_Vector t' => 'Previously fetched IDs', 'method_contacts.deleteByPhones' => 'Delete contacts by phones', 'method_contacts.deleteByPhones_param_phones_type_Vector t' => 'Phones', 'method_messages.sendInlineBotResult_param_hide_via_type_true' => 'Hide "via @bot"', 'method_messages.clearAllDrafts' => 'Clear all drafts', 'method_messages.updatePinnedMessage' => 'Update pinned message', 'method_messages.updatePinnedMessage_param_silent_type_true' => 'Silent?', 'method_messages.updatePinnedMessage_param_peer_type_InputPeer' => 'Peer', 'method_messages.updatePinnedMessage_param_id_type_int' => 'Message ID', 'method_messages.sendVote' => 'Send vote', 'method_messages.sendVote_param_peer_type_InputPeer' => 'Peer', 'method_messages.sendVote_param_msg_id_type_int' => 'Message ID', 'method_messages.sendVote_param_options_type_Vector t' => 'Options', 'method_messages.getPollResults' => 'Get poll results', 'method_messages.getPollResults_param_peer_type_InputPeer' => 'Peer', 'method_messages.getPollResults_param_msg_id_type_int' => 'Message ID', 'method_messages.getOnlines' => 'Get online users', 'method_messages.getOnlines_param_peer_type_InputPeer' => 'Peer', 'method_messages.getStatsURL' => 'Get stats URL', 'method_messages.getStatsURL_param_peer_type_InputPeer' => 'Peer', 'method_help.getAppUpdate_param_source_type_string' => 'Source', 'method_help.getAppConfig' => 'Get app config', 'method_help.getPassportConfig' => 'Get passport config', 'method_help.getPassportConfig_param_hash_type_Vector t' => 'Hash', 'method_help.getSupportName' => 'Get support name', 'method_help.getUserInfo' => 'Get user info', 'method_help.getUserInfo_param_user_id_type_InputUser' => 'User ID', 'method_help.editUserInfo' => 'Edit user info', 'method_help.editUserInfo_param_user_id_type_InputUser' => 'User ID', 'method_help.editUserInfo_param_message_type_string' => 'Message', 'method_help.editUserInfo_param_entities_type_Vector t' => 'Entities', 'method_langpack.getLangPack_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getStrings_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getDifference_param_lang_code_type_string' => 'Lang code', 'method_langpack.getLanguages_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getLanguage' => 'Get language', 'method_langpack.getLanguage_param_lang_pack_type_string' => 'Lang pack', 'method_langpack.getLanguage_param_lang_code_type_string' => 'Lang code', 'object_inputMediaGeoLive_param_stopped_type_true' => 'Stopped?', 'object_inputMediaPoll' => 'Media poll', 'object_inputMediaPoll_param_poll_type_Poll' => 'Poll', 'object_inputPhoto_param_file_reference_type_bytes' => 'File reference', 'object_inputFileLocation_param_file_reference_type_bytes' => 'File reference', 'object_inputDocumentFileLocation_param_file_reference_type_bytes' => 'File reference', 'object_fileLocation_param_file_reference_type_bytes' => 'File reference', 'object_chatFull_param_pinned_msg_id_type_int' => 'Pinned msg ID', 'object_channelFull_param_can_view_stats_type_true' => 'Can view stats?', 'object_channelFull_param_online_count_type_int' => 'Online count', 'object_message_param_from_scheduled_type_true' => 'From scheduled?', 'object_messageMediaPoll' => 'Message media poll', 'object_messageMediaPoll_param_poll_type_Poll' => 'Poll', 'object_messageMediaPoll_param_results_type_PollResults' => 'Results', 'object_messageActionContactSignUp' => 'Message action contact sign up', 'object_photo_param_file_reference_type_bytes' => 'File reference', 'object_inputNotifyBroadcasts' => 'Notify broadcasts', 'object_inputReportReasonChildAbuse' => 'Report reason child abuse', 'object_inputReportReasonCopyright' => 'Report reason copyright', 'object_userFull_param_can_pin_message_type_true' => 'Can pin message?', 'object_userFull_param_pinned_msg_id_type_int' => 'Pinned msg ID', 'object_messages.channelMessages_param_inexact_type_true' => 'Inexact?', 'object_updateLangPackTooLong_param_lang_code_type_string' => 'Lang code', 'object_updateUserPinnedMessage' => 'Update user pinned message', 'object_updateUserPinnedMessage_param_user_id_type_int' => 'User ID', 'object_updateUserPinnedMessage_param_id_type_int' => 'ID', 'object_updateChatPinnedMessage' => 'Update chat pinned message', 'object_updateChatPinnedMessage_param_chat_id_type_int' => 'Chat ID', 'object_updateChatPinnedMessage_param_id_type_int' => 'ID', 'object_updateMessagePoll' => 'Update message poll', 'object_updateMessagePoll_param_poll_id_type_long' => 'Poll ID', 'object_updateMessagePoll_param_poll_type_Poll' => 'Poll', 'object_updateMessagePoll_param_results_type_PollResults' => 'Results', 'object_config_param_pfs_enabled_type_true' => 'Pfs enabled?', 'object_config_param_base_lang_pack_version_type_int' => 'Base lang pack version', 'object_help.appUpdate_param_popup_type_true' => 'Popup?', 'object_help.appUpdate_param_version_type_string' => 'Version', 'object_help.appUpdate_param_entities_type_Vector t' => 'Entities', 'object_help.appUpdate_param_document_type_Document' => 'Document', 'object_inputDocument_param_file_reference_type_bytes' => 'File reference', 'object_document_param_file_reference_type_bytes' => 'File reference', 'object_notifyBroadcasts' => 'Notify broadcasts', 'object_inputPrivacyKeyPhoneP2P' => 'Privacy key phone p2p', 'object_privacyKeyPhoneP2P' => 'Privacy key phone p2p', 'object_authorization_param_current_type_true' => 'Current?', 'object_authorization_param_official_app_type_true' => 'Official app?', 'object_authorization_param_password_pending_type_true' => 'Password pending?', 'object_account.password_param_has_password_type_true' => 'Has password?', 'object_account.password_param_current_algo_type_PasswordKdfAlgo' => 'Current algo', 'object_account.password_param_srp_B_type_bytes' => 'Srp b', 'object_account.password_param_srp_id_type_long' => 'Srp ID', 'object_account.password_param_new_algo_type_PasswordKdfAlgo' => 'New algo', 'object_account.password_param_new_secure_algo_type_SecurePasswordKdfAlgo' => 'New secure algo', 'object_account.passwordSettings_param_secure_settings_type_SecureSecretSettings' => 'Secure settings', 'object_account.passwordInputSettings_param_new_algo_type_PasswordKdfAlgo' => 'New algo', 'object_account.passwordInputSettings_param_new_secure_settings_type_SecureSecretSettings' => 'New secure settings', 'object_textSubscript' => 'Text subscript', 'object_textSubscript_param_text_type_RichText' => 'Text', 'object_textSuperscript' => 'Text superscript', 'object_textSuperscript_param_text_type_RichText' => 'Text', 'object_textMarked' => 'Text marked', 'object_textMarked_param_text_type_RichText' => 'Text', 'object_textPhone' => 'Text phone', 'object_textPhone_param_text_type_RichText' => 'Text', 'object_textPhone_param_phone_type_string' => 'Phone', 'object_textImage' => 'Text image', 'object_textImage_param_document_id_type_long' => 'Document ID', 'object_textImage_param_w_type_int' => 'Width', 'object_textImage_param_h_type_int' => 'Height', 'object_textAnchor' => 'Text anchor', 'object_textAnchor_param_text_type_RichText' => 'Text', 'object_textAnchor_param_name_type_string' => 'Name', 'object_pageBlockPhoto_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockPhoto_param_url_type_string' => 'URL', 'object_pageBlockPhoto_param_webpage_id_type_long' => 'Webpage ID', 'object_pageBlockVideo_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockEmbed_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockEmbedPost_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockCollage_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockSlideshow_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockAudio_param_caption_type_PageCaption' => 'Caption', 'object_pageBlockKicker' => 'Page block kicker', 'object_pageBlockKicker_param_text_type_RichText' => 'Text', 'object_pageBlockTable' => 'Page block table', 'object_pageBlockTable_param_bordered_type_true' => 'Bordered?', 'object_pageBlockTable_param_striped_type_true' => 'Striped?', 'object_pageBlockTable_param_title_type_RichText' => 'Title', 'object_pageBlockTable_param_rows_type_Vector t' => 'Rows', 'object_pageBlockOrderedList' => 'Page block ordered list', 'object_pageBlockOrderedList_param_items_type_Vector t' => 'Items', 'object_pageBlockDetails' => 'Page block details', 'object_pageBlockDetails_param_open_type_true' => 'Open?', 'object_pageBlockDetails_param_blocks_type_Vector t' => 'Blocks', 'object_pageBlockDetails_param_title_type_RichText' => 'Title', 'object_pageBlockRelatedArticles' => 'Page block related articles', 'object_pageBlockRelatedArticles_param_title_type_RichText' => 'Title', 'object_pageBlockRelatedArticles_param_articles_type_Vector t' => 'Articles', 'object_pageBlockMap' => 'Page block map', 'object_pageBlockMap_param_geo_type_GeoPoint' => 'Geo', 'object_pageBlockMap_param_zoom_type_int' => 'Zoom', 'object_pageBlockMap_param_w_type_int' => 'Width', 'object_pageBlockMap_param_h_type_int' => 'Height', 'object_pageBlockMap_param_caption_type_PageCaption' => 'Caption', 'object_phoneCall_param_p2p_allowed_type_true' => 'P2p allowed?', 'object_langPackLanguage_param_official_type_true' => 'Official?', 'object_langPackLanguage_param_rtl_type_true' => 'Rtl?', 'object_langPackLanguage_param_beta_type_true' => 'Beta?', 'object_langPackLanguage_param_base_lang_code_type_string' => 'Base lang code', 'object_langPackLanguage_param_plural_code_type_string' => 'Plural code', 'object_langPackLanguage_param_strings_count_type_int' => 'Strings count', 'object_langPackLanguage_param_translated_count_type_int' => 'Translated count', 'object_langPackLanguage_param_translations_url_type_string' => 'Translations URL', 'object_secureValue_param_translation_type_Vector t' => 'Translation', 'object_inputSecureValue_param_translation_type_Vector t' => 'Translation', 'object_secureValueError' => 'Secure value error', 'object_secureValueError_param_type_type_SecureValueType' => 'Type', 'object_secureValueError_param_hash_type_bytes' => 'Hash', 'object_secureValueError_param_text_type_string' => 'Text', 'object_secureValueErrorTranslationFile' => 'Secure value error translation file', 'object_secureValueErrorTranslationFile_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorTranslationFile_param_file_hash_type_bytes' => 'File hash', 'object_secureValueErrorTranslationFile_param_text_type_string' => 'Text', 'object_secureValueErrorTranslationFiles' => 'Secure value error translation files', 'object_secureValueErrorTranslationFiles_param_type_type_SecureValueType' => 'Type', 'object_secureValueErrorTranslationFiles_param_file_hash_type_Vector t' => 'File hash', 'object_secureValueErrorTranslationFiles_param_text_type_string' => 'Text', 'object_passwordKdfAlgoUnknown' => 'Password kdf algo unknown', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow' => 'Password kdf algo sha256sha256pbkdf2hmacsh a512iter100000 sha256 mod pow', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_salt1_type_bytes' => 'Salt1', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_salt2_type_bytes' => 'Salt2', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_g_type_int' => 'G', 'object_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow_param_p_type_bytes' => 'P', 'object_securePasswordKdfAlgoUnknown' => 'Secure password kdf algo unknown', 'object_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000' => 'Secure password kdf algo pbkdf2hmacsh a512iter100000', 'object_securePasswordKdfAlgoPBKDF2HMACSHA512iter100000_param_salt_type_bytes' => 'Salt', 'object_securePasswordKdfAlgoSHA512' => 'Secure password kdf algo sha512', 'object_securePasswordKdfAlgoSHA512_param_salt_type_bytes' => 'Salt', 'object_secureSecretSettings' => 'Secure secret settings', 'object_secureSecretSettings_param_secure_algo_type_SecurePasswordKdfAlgo' => 'Secure algo', 'object_secureSecretSettings_param_secure_secret_type_bytes' => 'Secure secret', 'object_secureSecretSettings_param_secure_secret_id_type_long' => 'Secure secret ID', 'object_inputCheckPasswordEmpty' => 'Empty input check password', 'object_inputCheckPasswordSRP' => 'Check password srp', 'object_inputCheckPasswordSRP_param_srp_id_type_long' => 'Srp ID', 'object_inputCheckPasswordSRP_param_A_type_bytes' => 'A', 'object_inputCheckPasswordSRP_param_M1_type_bytes' => 'M1', 'object_secureRequiredType' => 'Secure required type', 'object_secureRequiredType_param_native_names_type_true' => 'Native names?', 'object_secureRequiredType_param_selfie_required_type_true' => 'Selfie required?', 'object_secureRequiredType_param_translation_required_type_true' => 'Translation required?', 'object_secureRequiredType_param_type_type_SecureValueType' => 'Type', 'object_secureRequiredTypeOneOf' => 'Secure required type one of', 'object_secureRequiredTypeOneOf_param_types_type_Vector t' => 'Types', 'object_help.passportConfigNotModified' => 'Passport config not modified', 'object_help.passportConfig' => 'Passport config', 'object_help.passportConfig_param_hash_type_int' => 'Hash', 'object_help.passportConfig_param_countries_langs_type_DataJSON' => 'Countries langs', 'object_inputAppEvent_param_data_type_JSONValue' => 'Data', 'object_jsonObjectValue' => 'Json object value', 'object_jsonObjectValue_param_key_type_string' => 'Key', 'object_jsonObjectValue_param_value_type_JSONValue' => 'Value', 'object_jsonNull' => 'Json null', 'object_jsonBool' => 'Json bool', 'object_jsonBool_param_value_type_Bool' => 'Value?', 'object_jsonNumber' => 'Json number', 'object_jsonNumber_param_value_type_double' => 'Value', 'object_jsonString' => 'Json string', 'object_jsonString_param_value_type_string' => 'Value', 'object_jsonArray' => 'Json array', 'object_jsonArray_param_value_type_Vector t' => 'Value', 'object_jsonObject' => 'Json object', 'object_jsonObject_param_value_type_Vector t' => 'Value', 'object_pageTableCell' => 'Page table cell', 'object_pageTableCell_param_header_type_true' => 'Header?', 'object_pageTableCell_param_align_center_type_true' => 'Align center?', 'object_pageTableCell_param_align_right_type_true' => 'Align right?', 'object_pageTableCell_param_valign_middle_type_true' => 'Valign middle?', 'object_pageTableCell_param_valign_bottom_type_true' => 'Valign bottom?', 'object_pageTableCell_param_text_type_RichText' => 'Text', 'object_pageTableCell_param_colspan_type_int' => 'Colspan', 'object_pageTableCell_param_rowspan_type_int' => 'Rowspan', 'object_pageTableRow' => 'Page table row', 'object_pageTableRow_param_cells_type_Vector t' => 'Cells', 'object_pageCaption' => 'Page caption', 'object_pageCaption_param_text_type_RichText' => 'Text', 'object_pageCaption_param_credit_type_RichText' => 'Credit', 'object_pageListItemText' => 'Page list item text', 'object_pageListItemText_param_text_type_RichText' => 'Text', 'object_pageListItemBlocks' => 'Page list item blocks', 'object_pageListItemBlocks_param_blocks_type_Vector t' => 'Blocks', 'object_pageListOrderedItemText' => 'Page list ordered item text', 'object_pageListOrderedItemText_param_num_type_string' => 'Num', 'object_pageListOrderedItemText_param_text_type_RichText' => 'Text', 'object_pageListOrderedItemBlocks' => 'Page list ordered item blocks', 'object_pageListOrderedItemBlocks_param_num_type_string' => 'Num', 'object_pageListOrderedItemBlocks_param_blocks_type_Vector t' => 'Blocks', 'object_pageRelatedArticle' => 'Page related article', 'object_pageRelatedArticle_param_url_type_string' => 'URL', 'object_pageRelatedArticle_param_webpage_id_type_long' => 'Webpage ID', 'object_pageRelatedArticle_param_title_type_string' => 'Title', 'object_pageRelatedArticle_param_description_type_string' => 'Description', 'object_pageRelatedArticle_param_photo_id_type_long' => 'Photo ID', 'object_pageRelatedArticle_param_author_type_string' => 'Author', 'object_pageRelatedArticle_param_published_date_type_int' => 'Published date', 'object_page' => 'Page', 'object_page_param_part_type_true' => 'Part?', 'object_page_param_rtl_type_true' => 'Rtl?', 'object_page_param_v2_type_true' => 'V2?', 'object_page_param_url_type_string' => 'URL', 'object_page_param_blocks_type_Vector t' => 'Blocks', 'object_page_param_photos_type_Vector t' => 'Photos', 'object_page_param_documents_type_Vector t' => 'Documents', 'object_help.supportName' => 'Support name', 'object_help.supportName_param_name_type_string' => 'Name', 'object_help.userInfoEmpty' => 'Empty user info', 'object_help.userInfo' => 'User info', 'object_help.userInfo_param_message_type_string' => 'Message', 'object_help.userInfo_param_entities_type_Vector t' => 'Entities', 'object_help.userInfo_param_author_type_string' => 'Author', 'object_help.userInfo_param_date_type_int' => 'Date', 'object_pollAnswer' => 'Poll answer', 'object_pollAnswer_param_text_type_string' => 'Text', 'object_pollAnswer_param_option_type_bytes' => 'Option', 'object_poll' => 'Poll', 'object_poll_param_id_type_long' => 'ID', 'object_poll_param_closed_type_true' => 'Closed?', 'object_poll_param_question_type_string' => 'Question', 'object_poll_param_answers_type_Vector t' => 'Answers', 'object_pollAnswerVoters' => 'Poll answer voters', 'object_pollAnswerVoters_param_chosen_type_true' => 'Chosen?', 'object_pollAnswerVoters_param_option_type_bytes' => 'Option', 'object_pollAnswerVoters_param_voters_type_int' => 'Voters', 'object_pollResults' => 'Poll results', 'object_pollResults_param_min_type_true' => 'Min?', 'object_pollResults_param_results_type_Vector t' => 'Results', 'object_pollResults_param_total_voters_type_int' => 'Total voters', 'object_chatOnlines' => 'Chat onlines', 'object_chatOnlines_param_onlines_type_int' => 'Onlines', 'object_statsURL' => 'Stats URL', 'object_statsURL_param_url_type_string' => 'URL', 'method_auth.sendCode_param_settings_type_CodeSettings' => 'You cannot use this method directly, use the phone_login method instead (see https://docs.madelineproto.xyz for more info)', 'method_account.getWallPapers_param_hash_type_Vector t' => 'IDs of previously fetched wallpapers', 'method_account.sendChangePhoneCode_param_settings_type_CodeSettings' => 'Code settings', 'method_account.sendConfirmPhoneCode_param_settings_type_CodeSettings' => 'Code settings', 'method_account.sendVerifyPhoneCode_param_settings_type_CodeSettings' => 'Code settings', 'method_account.getWallPaper' => 'Get wallpaper info', 'method_account.getWallPaper_param_wallpaper_type_InputWallPaper' => 'Wallpaper', 'method_account.uploadWallPaper' => 'Upload wallpaper', 'method_account.uploadWallPaper_param_file_type_InputFile' => 'Image', 'method_account.uploadWallPaper_param_mime_type_type_string' => 'Mime type', 'method_account.uploadWallPaper_param_settings_type_WallPaperSettings' => 'Wallpaper settings', 'method_account.saveWallPaper' => 'Save wallpaper', 'method_account.saveWallPaper_param_wallpaper_type_InputWallPaper' => 'The wallpaper to save', 'method_account.saveWallPaper_param_unsave_type_Bool' => 'Delete saved wallpaper', 'method_account.saveWallPaper_param_settings_type_WallPaperSettings' => 'The wallpaper to save', 'method_account.installWallPaper' => 'Install wallpaper', 'method_account.installWallPaper_param_wallpaper_type_InputWallPaper' => 'Wallpaper to install', 'method_account.installWallPaper_param_settings_type_WallPaperSettings' => 'Wallpaper settings', 'method_account.resetWallPapers' => 'Reset wallpapers', 'method_messages.exportChatInvite_param_peer_type_InputPeer' => 'Export invite only for this user', 'method_messages.editChatAbout' => 'Edit chat info', 'method_messages.editChatAbout_param_peer_type_InputPeer' => 'Chat', 'method_messages.editChatAbout_param_about_type_string' => 'Info', 'method_messages.editChatDefaultBannedRights' => 'Edit default rights of chat', 'method_messages.editChatDefaultBannedRights_param_peer_type_InputPeer' => 'Chat', 'method_messages.editChatDefaultBannedRights_param_banned_rights_type_ChatBannedRights' => 'Global chat rights', 'method_channels.editAdmin_param_admin_rights_type_ChatAdminRights' => 'Admin rights', 'method_channels.editBanned_param_banned_rights_type_ChatBannedRights' => 'Banned rights', 'object_chat_param_admin_rights_type_ChatAdminRights' => 'Admin rights of current user', 'object_chat_param_default_banned_rights_type_ChatBannedRights' => 'Global chat banned rights', 'object_channel_param_admin_rights_type_ChatAdminRights' => 'Admin rights of current user', 'object_channel_param_banned_rights_type_ChatBannedRights' => 'Banned rights of current user', 'object_channel_param_default_banned_rights_type_ChatBannedRights' => 'Global chat banned rights', 'object_chatFull_param_can_set_username_type_true' => 'Can set username?', 'object_chatFull_param_about_type_string' => 'Chat about', 'object_photoStrippedSize' => 'Stripped size', 'object_photoStrippedSize_param_type_type_string' => 'Stripped size', 'object_photoStrippedSize_param_bytes_type_bytes' => 'Bytes', 'object_wallPaper_param_id_type_long' => 'ID', 'object_wallPaper_param_creator_type_true' => 'Am I the creator?', 'object_wallPaper_param_default_type_true' => 'Default?', 'object_wallPaper_param_pattern_type_true' => 'Pattern', 'object_wallPaper_param_dark_type_true' => 'Dark?', 'object_wallPaper_param_access_hash_type_long' => 'Hash', 'object_wallPaper_param_slug_type_string' => 'Slug?', 'object_wallPaper_param_document_type_Document' => 'Wallpaper', 'object_wallPaper_param_settings_type_WallPaperSettings' => 'Wallpaper settings', 'object_messages.messagesSlice_param_inexact_type_true' => 'Inexact?', 'object_updateChatDefaultBannedRights' => 'Global chat rights updated', 'object_updateChatDefaultBannedRights_param_peer_type_Peer' => 'Peer', 'object_updateChatDefaultBannedRights_param_default_banned_rights_type_ChatBannedRights' => 'Global chat rights', 'object_updateChatDefaultBannedRights_param_version_type_int' => 'Version', 'object_document_param_thumbs_type_Vector t' => 'Thumbnails', 'object_channelParticipantAdmin_param_self_type_true' => 'Is this the current user?', 'object_channelParticipantAdmin_param_admin_rights_type_ChatAdminRights' => 'Admin rights', 'object_channelParticipantBanned_param_banned_rights_type_ChatBannedRights' => 'Banned rights', 'object_channelParticipantsContacts' => 'Contacts', 'object_channelParticipantsContacts_param_q_type_string' => 'Query', 'object_channelAdminLogEventActionDefaultBannedRights' => 'Changed global chat rights', 'object_channelAdminLogEventActionDefaultBannedRights_param_prev_banned_rights_type_ChatBannedRights' => 'Previous Banned rights of current user', 'object_channelAdminLogEventActionDefaultBannedRights_param_new_banned_rights_type_ChatBannedRights' => 'New Banned rights of current user', 'object_channelAdminLogEventActionStopPoll' => 'Stopped poll', 'object_channelAdminLogEventActionStopPoll_param_message_type_Message' => 'Message', 'object_chatAdminRights' => 'Admin rights', 'object_chatAdminRights_param_change_info_type_true' => 'Can change info?', 'object_chatAdminRights_param_post_messages_type_true' => 'Can post messages?', 'object_chatAdminRights_param_edit_messages_type_true' => 'Can edit messages?', 'object_chatAdminRights_param_delete_messages_type_true' => 'Can delete messages?', 'object_chatAdminRights_param_ban_users_type_true' => 'Can ban users?', 'object_chatAdminRights_param_invite_users_type_true' => 'Can invite users?', 'object_chatAdminRights_param_pin_messages_type_true' => 'Can pin messages?', 'object_chatAdminRights_param_add_admins_type_true' => 'Can add other admins?', 'object_chatBannedRights' => 'Banned rights (when true, the user will NOT be able to do that thing)', 'object_chatBannedRights_param_view_messages_type_true' => 'Can view messages?', 'object_chatBannedRights_param_send_messages_type_true' => 'Can send messages?', 'object_chatBannedRights_param_send_media_type_true' => 'Can send media?', 'object_chatBannedRights_param_send_stickers_type_true' => 'Can send stickers?', 'object_chatBannedRights_param_send_gifs_type_true' => 'Can send gifs?', 'object_chatBannedRights_param_send_games_type_true' => 'Can send games?', 'object_chatBannedRights_param_send_inline_type_true' => 'Can use inline bots?', 'object_chatBannedRights_param_embed_links_type_true' => 'Can embed links?', 'object_chatBannedRights_param_send_polls_type_true' => 'Can send polls?', 'object_chatBannedRights_param_change_info_type_true' => 'Can change info?', 'object_chatBannedRights_param_invite_users_type_true' => 'Can invite users?', 'object_chatBannedRights_param_pin_messages_type_true' => 'Can pin messages?', 'object_chatBannedRights_param_until_date_type_int' => 'Until date (0 = forever)', 'object_inputWallPaper' => 'Wallpaper', 'object_inputWallPaper_param_id_type_long' => 'ID', 'object_inputWallPaper_param_access_hash_type_long' => 'Access hash', 'object_inputWallPaperSlug' => 'Wallpaper slug', 'object_inputWallPaperSlug_param_slug_type_string' => 'Type', 'object_account.wallPapersNotModified' => 'No wallpapers were modified', 'object_account.wallPapers' => 'Wallpapers', 'object_account.wallPapers_param_hash_type_int' => 'Hash', 'object_account.wallPapers_param_wallpapers_type_Vector t' => 'Wallpapers', 'object_codeSettings' => 'Code settings', 'object_codeSettings_param_allow_flashcall_type_true' => 'Allow flashcal?', 'object_codeSettings_param_current_number_type_true' => 'Current number?', 'object_codeSettings_param_app_hash_persistent_type_true' => 'Persistent hash?', 'object_codeSettings_param_app_hash_type_string' => 'Hash type', 'object_wallPaperSettings' => 'Wallpaper settings', 'object_wallPaperSettings_param_blur_type_true' => 'Blur?', 'object_wallPaperSettings_param_motion_type_true' => 'Motion?', 'object_wallPaperSettings_param_background_color_type_int' => 'Background color', 'object_wallPaperSettings_param_intensity_type_int' => 'Intensity', 'object_inputPrivacyKeyProfilePhoto' => 'Can his profile photo be viewed?', 'object_inputPrivacyKeyForwards' => 'Can his messages be forwarded?', 'method_account.getAutoDownloadSettings' => 'Get autodownload settings', 'method_account.saveAutoDownloadSettings' => 'Save autodownload settings', 'method_account.saveAutoDownloadSettings_param_low_type_true' => 'Low preset', 'method_account.saveAutoDownloadSettings_param_high_type_true' => 'High preset', 'method_account.saveAutoDownloadSettings_param_settings_type_AutoDownloadSettings' => 'Autodownload settings', 'method_messages.deleteHistory_param_revoke_type_true' => 'Delete messages for the other user', 'method_messages.getStatsURL_param_dark_type_true' => 'Dark?', 'method_messages.getStatsURL_param_params_type_string' => 'Params', 'method_messages.getEmojiKeywords' => 'Get emoji keywords', 'method_messages.getEmojiKeywords_param_lang_code_type_string' => 'Language code', 'method_messages.getEmojiKeywordsDifference' => 'Get emoji keyword difference', 'method_messages.getEmojiKeywordsDifference_param_lang_code_type_string' => 'Language code', 'method_messages.getEmojiKeywordsDifference_param_from_version_type_int' => 'From version', 'method_messages.getEmojiURL' => 'Get emoji URL', 'method_messages.getEmojiURL_param_lang_code_type_string' => 'Language code', 'method_phone.setCallRating_param_user_initiative_type_true' => 'User initiative', 'method_langpack.getDifference_param_lang_pack_type_string' => 'Language pack', 'object_user_param_support_type_true' => 'Is this a support user?', 'object_updateChatPinnedMessage_param_version_type_int' => 'Version', 'object_privacyKeyForwards' => 'Forwards privacy key', 'object_privacyKeyProfilePhoto' => 'Show profile photo?', 'object_stickerSet_param_thumb_type_PhotoSize' => 'Thumbnail', 'object_messageFwdHeader_param_from_name_type_string' => 'Author of the original message', 'object_autoDownloadSettings' => 'Autodownload settings', 'object_autoDownloadSettings_param_disabled_type_true' => 'Disabled?', 'object_autoDownloadSettings_param_video_preload_large_type_true' => 'Preload large videos?', 'object_autoDownloadSettings_param_audio_preload_next_type_true' => 'Preload audios?', 'object_autoDownloadSettings_param_phonecalls_less_data_type_true' => 'Use less data in phonecalls?', 'object_autoDownloadSettings_param_photo_size_max_type_int' => 'Maximum photo file size to preload', 'object_autoDownloadSettings_param_video_size_max_type_int' => 'Maximum video file size to preload', 'object_autoDownloadSettings_param_file_size_max_type_int' => 'Maximum file size to preload', 'object_account.autoDownloadSettings' => 'Autodownload settings', 'object_account.autoDownloadSettings_param_low_type_AutoDownloadSettings' => 'Low preset?', 'object_account.autoDownloadSettings_param_medium_type_AutoDownloadSettings' => 'Medium preset?', 'object_account.autoDownloadSettings_param_high_type_AutoDownloadSettings' => 'High preset?', 'object_emojiKeyword' => 'Emoji keyword', 'object_emojiKeyword_param_keyword_type_string' => 'Keyword', 'object_emojiKeyword_param_emoticons_type_Vector t' => 'Emoticons', 'object_emojiKeywordDeleted' => 'Deleted emoji keyword', 'object_emojiKeywordDeleted_param_keyword_type_string' => 'Keyword', 'object_emojiKeywordDeleted_param_emoticons_type_Vector t' => 'Emoticons', 'object_emojiKeywordsDifference' => 'Emoji keword difference', 'object_emojiKeywordsDifference_param_lang_code_type_string' => 'Language code', 'object_emojiKeywordsDifference_param_from_version_type_int' => 'Previous version', 'object_emojiKeywordsDifference_param_version_type_int' => 'Current version', 'object_emojiKeywordsDifference_param_keywords_type_Vector t' => 'Keywords', 'object_emojiURL' => 'Emoji URL', 'object_emojiURL_param_url_type_string' => 'URL', ); } <?php /** * DocsBuilder module. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class DocsBuilder { use \danog\MadelineProto\TL\TL; use \danog\MadelineProto\DocsBuilder\Methods; use \danog\MadelineProto\DocsBuilder\Constructors; use Tools; public $td = false; public function __construct($logger, $settings) { $this->logger = $logger; set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); $this->construct_TL($settings['tl_schema']); if (isset($settings['tl_schema']['td']) && !isset($settings['tl_schema']['telegram'])) { $this->constructors = $this->td_constructors; $this->methods = $this->td_methods; $this->td = true; } $this->settings = $settings; if (!file_exists($this->settings['output_dir'])) { mkdir($this->settings['output_dir']); } chdir($this->settings['output_dir']); $this->index = $settings['readme'] ? 'README.md' : 'index.md'; } public $types = []; public $any = '*'; public function end($what) { return end($what); } public function escape($hwat) { return str_replace('_', '\\_', $hwat); } public function mk_docs() { \danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE); file_put_contents($this->index, '--- title: '.$this->settings['title'].' description: '.$this->settings['description'].' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # '.$this->settings['description'].' [Back to main documentation](..) [Methods](methods/) [Constructors](constructors/) [Types](types/)'); $this->mk_methodS(); $this->mk_constructors(); foreach (glob('types/*') as $unlink) { unlink($unlink); } if (file_exists('types')) { rmdir('types'); } mkdir('types'); ksort($this->types); $index = ''; \danog\MadelineProto\Logger::log('Generating types documentation...', \danog\MadelineProto\Logger::NOTICE); $last_namespace = ''; foreach ($this->types as $otype => $keys) { $new_namespace = preg_replace('/_.*/', '', $otype); //$br = $new_namespace != $last_namespace ? '***<br><br>' : ''; $type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $otype); $type = preg_replace('/.*_of_/', '', $type); $index .= '['.str_replace('_', '\\_', $type).']('.$type.'.md)<a name="'.$type.'"></a> '; $constructors = ''; foreach ($keys['constructors'] as $data) { $predicate = str_replace('.', '_', $data['predicate']).(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : ''); $md_predicate = str_replace('_', '\\_', $predicate); $constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md) '; } $methods = ''; foreach ($keys['methods'] as $data) { $name = str_replace('.', '_', $data['method']); $md_name = str_replace('_', '->', $name); $methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md) '; } $description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of typr '.$type; $header = '--- title: '.$type.' description: constructors and methods of type '.$type.' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Type: '.str_replace('_', '\\_', $type).' [Back to types index](index.md) '; $header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : ''; if (!isset($this->settings['td'])) { if (in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) { $header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id. The following syntaxes can also be used: ``` $'.$type." = '@username'; // Username \$".$type." = 'me'; // The currently logged-in user \$".$type.' = 44700; // bot API id (users) $'.$type.' = -492772765; // bot API id (chats) $'.$type.' = -10038575794; // bot API id (channels) $'.$type." = 'https://t.me/danogentili'; // t.me URLs \$".$type." = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links \$".$type." = 'user#44700'; // tg-cli style id (users) \$".$type." = 'chat#492772765'; // tg-cli style id (chats) \$".$type." = 'channel#38575794'; // tg-cli style id (channels) ``` A [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n"; } if (in_array($type, ['InputEncryptedChat'])) { $header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id. The following syntax can also be used: ``` $'.$type.' = -147286699; // Numeric chat id returned by request_secret_chat, can be positive or negative ``` '; } if (in_array($type, ['InputFile', 'InputEncryptedFile'])) { $header .= 'The following syntax can also be used: ``` $'.$type.' = \'filename.mp4\'; // The file path can also be used ``` '; } if (in_array($type, ['InputPhoto'])) { $header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Photo](Photo.md) here, MadelineProto will automatically convert it to the right type. '; } if (in_array($type, ['InputDocument'])) { $header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Document](Document.md) here, MadelineProto will automatically convert it to the right type. '; } if (in_array($type, ['InputMedia'])) { $header .= 'You can also provide a [MessageMedia](MessageMedia.md), [Message](Message.md), [Update](Update.md), [Document](Document.md), [Photo](Photo.md), [InputDocument](InputDocument.md), [InputPhoto](InputPhoto.md) here, MadelineProto will automatically convert it to the right type. '; } if (in_array($type, ['InputMessage'])) { $header .= 'The following syntax can also be used: ``` $'.$type.' = 142; // Numeric message ID ``` '; } if (in_array($type, ['KeyboardButton'])) { $header .= 'Clicking these buttons: To click these buttons simply run the `click` method: ``` $result = $'.$type.'->click(); ``` `$result` can be one of the following: * A string - If the button is a keyboardButtonUrl * [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard * [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned * `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually You can also access the properties of the constructor as a normal array, for example $button[\'name\'] '; } } $constructors = '### Possible values (constructors): '.$constructors.' '; $methods = '### Methods that return an object of this type (methods): '.$methods.' '; if (!isset($this->settings['td'])) { if (in_array($type, ['PhoneCall'])) { $methods = ''; $constructors = ''; $header .= 'This is an object of type `\\danog\\MadelineProto\\VoIP`. It will only be available if the [php-libtgvoip](https://github.com/danog/php-libtgvoip) extension is installed, see [the main docs](https://docs.madelineproto.xyz#calls) for an easy installation script. You MUST know [OOP](http://php.net/manual/en/language.oop5.php) to use this class. ## Constants: VoIPController states (these constants are incrementing integers, thus can be compared like numbers): * `STATE_CREATED` - controller created * `STATE_WAIT_INIT` - controller inited * `STATE_WAIT_INIT_ACK` - controller inited * `STATE_ESTABLISHED` - connection established * `STATE_FAILED` - connection failed * `STATE_RECONNECTING` - reconnecting VoIPController errors: * `TGVOIP_ERROR_UNKNOWN` - An unknown error occurred * `TGVOIP_ERROR_INCOMPATIBLE` - The other side is using an unsupported client/protocol * `TGVOIP_ERROR_TIMEOUT` - A timeout occurred * `TGVOIP_ERROR_AUDIO_IO` - An I/O error occurred Network types (these constants are incrementing integers, thus can be compared like numbers): * `NET_TYPE_UNKNOWN` - Unknown network type * `NET_TYPE_GPRS` - GPRS connection * `NET_TYPE_EDGE` - EDGE connection * `NET_TYPE_3G` - 3G connection * `NET_TYPE_HSPA` - HSPA connection * `NET_TYPE_LTE` - LTE connection * `NET_TYPE_WIFI` - WIFI connection * `NET_TYPE_ETHERNET` - Ethernet connection (this guarantees high audio quality) * `NET_TYPE_OTHER_HIGH_SPEED` - Other high speed connection * `NET_TYPE_OTHER_LOW_SPEED` - Other low speed connection * `NET_TYPE_DIALUP` - Dialup connection * `NET_TYPE_OTHER_MOBILE` - Other mobile network connection Data saving modes (these constants are incrementing integers, thus can be compared like numbers): * `DATA_SAVING_NEVER` - Never save data (this guarantees high audio quality) * `DATA_SAVING_MOBILE` - Use mobile data saving profiles * `DATA_SAVING_ALWAYS` - Always use data saving profiles Proxy settings (these constants are incrementing integers, thus can be compared like numbers): * `PROXY_NONE` - No proxy * `PROXY_SOCKS5` - Use the socks5 protocol Audio states (these constants are incrementing integers, thus can be compared like numbers): * `AUDIO_STATE_NONE` - The audio module was not created yet * `AUDIO_STATE_CREATED` - The audio module was created * `AUDIO_STATE_CONFIGURED` - The audio module was configured * `AUDIO_STATE_RUNNING` - The audio module is running Call states (these constants are incrementing integers, thus can be compared like numbers): * `CALL_STATE_NONE` - The call was not created yet * `CALL_STATE_REQUESTED` - This is an outgoing call * `CALL_STATE_INCOMING` - This is an incoming call * `CALL_STATE_ACCEPTED` - The incoming call was accepted, but not yet ready * `CALL_STATE_CONFIRMED` - The outgoing call was accepted, but not yet ready * `CALL_STATE_READY` - The call is ready. Audio data is being sent and received * `CALL_STATE_ENDED` - The call is over. ## Methods: * `getState()` - Gets the controller state, as a VoIPController state constant * `getCallState()` - Gets the call state, as a call state constant * `getVisualization()` - Gets the visualization of the encryption key, as an array of emojis, can be called only when the call state is bigger than or equal to `CALL_STATE_READY`. If called sooner, returns false. * `getStats()` Gets connection stats * `getOtherID()` - Gets the id of the other call participant, as a bot API ID * `getProtocol()` - Gets the protocol used by the current call, as a [PhoneCallProtocol](https://docs.madelineproto.xyz/API_docs/types/PhoneCallProtocol.html) object * `getCallID()` - Gets the call ID, as an [InputPhoneCall](https://docs.madelineproto.xyz/API_docs/types/InputPhoneCall.html) object * `isCreator()` - Returns a boolean that indicates whether you are the creator of the call * `whenCreated()` - Returns the unix timestamp of when the call was started (when was the call state set to `CALL_STATE_READY`) * `getOutputState()` - Returns the state of the audio output module, as an audio state constant * `getInputState()` - Returns the state of the audio input module, as an audio state constant * `getDebugLog()` - Gets VoIPController debug log * `getDebugString()` - Gets VoIPController debug string * `getLastError()` - Gets the last error as a VoIPController error constant * `getVersion()` - Gets VoIPController version * `getSignalBarsCount()` - Gets number of signal bars (0-4) * `parseConfig()` - Parses the configuration * `accept()` - Accepts the phone call, returns `$this` * `discard($reason = ["_" => "phoneCallDiscardReasonDisconnect"], $rating = [])` - Ends the phone call. Accepts two optional parameters: `$reason` - can be a [PhoneCallDiscardReason](https://docs.madelineproto.xyz/API_docs/types/PhoneCallDiscardReason.html) object (defaults to a [phoneCallDiscardReasonDisconnect](https://docs.madelineproto.xyz/API_docs/constructors/phoneCallDiscardReasonDisconnect.html) object). `$rating` - Can be an array that must contain a rating, and a comment (`["rating" => 5, "comment" => "MadelineProto is very easy to use!"]). Defaults to an empty array.` * `getOutputParams()` - Returns the output audio configuration MadelineProto works using raw signed PCM audio, internally split in packets with `sampleNumber` samples. The audio configuration is an array structured in the following way: ``` [ "bitsPerSample" => int. // Bits in each PCM sample "sampleRate" => int, // PCM sample rate "channels" => int, // Number of PCM audio channels "sampleNumber" => int, // The audio data is internally split in packets, each having this number of samples "samplePeriod" => double, // PCM sample period in seconds, useful if you want to generate audio data manually "writePeriod" => double, // PCM write period in seconds (samplePeriod*sampleNumber), useful if you want to generate audio data manually "samplesSize" => int, // The audio data is internally split in packets, each having this number of bytes (sampleNumber*bitsPerSample/8) "level" => int // idk ]; ``` * `getInputParams()` - Returns the input audio configuration MadelineProto works using raw signed PCM audio, internally split in packets with `sampleNumber` samples. The audio configuration is an array structured in the following way: ``` [ "bitsPerSample" => int. // Bits in each PCM sample "sampleRate" => int, // PCM sample rate "channels" => int, // Number of PCM audio channels "sampleNumber" => int, // The audio data is internally split in packets, each having this number of samples "samplePeriod" => double, // PCM sample period in seconds, useful if you want to generate audio data manually "writePeriod" => double, // PCM write period in seconds (samplePeriod*sampleNumber), useful if you want to generate audio data manually "samplesSize" => int, // The audio data is internally split in packets, each having this number of bytes (sampleNumber*bitsPerSample/8) ]; ``` * `play(string $file)` and `then(string $file)` - Play a certain audio file encoded in PCM, with the audio input configuration, returns `$this` * `playOnHold(array $files)` - Array of audio files encoded in PCM, with the audio input configuration to loop on hold (when the files given with play/then have finished playing). If not called, no data will be played, returns `$this` * `isPlaying()` - Returns true if MadelineProto is still playing the files given with play/then, false if the hold files (or nothing) is being played * `setMicMute(bool $mute)` - Stops/resumes playing files/hold files, returns `$this` * `setOutputFile(string $outputfile)` - Writes incoming audio data to file encoded in PCM, with the audio output configuration, returns `$this` * `unsetOutputFile()` - Stops writing audio data to previously set file, returns `$this` ## Properties: * `storage`: An array that can be used to store data related to this call. Easy as pie: ``` $call->storage["pony"] = "fluttershy"; \danog\MadelineProto\Logger::log($call->storage["pony"]); // fluttershy ``` Note: when modifying this property, *never* overwrite the previous values. Always either modify the values of the array separately like showed above, or use array_merge. * `configuration`: An array containing the libtgvoip configuration. You can only modify the data saving mode, the network type, the logging file path and the stats dump file path: Example: ``` $call->configuration["log_file_path"] = "logs".$call->getOtherID().".log"; // Default is /dev/null $call->configuration["stats_dump_file_path"] = "stats".$call->getOtherID().".log"; // Default is /dev/null $call->configuration["network_type"] = \\danog\\MadelineProto\\VoIP::NET_TYPE_WIFI; // Default is NET_TYPE_ETHERNET $call->configuration["data_saving"] = \\danog\\MadelineProto\\VoIP::DATA_SAVING_MOBILE; // Default is DATA_SAVING_NEVER $call->parseConfig(); // Always call this after changing settings ``` Note: when modifying this property, *never* overwrite the previous values. Always either modify the values of the array separately like showed above, or use array_merge. After modifying it, you must always parse the new configuration with a call to `parseConfig`. '; } } if (file_exists('types/'.$type.'.md')) { \danog\MadelineProto\Logger::log($type); } file_put_contents('types/'.$type.'.md', $header.$constructors.$methods); $last_namespace = $new_namespace; } \danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE); file_put_contents('types/'.$this->index, '--- title: Types description: List of types image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Types [Back to API documentation index](..) '.$index); \danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE); file_put_contents('types/string.md', '--- title: string description: A UTF8 string of variable length image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: string [Back to constructor index](index.md) A UTF8 string of variable length. The total length in bytes of the string must not be bigger than 16777215. '); file_put_contents('types/bytes.md', '--- title: bytes description: A string of variable length image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: bytes [Back to constructor index](index.md) An object of type `\danog\MadelineProto\TL\Types\Bytes`. When casted to string, turns into a string of bytes of variable length, with length smaller than or equal to 16777215. When JSON-serialized, turns into an array of the following format: ``` [ \'_\' => \'bytes\', \'bytes\' => base64_encode($contents) ]; ``` '); file_put_contents('types/int.md', '--- title: integer description: A 32 bit signed integer ranging from -2147483648 to 2147483647 image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: int [Back to constructor index](index.md) A 32 bit signed integer ranging from `-2147483648` to `2147483647`. '); file_put_contents('types/int53.md', '--- title: integer description: A 53 bit signed integer image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: int53 [Back to constructor index](index.md) A 53 bit signed integer. '); file_put_contents('types/long.md', '--- title: long description: A 32 bit signed integer ranging from -9223372036854775808 to 9223372036854775807 image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: long [Back to constructor index](index.md) A 64 bit signed integer ranging from `-9223372036854775808` to `9223372036854775807`. '); file_put_contents('types/int128.md', '--- title: int128 description: A 128 bit signed integer image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: int128 [Back to constructor index](index.md) A 128 bit signed integer represented in little-endian base256 (`string`) format. '); file_put_contents('types/int256.md', '--- title: int256 description: A 256 bit signed integer image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: int256 [Back to constructor index](index.md) A 256 bit signed integer represented in little-endian base256 (`string`) format. '); file_put_contents('types/int512.md', '--- title: int512 description: A 512 bit signed integer image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: int512 [Back to constructor index](index.md) A 512 bit signed integer represented in little-endian base256 (`string`) format. '); file_put_contents('types/double.md', '--- title: double description: A double precision floating point number image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: double [Back to constructor index](index.md) A double precision floating point number, single precision can also be used (float). '); file_put_contents('types/!X.md', '--- title: !X description: Represents a TL serialized payload image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: !X [Back to constructor index](index.md) Represents a TL serialized payload. '); file_put_contents('types/X.md', '--- title: X description: Represents a TL serialized payload image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: X [Back to constructor index](index.md) Represents a TL serialized payload. '); file_put_contents('constructors/boolFalse.md', '--- title: boolFalse description: Represents a boolean with value equal to false image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # boolFalse [Back to constructor index](index.md) Represents a boolean with value equal to `false`. '); file_put_contents('constructors/boolTrue.md', '--- title: boolTrue description: Represents a boolean with value equal to true image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # boolTrue [Back to constructor index](index.md) Represents a boolean with value equal to `true`. '); file_put_contents('constructors/null.md', '--- title: null description: Represents a null value image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # null [Back to constructor index](index.md) Represents a `null` value. '); file_put_contents('types/Bool.md', '--- title: Bool description: Represents a boolean. image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- # Bool [Back to types index](index.md) Represents a boolean. '); file_put_contents('types/DataJSON.md', '--- title: DataJSON description: Any json-encodable data image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png --- ## Type: DataJSON [Back to constructor index](index.md) Any json-encodable data. '); \danog\MadelineProto\Logger::log('Done!', \danog\MadelineProto\Logger::NOTICE); } public $template = '<?php /** * Lang module * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto; class Lang { public static $lang = %s; // THIS WILL BE OVERWRITTEN BY $lang["en"] public static $current_lang = %s; }'; public function add_to_lang($key) { if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key])) { \danog\MadelineProto\Lang::$lang['en'][$key] = ''; file_put_contents(__DIR__.'/Lang.php', sprintf($this->template, var_export(\danog\MadelineProto\Lang::$lang, true), var_export(\danog\MadelineProto\Lang::$lang['en'], true))); } } } <?php /** * Yield return value PHP5 polyfill. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ class YieldReturnValue { private $value; public function __construct($value) { $this->value = $value; } public function getReturn() { return $this->value; } } <?php /** * BigInteger placeholder for deserialization. * * This file is part of MadelineProto. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineProto. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace phpseclib\Math; if (PHP_MAJOR_VERSION < 7 && !(class_exists('\\Phar') && \Phar::running())) { throw new \Exception('MadelineProto requires php 7 to run natively, use phar.madelineproto.xyz to run on PHP 5.6'); } if (defined('HHVM_VERSION')) { $engines = [['PHP64', ['OpenSSL']], ['BCMath', ['OpenSSL']], ['PHP32', ['OpenSSL']]]; foreach ($engines as $engine) { try { \phpseclib\Math\BigInteger::setEngine($engine[0], isset($engine[1]) ? $engine[1] : []); break; } catch (\Exception $e) { } } } class BigIntegor { } #!/usr/bin/env php <?php /* Copyright 2016-2019 Daniil Gentili (https://daniil.it) This file is part of MadelineProto. MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU General Public License along with MadelineProto. If not, see <http://www.gnu.org/licenses/>. */ set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/')); if (!file_exists(__DIR__.'/vendor/autoload.php')) { echo 'You did not run composer update, using madeline.php'.PHP_EOL; if (!file_exists('madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); } include 'madeline.php'; } else { require_once 'vendor/autoload.php'; } if (!file_exists('songs.php')) { copy('https://github.com/danog/MadelineProto/raw/master/songs.php', 'songs.php'); } echo 'Deserializing MadelineProto from session.madeline...'.PHP_EOL; /*if (!isset($MadelineProto->inputEncryptedFilePhoto) && false) { $MadelineProto->inputEncryptedFilePhoto = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic $MadelineProto->inputEncryptedFileGif = $MadelineProto->upload_encrypted('tests/pony.mp4'); $MadelineProto->inputEncryptedFileSticker = $MadelineProto->upload_encrypted('tests/lel.webp'); $MadelineProto->inputEncryptedFileDocument = $MadelineProto->upload_encrypted('tests/60', 'magic'); // This gets an inputFile object with file name magic $MadelineProto->inputEncryptedFileVideo = $MadelineProto->upload_encrypted('tests/swing.mp4'); $MadelineProto->inputEncryptedFileAudio = $MadelineProto->upload_encrypted('tests/mosconi.mp3'); }*/ class EventHandler extends \danog\MadelineProto\EventHandler { public function configureCall($call) { include 'songs.php'; $call->configuration['enable_NS'] = false; $call->configuration['enable_AGC'] = false; $call->configuration['enable_AEC'] = false; $call->configuration['log_file_path'] = '/tmp/logs'.$call->getCallID()['id'].'.log'; // Default is /dev/null //$call->configuration["stats_dump_file_path"] = "/tmp/stats".$call->getCallID()['id'].".txt"; // Default is /dev/null $call->parseConfig(); $call->playOnHold($songs); //$this->messages->sendMessage(['message' => var_export($call->configuration, true), 'peer' => $call->getOtherID()]); } public function handleMessage($chat_id, $from_id, $message) { try { if (!isset($this->my_users[$from_id]) || $message === '/start') { $this->my_users[$from_id] = true; $message = '/call'; $this->messages->sendMessage(['no_webpage' => true, 'peer' => $chat_id, 'message' => "Hi, I'm @magnaluna the webradio. Call _me_ to listen to some **awesome** music, or send /call to make _me_ call _you_ (don't forget to disable call privacy settings!). You can also program a phone call with /program: /program 29 August 2018 - call me the 29th of august 2018 /program +1 hour 30 minutes - call me in one hour and thirty minutes /program next Thursday - call me next Thursday at midnight Send /start to see this message again. I also provide advanced stats during calls! I'm a userbot powered by @MadelineProto, created by @danogentili. Source code: https://github.com/danog/MadelineProto Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'parse_mode' => 'Markdown']); } if (!isset($this->calls[$from_id]) && $message === '/call') { $call = $this->request_call($from_id); $this->configureCall($call); if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $this->calls[$call->getOtherID()] = $call; $this->times[$call->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $call->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL.$call->getDebugString()])['id']]; } } if (strpos($message, '/program') === 0) { $time = strtotime(str_replace('/program ', '', $message)); if ($time === false) { $this->messages->sendMessage(['peer' => $chat_id, 'message' => 'Invalid time provided']); } else { $this->programmed_call[] = [$from_id, $time]; $this->messages->sendMessage(['peer' => $chat_id, 'message' => 'OK']); } } if ($message === '/broadcast' && $from_id === 101374607) { $time = time() + 100; $message = explode(' ', $message, 2); unset($message[0]); $message = implode(' ', $message); foreach ($this->get_dialogs() as $peer) { $this->times_messages[] = [$peer, $time, $message]; if (isset($peer['user_id'])) { $this->programmed_call[] = [$peer['user_id'], $time]; } $time += 30; } } } catch (\danog\MadelineProto\RPCErrorException $e) { try { if ($e->rpc === 'USER_PRIVACY_RESTRICTED') { $e = 'Please disable call privacy settings to make me call you'; } elseif (strpos($e->rpc, 'FLOOD_WAIT_') === 0) { $t = str_replace('FLOOD_WAIT_', '', $e->rpc); $this->programmed_call[] = [$from_id, time() + 1 + $t]; $e = "Too many people used the /call function. I'll call you back in $t seconds.\nYou can also call me right now."; } $this->messages->sendMessage(['peer' => $chat_id, 'message' => (string) $e]); } catch (\danog\MadelineProto\RPCErrorException $e) { } echo $e; } catch (\danog\MadelineProto\Exception $e) { echo $e; } } public function onUpdateNewMessage($update) { if ($update['message']['out'] || $update['message']['to_id']['_'] !== 'peerUser' || !isset($update['message']['from_id'])) { return; } \danog\MadelineProto\Logger::log($update); $chat_id = $from_id = $this->get_info($update)['bot_api_id']; $message = isset($update['message']['message']) ? $update['message']['message'] : ''; $this->handleMessage($chat_id, $from_id, $message); } public function onUpdateNewEncryptedMessage($update) { return; $chat_id = $this->get_info($update)['InputEncryptedChat']; $from_id = $this->get_secret_chat($chat_id)['user_id']; $message = isset($update['message']['decrypted_message']['message']) ? $update['message']['decrypted_message']['message'] : ''; $this->handleMessage($chat_id, $from_id, $message); } public function onUpdateEncryption($update) { return; try { if ($update['chat']['_'] !== 'encryptedChat') { return; } $chat_id = $this->get_info($update)['InputEncryptedChat']; $from_id = $this->get_secret_chat($chat_id)['user_id']; $message = ''; } catch (\danog\MadelineProto\Exception $e) { return; } $this->handleMessage($chat_id, $from_id, $message); } public function onUpdatePhoneCall($update) { if (is_object($update['phone_call']) && isset($update['phone_call']->madeline) && $update['phone_call']->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_INCOMING) { $this->configureCall($update['phone_call']); if ($update['phone_call']->accept() === false) { echo 'DID NOT ACCEPT A CALL'; } $this->calls[$update['phone_call']->getOtherID()] = $update['phone_call']; try { $this->times[$update['phone_call']->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $update['phone_call']->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL])['id']]; } catch (\danog\MadelineProto\RPCErrorException $e) { } } } public function onAny($update) { \danog\MadelineProto\Logger::log($update); } public function onLoop() { foreach ($this->programmed_call as $key => $pair) { list($user, $time) = $pair; if ($time < time()) { if (!isset($this->calls[$user])) { try { $call = $this->request_call($user); $this->configureCall($call); if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { $this->calls[$call->getOtherID()] = $call; $this->times[$call->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $call->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL.$call->getDebugString()])['id']]; } } catch (\danog\MadelineProto\RPCErrorException $e) { try { if ($e->rpc === 'USER_PRIVACY_RESTRICTED') { $e = 'Please disable call privacy settings to make me call you'; } elseif (strpos($e->rpc, 'FLOOD_WAIT_') === 0) { $t = str_replace('FLOOD_WAIT_', '', $e->rpc); $this->programmed_call[] = [$user, time() + 1 + $t]; $e = "I'll call you back in $t seconds.\nYou can also call me right now."; } $this->messages->sendMessage(['peer' => $user, 'message' => (string) $e]); } catch (\danog\MadelineProto\RPCErrorException $e) { } } } unset($this->programmed_call[$key]); } break; } foreach ($this->times_messages as $key => $pair) { list($peer, $time, $message) = $pair; if ($time < time()) { try { $this->messages->sendMessage(['peer' => $peer, 'message' => $message]); } catch (\danog\MadelineProto\RPCErrorException $e) { if (strpos($e->rpc, 'FLOOD_WAIT_') === 0) { $t = str_replace('FLOOD_WAIT_', '', $e->rpc); $this->times_messages[] = [$peer, time() + 1 + $t, $message]; } echo $e; } unset($this->times_messages[$key]); } break; } \danog\MadelineProto\Logger::log(count($this->calls).' calls running!'); foreach ($this->calls as $key => $call) { if ($call->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { try { if (isset($this->times[$call->getOtherID()][1])) { /*$this->messages->sendMedia([ 'reply_to_msg_id' => $this->times[$call->getOtherID()][1], 'peer' => $call->getOtherID(), 'message' => 'Call statistics by @magnaluna', 'media' => [ '_' => 'inputMediaUploadedDocument', 'file' => "/tmp/stats".$call->getCallID()['id'].".txt", 'attributes' => [ ['_' => 'documentAttributeFilename', 'file_name' => "stats".$call->getCallID()['id'].".txt"] ] ], ]);*/ $this->messages->sendMedia([ 'reply_to_msg_id' => $this->times[$call->getOtherID()][1], 'peer' => $call->getOtherID(), 'message' => 'Debug info by @magnaluna', 'media' => [ '_' => 'inputMediaUploadedDocument', 'file' => '/tmp/logs'.$call->getCallID()['id'].'.log', 'attributes' => [ ['_' => 'documentAttributeFilename', 'file_name' => 'logs'.$call->getCallID()['id'].'.log'], ], ], ]); } } catch (\danog\MadelineProto\Exception $e) { echo $e; } catch (\danog\MadelineProto\RPCErrorException $e) { echo $e; } catch (\danog\MadelineProto\Exception $e) { echo $e; } @unlink('/tmp/logs'.$call->getCallID()['id'].'.log'); @unlink('/tmp/stats'.$call->getCallID()['id'].'.txt'); unset($this->calls[$key]); } elseif (isset($this->times[$call->getOtherID()]) && $this->times[$call->getOtherID()][0] < time()) { $this->times[$call->getOtherID()][0] += 30 + count($this->calls); try { $this->messages->editMessage(['id' => $this->times[$call->getOtherID()][1], 'peer' => $call->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL.$call->getDebugString()]); } catch (\danog\MadelineProto\RPCErrorException $e) { echo $e; } } } } } if (!class_exists('\\danog\\MadelineProto\\VoIPServerConfig')) { die('Install the libtgvoip extension: https://voip.madelineproto.xyz'.PHP_EOL); } \danog\MadelineProto\VoIPServerConfig::update( [ 'audio_init_bitrate' => 100 * 1000, 'audio_max_bitrate' => 100 * 1000, 'audio_min_bitrate' => 10 * 1000, 'audio_congestion_window' => 4 * 1024, ] ); $MadelineProto = new \danog\MadelineProto\API('session.madeline', ['secret_chats' => ['accept_chats' => false], 'logger' => ['logger' => 3, 'logger_level' => 5, 'logger_param' => getcwd().'/MadelineProto.log']]); $MadelineProto->start(); if (!isset($MadelineProto->programmed_call)) { $MadelineProto->programmed_call = []; } foreach (['my_users', 'times', 'times_messages', 'calls'] as $key) { if (!isset($MadelineProto->{$key})) { $MadelineProto->{$key} = []; } } $MadelineProto->setEventHandler('\EventHandler'); $MadelineProto->loop(); <?php require 'vendor/autoload.php'; class a { use \danog\Serializable; protected $a; public function ___construct() { var_dump('CONSTRUCTED a'); } public function __wakeup() { var_dump('WOKE UP a'); } } new a(); class b { use \danog\Serializable; } $result = \danog\Serialization::unserialize(file_get_contents('test')); var_dump($result); file_put_contents('testb', \danog\Serialization::serialize($result)); { "name": "danog/magicalserializer", "description": "Serialize Volatile, Threaded or any other internal PHP class!", "type": "library", "license": "AGPL-3.0-only", "homepage": "https://daniil.it/MagicalSerializer", "keywords": ["pthreads", "volatile", "serialize", "threading", "serializable"], "authors": [ { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "autoload": { "psr-0": { "danog\\": "src/" } } } <?php class a { } class b { } $a = new a(); $a->a = ['lel', ['lel', [new a()]]]; $a->b = new a(); $a->b->c = [new a()]; $a->b->c[0]->d = 'cos'; $a->b->c[0]->e = new b(); $a->b->c[0]->e->f = new a(); $a = [$a]; file_put_contents('test', serialize($a)); var_dump(serialize($a), $a); var_dump(unserialize(file_get_contents('testb'))); <?php /* Copyright 2016-2018 Daniil Gentili (https://daniil.it) This file is part of MagicalSerializer. MagicalSerializer is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MagicalSerializer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU General Public License along with the MagicalSerializer. If not, see <http://www.gnu.org/licenses/>. */ namespace danog; trait Serializable { final public function __construct(...$params) { if (count($params) === 1 && is_array($params[0]) && isset($params[0]['originalclassnamepony'])) { unset($params[0]['originalclassnamepony']); foreach ($params[0] as $key => $value) { if (strpos($key, chr(0).get_class($this).chr(0)) === 0) { $key = substr($key, strlen(get_class($this)) + 2); } elseif (strpos($key, chr(0).'*'.chr(0)) === 0) { $key = substr($key, 3); } elseif ($key[0] === "\0") { $key = substr($key, 1); } $this->{$key} = \danog\Serialization::extractponyobject($value); } return; } if (method_exists($this, '__magic_construct')) { $this->__magic_construct(...$params); } elseif (method_exists($this, '___construct')) { $this->___construct(...$params); } } final public function fetchserializableobject($hash) { $values = get_object_vars($this); if (method_exists($this, '__sleep')) { $newvalues = []; foreach ($this->__sleep() as $key) { $newvalues[$key] = $values[$key]; } $values = $newvalues; } return new \danog\PlaceHolder($hash, get_class($this), $values); } } <?php /* Copyright 2016-2018 Daniil Gentili (https://daniil.it) This file is part of MagicalSerializer. MagicalSerializer is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MagicalSerializer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU General Public License along with the MagicalSerializer. If not, see <http://www.gnu.org/licenses/>. */ namespace danog; class Serialization { public static $extracted = []; public static function unserialize($data) { foreach (get_declared_classes() as $class) { if (isset(class_uses($class)['danog\Serializable'])) { $namelength = strlen($class); if (strpos($data, 'O:'.$namelength.':"'.$class.'":') === false) { continue; } $data = explode('O:'.$namelength.':"'.$class.'":', $data); $stringdata = array_shift($data); foreach ($data as $chunk) { list($attributecount, $value) = explode(':{', $chunk, 2); $attributecount++; $stringdata .= 'O:17:"danog\PlaceHolder":'.$attributecount.':{s:21:"originalclassnamepony";s:'.$namelength.':"'.$class.'";'.$value; } $data = $stringdata; } } self::$extracted = []; $data = self::extractponyobject(unserialize($data)); self::$extracted = []; return $data; } public static function extractponyobject($orig) { if (isset($orig->realactualponyobject)) { return self::extractponyobject($orig->realactualponyobject); } if (is_array($orig) || $orig instanceof \Volatile) { foreach ($orig as $key => $value) { $orig[$key] = self::extractponyobject($value); } return $orig; } if (is_object($orig) && !isset(self::$extracted[$hash = spl_object_hash($orig)])) { self::$extracted[$hash] = true; foreach ($orig as $key => $value) { $orig->{$key} = self::extractponyobject($value); } } return $orig; } public static function serialize($object, $not_compatible = false) { self::$extracted = []; $object = serialize(self::createserializableobject($object)); self::$extracted = []; if ($not_compatible === true) { return $object; } $object = explode('O:17:"danog\PlaceHolder":', $object); $newobject = array_shift($object); foreach ($object as $chunk) { list($attributecount, $value) = explode(':{', $chunk, 2); $attributecount--; list($pre, $value) = explode('s:21:"originalclassnamepony";s:', $value, 2); list($length, $value) = explode(':', $value, 2); $classname = substr($value, 1, $length); $value = $pre.substr($value, $length + 3); $newobject .= 'O:'.strlen($classname).':"'.$classname.'":'.$attributecount.':{'.$value; } return $newobject; } public static function createserializableobject($orig) { if (is_object($orig) && $orig instanceof \danog\MadelineProto\VoIP) { $orig = false; } if (is_object($orig)) { if (isset(self::$extracted[$hash = spl_object_hash($orig)])) { return self::$extracted[$hash]; } if (method_exists($orig, 'fetchserializableobject')) { return $orig->fetchserializableobject($hash); } self::$extracted[$hash] = $orig; } if (is_array($orig) || $orig instanceof \Volatile) { foreach ($orig as $key => $value) { $orig[$key] = self::createserializableobject($value); } } return $orig; } } <?php /* Copyright 2016-2018 Daniil Gentili (https://daniil.it) This file is part of MagicalSerializer. MagicalSerializer is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MagicalSerializer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU General Public License along with the MagicalSerializer. If not, see <http://www.gnu.org/licenses/>. */ namespace danog; class PlaceHolder { public function __construct($hash, $originalclassnamepony, $elements) { Serialization::$extracted[$hash] = $this; $this->originalclassnamepony = $originalclassnamepony; foreach ($elements as $key => $value) { $this->{$key} = Serialization::createserializableobject($value); } } public function __wakeup() { $this->realactualponyobject = new $this->originalclassnamepony(get_object_vars($this)); if (method_exists($this->realactualponyobject, '__wakeup')) { $this->realactualponyobject->__wakeup(); } } } { "name": "danog/primemodule", "description": "Prime module capable of doing prime factorization of huge numbers very quickly.\"", "type": "library", "license": "AGPL-3.0-only", "authors": [ { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "require": {}, "suggest": { "ext-primemodule": "Install the native C++ extension for extremely fast factorization (https://github.com/danog/PrimeModule-ext)" }, "autoload": { "psr-0": { "danog\\": "lib/" } } } # NOTICE!!! This is copied from https://stackoverflow.com/questions/4643647/fast-prime-factorization-module import sys import random def primesbelow(N): # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 #""" Input N>=6, Returns a list of primes, 2 <= p < N """ correction = N % 6 > 1 N = {0:N, 1:N-1, 2:N+4, 3:N+3, 4:N+2, 5:N+1}[N%6] sieve = [True] * (N // 3) sieve[0] = False for i in range(int(N ** .5) // 3 + 1): if sieve[i]: k = (3 * i + 1) | 1 sieve[k*k // 3::2*k] = [False] * ((N//6 - (k*k)//6 - 1)//k + 1) sieve[(k*k + 4*k - 2*k*(i%2)) // 3::2*k] = [False] * ((N // 6 - (k*k + 4*k - 2*k*(i%2))//6 - 1) // k + 1) return [2, 3] + [(3 * i + 1) | 1 for i in range(1, N//3 - correction) if sieve[i]] smallprimeset = set(primesbelow(100000)) _smallprimeset = 100000 def isprime(n, precision=7): # http://en.wikipedia.org/wiki/Miller-Rabin_primality_test#Algorithm_and_running_time if n == 1 or n % 2 == 0: return False elif n < 1: raise ValueError("Out of bounds, first argument must be > 0") elif n < _smallprimeset: return n in smallprimeset d = n - 1 s = 0 while d % 2 == 0: d //= 2 s += 1 for repeat in range(precision): a = random.randrange(2, n - 2) x = pow(a, d, n) if x == 1 or x == n - 1: continue for r in range(s - 1): x = pow(x, 2, n) if x == 1: return False if x == n - 1: break else: return False return True # https://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/ def pollard_brent(n): if n % 2 == 0: return 2 if n % 3 == 0: return 3 y, c, m = random.randint(1, n-1), random.randint(1, n-1), random.randint(1, n-1) g, r, q = 1, 1, 1 while g == 1: x = y for i in range(r): y = (pow(y, 2, n) + c) % n k = 0 while k < r and g==1: ys = y for i in range(min(m, r-k)): y = (pow(y, 2, n) + c) % n q = q * abs(x-y) % n g = gcd(q, n) k += m r *= 2 if g == n: while True: ys = (pow(ys, 2, n) + c) % n g = gcd(abs(x - ys), n) if g > 1: break return g smallprimes = primesbelow(10000) # might seem low, but 1000*1000 = 1000000, so this will fully factor every composite < 1000000 def primefactors(n, sort=False): factors = [] limit = int(n ** .5) + 1 for checker in smallprimes: if checker > limit: break while n % checker == 0: factors.append(checker) n //= checker limit = int(n ** .5) + 1 if checker > limit: break if n < 2: return factors while n > 1: if isprime(n): factors.append(n) break factor = pollard_brent(n) # trial division did not fully factor, switch to pollard-brent factors.extend(primefactors(factor)) # recurse to factor the not necessarily prime factor returned by pollard-brent n //= factor if sort: factors.sort() return factors def factorization(n): factors = {} for p1 in primefactors(n): try: factors[p1] += 1 except KeyError: factors[p1] = 1 return factors totients = {} def totient(n): if n == 0: return 1 try: return totients[n] except KeyError: pass tot = 1 for p, exp in factorization(n).items(): tot *= (p - 1) * p ** (exp - 1) totients[n] = tot return tot def gcd(a, b): if a == b: return a while b > 0: a, b = b, a % b return a def lcm(a, b): return abs(a * b) // gcd(a, b) print(primefactors(int(sys.argv[1]))[0])from math import log from argparse import ArgumentParser # Multiple Polynomial Quadratic Sieve def mpqs(n, verbose=False): if verbose: time1 = clock() root_n = isqrt(n) root_2n = isqrt(n+n) # formula chosen by experimentation # seems to be close to optimal for n < 10^50 bound = int(5 * log(n, 10)**2) prime = [] mod_root = [] log_p = [] num_prime = 0 # find a number of small primes for which n is a quadratic residue p = 2 while p < bound or num_prime < 3: # legendre (n|p) is only defined for odd p if p > 2: leg = legendre(n, p) else: leg = n & 1 if leg == 1: prime += [p] mod_root += [int(mod_sqrt(n, p))] log_p += [log(p, 10)] num_prime += 1 elif leg == 0: return p p = next_prime(p) # size of the sieve x_max = len(prime)*60 # maximum value on the sieved range m_val = (x_max * root_2n) >> 1 # fudging the threshold down a bit makes it easier to find powers of primes as factors # as well as partial-partial relationships, but it also makes the smoothness check slower. # there's a happy medium somewhere, depending on how efficient the smoothness check is thresh = log(m_val, 10) * 0.735 # skip small primes. they contribute very little to the log sum # and add a lot of unnecessary entries to the table # instead, fudge the threshold down a bit, assuming ~1/4 of them pass min_prime = int(thresh*3) fudge = sum(log_p[i] for i,p in enumerate(prime) if p < min_prime)/4 thresh -= fudge smooth = [] used_prime = set() partial = {} num_smooth = 0 num_used_prime = 0 num_partial = 0 num_poly = 0 root_A = isqrt(root_2n / x_max) while True: # find an integer value A such that: # A is =~ sqrt(2*n) / x_max # A is a perfect square # sqrt(A) is prime, and n is a quadratic residue mod sqrt(A) while True: root_A = next_prime(root_A) leg = legendre(n, root_A) if leg == 1: break elif leg == 0: return root_A A = root_A * root_A # solve for an adequate B # B*B is a quadratic residue mod n, such that B*B-A*C = n # this is unsolvable if n is not a quadratic residue mod sqrt(A) b = mod_sqrt(n, root_A) B = (b + (n - b*b) * mod_inv(b + b, root_A))%A # B*B-A*C = n <=> C = (B*B-n)/A C = (B*B - n) / A num_poly += 1 # sieve for prime factors sums = [0.0]*(2*x_max) i = 0 for p in prime: if p < min_prime: i += 1 continue logp = log_p[i] inv_A = mod_inv(A, p) # modular root of the quadratic a = int(((mod_root[i] - B) * inv_A)%p) b = int(((p - mod_root[i] - B) * inv_A)%p) k = 0 while k < x_max: if k+a < x_max: sums[k+a] += logp if k+b < x_max: sums[k+b] += logp if k: sums[k-a+x_max] += logp sums[k-b+x_max] += logp k += p i += 1 # check for smooths i = 0 for v in sums: if v > thresh: x = x_max-i if i > x_max else i vec = set() sqr = [] # because B*B-n = A*C # (A*x+B)^2 - n = A*A*x*x+2*A*B*x + B*B - n # = A*(A*x*x+2*B*x+C) # gives the congruency # (A*x+B)^2 = A*(A*x*x+2*B*x+C) (mod n) # because A is chosen to be square, it doesn't need to be sieved val = sieve_val = A*x*x + 2*B*x + C if sieve_val < 0: vec = set([-1]) sieve_val = -sieve_val for p in prime: while sieve_val%p == 0: if p in vec: # keep track of perfect square factors # to avoid taking the sqrt of a gigantic number at the end sqr += [p] vec ^= set([p]) sieve_val = int(sieve_val / p) if sieve_val == 1: # smooth smooth += [(vec, (sqr, (A*x+B), root_A))] used_prime |= vec elif sieve_val in partial: # combine two partials to make a (xor) smooth # that is, every prime factor with an odd power is in our factor base pair_vec, pair_vals = partial[sieve_val] sqr += list(vec & pair_vec) + [sieve_val] vec ^= pair_vec smooth += [(vec, (sqr + pair_vals[0], (A*x+B)*pair_vals[1], root_A*pair_vals[2]))] used_prime |= vec num_partial += 1 else: # save partial for later pairing partial[sieve_val] = (vec, (sqr, A*x+B, root_A)) i += 1 num_smooth = len(smooth) num_used_prime = len(used_prime) if num_smooth > num_used_prime: used_prime_list = sorted(list(used_prime)) # set up bit fields for gaussian elimination masks = [] mask = 1 bit_fields = [0]*num_used_prime for vec, vals in smooth: masks += [mask] i = 0 for p in used_prime_list: if p in vec: bit_fields[i] |= mask i += 1 mask <<= 1 # row echelon form col_offset = 0 null_cols = [] for col in xrange(num_smooth): pivot = col-col_offset == num_used_prime or bit_fields[col-col_offset] & masks[col] == 0 for row in xrange(col+1-col_offset, num_used_prime): if bit_fields[row] & masks[col]: if pivot: bit_fields[col-col_offset], bit_fields[row] = bit_fields[row], bit_fields[col-col_offset] pivot = False else: bit_fields[row] ^= bit_fields[col-col_offset] if pivot: null_cols += [col] col_offset += 1 # reduced row echelon form for row in xrange(num_used_prime): # lowest set bit mask = bit_fields[row] & -bit_fields[row] for up_row in xrange(row): if bit_fields[up_row] & mask: bit_fields[up_row] ^= bit_fields[row] # check for non-trivial congruencies for col in null_cols: all_vec, (lh, rh, rA) = smooth[col] lhs = lh # sieved values (left hand side) rhs = [rh] # sieved values - n (right hand side) rAs = [rA] # root_As (cofactor of lhs) i = 0 for field in bit_fields: if field & masks[col]: vec, (lh, rh, rA) = smooth[i] lhs += list(all_vec & vec) + lh all_vec ^= vec rhs += [rh] rAs += [rA] i += 1 factor = gcd(list_prod(rAs)*list_prod(lhs) - list_prod(rhs), n) if factor != 1 and factor != n: break else: continue break return factor # divide and conquer list product def list_prod(a): size = len(a) if size == 1: return a[0] return list_prod(a[:size>>1]) * list_prod(a[size>>1:]) # greatest common divisor of a and b def gcd(a, b): while b: a, b = b, a%b return a # modular inverse of a mod m def mod_inv(a, m): a = int(a%m) x, u = 0, 1 while a: x, u = u, x - (m/a)*u m, a = a, m%a return x # legendre symbol (a|m) # note: returns m-1 if a is a non-residue, instead of -1 def legendre(a, m): return pow(a, (m-1) >> 1, m) # modular sqrt(n) mod p # p must be prime def mod_sqrt(n, p): a = n%p if p%4 == 3: return pow(a, (p+1) >> 2, p) elif p%8 == 5: v = pow(a << 1, (p-5) >> 3, p) i = ((a*v*v << 1) % p) - 1 return (a*v*i)%p elif p%8 == 1: # Shank's method q = p-1 e = 0 while q&1 == 0: e += 1 q >>= 1 n = 2 while legendre(n, p) != p-1: n += 1 w = pow(a, q, p) x = pow(a, (q+1) >> 1, p) y = pow(n, q, p) r = e while True: if w == 1: return x v = w k = 0 while v != 1 and k+1 < r: v = (v*v)%p k += 1 if k == 0: return x d = pow(y, 1 << (r-k-1), p) x = (x*d)%p y = (d*d)%p w = (w*y)%p r = k else: # p == 2 return a #integer sqrt of n def isqrt(n): c = n*4/3 d = c.bit_length() a = d>>1 if d&1: x = 1 << a y = (x + (n >> a)) >> 1 else: x = (3 << a) >> 2 y = (x + (c >> a)) >> 1 if x != y: x = y y = (x + n/x) >> 1 while y < x: x = y y = (x + n/x) >> 1 return x # strong probable prime def is_sprp(n, b=2): if n < 2: return False d = n-1 s = 0 while d&1 == 0: s += 1 d >>= 1 x = pow(b, d, n) if x == 1 or x == n-1: return True for r in xrange(1, s): x = (x * x)%n if x == 1: return False elif x == n-1: return True return False # lucas probable prime # assumes D = 1 (mod 4), (D|n) = -1 def is_lucas_prp(n, D): P = 1 Q = (1-D) >> 2 # n+1 = 2**r*s where s is odd s = n+1 r = 0 while s&1 == 0: r += 1 s >>= 1 # calculate the bit reversal of (odd) s # e.g. 19 (10011) <=> 25 (11001) t = 0 while s: if s&1: t += 1 s -= 1 else: t <<= 1 s >>= 1 # use the same bit reversal process to calculate the sth Lucas number # keep track of q = Q**n as we go U = 0 V = 2 q = 1 # mod_inv(2, n) inv_2 = (n+1) >> 1 while t: if t&1: # U, V of n+1 U, V = ((U + V) * inv_2)%n, ((D*U + V) * inv_2)%n q = (q * Q)%n t -= 1 else: # U, V of n*2 U, V = (U * V)%n, (V * V - 2 * q)%n q = (q * q)%n t >>= 1 # double s until we have the 2**r*sth Lucas number while r: U, V = (U * V)%n, (V * V - 2 * q)%n q = (q * q)%n r -= 1 # primality check # if n is prime, n divides the n+1st Lucas number, given the assumptions return U == 0 # primes less than 212 small_primes = set([ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,101,103,107,109,113, 127,131,137,139,149,151,157,163,167,173, 179,181,191,193,197,199,211]) # pre-calced sieve of eratosthenes for n = 2, 3, 5, 7 indices = [ 1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,101,103,107,109,113,121,127,131, 137,139,143,149,151,157,163,167,169,173, 179,181,187,191,193,197,199,209] # distances between sieve values offsets = [ 10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2,10, 2] max_int = 2147483647 # an 'almost certain' primality check def is_prime(n): if n < 212: return n in small_primes for p in small_primes: if n%p == 0: return False # if n is a 32-bit integer, perform full trial division if n <= max_int: i = 211 while i*i < n: for o in offsets: i += o if n%i == 0: return False return True # Baillie-PSW # this is technically a probabalistic test, but there are no known pseudoprimes if not is_sprp(n, 2): return False # idea shamelessly stolen from Mathmatica # if n is a 2-sprp and a 3-sprp, n is necessarily square-free if not is_sprp(n, 3): return False a = 5 s = 2 # if n is a perfect square, this will never terminate while legendre(a, n) != n-1: s = -s a = s-a return is_lucas_prp(n, a) # next prime strictly larger than n def next_prime(n): if n < 2: return 2 # first odd larger than n n = (n + 1) | 1 if n < 212: while True: if n in small_primes: return n n += 2 # find our position in the sieve rotation via binary search x = int(n%210) s = 0 e = 47 m = 24 while m != e: if indices[m] < x: s = m m = (s + e + 1) >> 1 else: e = m m = (s + e) >> 1 i = int(n + (indices[m] - x)) # adjust offsets offs = offsets[m:] + offsets[:m] while True: for o in offs: if is_prime(i): return i i += o if __name__ == "__main__": parser =ArgumentParser(description='Uses a MPQS to factor a composite number') parser.add_argument('composite', metavar='number_to_factor', type=long, help='the composite number to factor') parser.add_argument('--verbose', dest='verbose', action='store_true', help="enable verbose output") args = parser.parse_args() print mpqs(args.composite) <?php /* Copyright 2016-2018 Daniil Gentili (https://daniil.it) This file is part of MadelineProto. MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU General Public License along with the MadelineProto. If not, see <http://www.gnu.org/licenses/>. */ namespace danog; class PrimeModule { public static function native_single($what) { if (!is_int($what)) { return false; } foreach ([2, 3, 5, 7, 11, 13, 17, 19, 23] as $s) { if ($what % $s === 0) { return $s; } } $g = 0; for ($i = 0; $i < 3; $i++) { $q = (rand(0, 127) & 15) + 17; $x = rand(0, 1000000000) + 1; $y = $x; $lim = 1 << ($i + 18); for ($j = 1; $j <= $lim; $j++) { list($a, $b, $c) = [$x, $x, $q]; while ($b != 0) { if (($b & 1) != 0) { $c += $a; if ($c >= $what) { $c -= $what; } } $a += $a; if ($a >= $what) { $a -= $what; } $b >>= 1; } $x = $c; $z = ($x < $y) ? $y - $x : $x - $y; $g = self::gcd($z, $what); if ($g != 1) { break; } if (($j & ($j - 1)) === 0) { $y = $x; } } if ($g > 1) { break; } } $p = $what; return min($p, $g); } public static function native($what) { $res = [self::native_single($what)]; while (array_product($res) !== $what) { $res[] = self::native_single($what / array_product($res)); } return $res; } public static function python_single($what) { if (function_exists('shell_exec')) { $res = trim(shell_exec('timeout 10 python '.__DIR__.'/prime.py '.$what.' 2>&1')); if ($res == '' || is_null($res) || !is_numeric($res)) { copy(__DIR__.'/prime.py', getcwd().'/.prime.py'); $res = trim(shell_exec('timeout 10 python '.getcwd().'/.prime.py '.$what.' 2>&1')); unlink(getcwd().'/.prime.py'); if ($res == '' || is_null($res) || !is_numeric($res)) { return false; } } $newval = intval($res); if (is_int($newval)) { $res = $newval; } if ($res === 0) { return false; } return $res; } return false; } public static function python($what) { $res = [self::python_single($what)]; if ($res[0] === false) { return false; } while (array_product($res) !== $what) { $res[] = self::python_single($what / array_product($res)); } return $res; } public static function python_single_alt($what) { if (function_exists('shell_exec')) { $res = trim(shell_exec('python '.__DIR__.'/alt_prime.py '.$what.' 2>&1')); if ($res == '' || is_null($res) || !is_numeric($res)) { copy(__DIR__.'/alt_prime.py', getcwd().'/.alt_prime.py'); $res = trim(shell_exec('python '.getcwd().'/.alt_prime.py '.$what.' 2>&1')); unlink(getcwd().'/.alt_prime.py'); if ($res == '' || is_null($res) || !is_numeric($res)) { return false; } } $newval = intval($res); if (is_int($newval)) { $res = $newval; } if ($res === 0) { return false; } return $res; } return false; } public static function python_alt($what) { $res = [self::python_single_alt($what)]; if ($res[0] === false) { return false; } while (array_product($res) !== $what) { $res[] = self::python_single_alt($what / array_product($res)); } return $res; } public static function wolfram_single($what) { $query = 'Do prime factorization of '.$what; $params = [ 'async' => true, 'banners' => 'raw', 'debuggingdata' => false, 'format' => 'moutput', 'formattimeout' => 8, 'input' => $query, 'output' => 'JSON', 'proxycode' => json_decode(file_get_contents('http://www.wolframalpha.com/api/v1/code'), true)['code'], ]; $url = 'https://www.wolframalpha.com/input/json.jsp?'.http_build_query($params); $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Referer: https://www.wolframalpha.com/input/?i='.urlencode($query)]); curl_setopt($ch, CURLOPT_URL, $url); $res = json_decode(curl_exec($ch), true); curl_close($ch); $fres = false; if (!isset($res['queryresult']['pods'])) { return false; } foreach ($res['queryresult']['pods'] as $cur) { if ($cur['id'] === 'Divisors') { $fres = explode(', ', preg_replace(["/{\d+, /", "/, \d+}$/"], '', $cur['subpods'][0]['moutput'])); break; } } if (is_array($fres)) { $fres = $fres[0]; $newval = intval($fres); if (is_int($newval)) { $fres = $newval; } return $fres; } return false; } public static function wolfram($what) { $res = [self::wolfram_single($what)]; while (array_product($res) !== $what) { $res[] = self::wolfram_single($what / array_product($res)); } return $res; } public static function native_single_cpp($what) { if (!extension_loaded('primemodule')) { return false; } try { return factorize($what); } catch (\Exception $e) { return false; } } public static function native_cpp($what) { $res = [self::native_single_cpp($what)]; if ($res[0] == false) { return false; } while (($product = array_product($res)) !== $what) { if ($product == 0) { return false; } $res[] = self::native_single_cpp($what / $product); } return $res; } public static function auto_single($what) { $res = self::native_single_cpp($what); if ($res !== false) { return $res; } $res = self::python_single_alt($what); if ($res !== false) { return $res; } $res = self::python_single($what); if ($res !== false) { return $res; } $res = self::native_single((int) $what); if ($res !== false) { return $res; } $res = self::wolfram_single($what); if ($res !== false) { return $res; } return false; } public static function auto($what) { $res = self::native_cpp($what); if (is_array($res)) { return $res; } $res = self::python_alt($what); if (is_array($res)) { return $res; } $res = self::python($what); if (is_array($res)) { return $res; } $res = self::native((int) $what); if (is_array($res)) { return $res; } $res = self::wolfram($what); if (is_array($res)) { return $res; } return false; } private static function gcd($a, $b) { if ($a == $b) { return $a; } while ($b > 0) { list($a, $b) = [$b, self::posmod($a, $b)]; } return $a; } private static function posmod($a, $b) { $resto = $a % $b; if ($resto < 0) { $resto += abs($b); } return $resto; } private function primesbelow($N) { $correction = ($N % 6 > 1) ? true : false; $N_Array = [$N, $N - 1, $N + 4, $N + 3, $N + 2, $N + 1]; $N = $N_Array[$N % 6]; $sieve = []; for ($i = 0; $i < (int) $N / 3; $i++) { $sieve[$i] = true; } $sieve[0] = false; for ($i = 0; $i < (int) ((int) pow($N, 0.5) / 3) + 1; $i++) { if ($sieve[$i]) { $k = (3 * $i + 1) | 1; $startIndex1 = (int) ($k * $k / 3); $period = 2 * $k; for ($j = $startIndex1; $j < count($sieve); $j = $j + $period) { $sieve[$j] = false; } $startIndex2 = (int) (($k * $k + 4 * $k - 2 * $k * ($i % 2)) / 3); $period = 2 * $k; for ($k = $startIndex2; $k < count($sieve); $k = $k + $period) { $sieve[$k] = false; } } } $resultArray = [2, 3]; $t = 1; for ($i = 1; $i < (int) ($N / 3) - $correction; $i++) { if ($sieve[$i]) { $resultArray[$t + 1] = (3 * $i + 1) | 1; $t++; } } return $resultArray; } private function isprime($n, $precision = 7) { $smallprimeset = $this->primesbelow(100000); $_smallprimeset = 100000; if ($n == 1 || $n % 2 == 0) { return false; } elseif ($n < 1) { throw new Exception('Out of bounds, first argument must be > 0'); } elseif ($n < $_smallprimeset) { return in_array($n, $smallprimeset); } $d = $n - 1; $s = 0; while ($d % 2 == 0) { $d = (int) ($d / 2); $s += 1; } for ($i = 0; $i < $precision; $i++) { // random.randrange(2, n - 2) means: // $a = mt_rand(2, $n - 3); // maybe $n would be bigger that PHP_MAX_INT $a = mt_rand(2, 1084); $x = bcpowmod($a, $d, $n); if ($x == 1 || $x == $n - 1) { continue; } $flagfound = 0; for ($j = 0; $j < $s - 1; $j++) { $x = bcpowmod($x, 2, $n); if ($x == 1) { return false; } if ($x == $n - 1) { $flagfound = 1; break; } } if ($flagfound == 0) { return false; } } return true; } private function pollard_brent($n) { $n = (int) $n; if ($n % 2 == 0) { return 2; } if (bcmod($n, 2) == 0) { return 2; } if (bcmod($n, 3) == 0) { return 3; } // $y = mt_rand(1, $n-1); // $c = mt_rand(1, $n-1); // $m = mt_rand(1, $n-1); // Again, $n may be bigger than PHP_MAX_INT // also, small numbers has a big affect in a good performance $y = 2; $c = 3; $m = 4; $g = 1; $r = 1; $q = 1; while ($g == 1) { $x = $y; for ($i = 0; $i < $r; $i++) { // $y = gmp_mod( (bcpowmod($y, 2, $n) + $c) , $n); $y = bcmod((bcpowmod($y, 2, $n) + $c), $n); } $k = 0; while ($k < $r && $g == 1) { $ys = $y; for ($j = 0; $j < min($m, $r - $k); $j++) { // $y = gmp_mod( (bcpowmod($y, 2, $n) + $c), $n ); $y = bcmod((bcpowmod($y, 2, $n) + $c), $n); // $q = gmp_mod($q * abs($x-$y), $n); $mul = bcmul($q, abs($x - $y)); $q = bcmod($mul, $n); } $g = $this->gcd2($q, $n); $k += $m; } $r *= 2; } if ($g == $n) { while (true) { // $ys = ( bcpowmod($ys, 2, $n) + $c ) % $n; $ys = bcmod((bcpowmod($ys, 2, $n) + $c), $n); $g = $this->gcd2(abs($x - $ys), $n); if ($g > 1) { break; } } } return $g; } public function primefactors($n, $sort = false) { $smallprimes = $this->primesbelow(10000); $factors = []; $limit = bcadd(bcsqrt($n), 1); foreach ($smallprimes as $checker) { if ($checker > $limit) { break; } // while (gmp_mod($n, $checker) == 0) { while (bcmod($n, $checker) == 0) { array_push($factors, $checker); $n = bcdiv($n, $checker); $limit = bcadd(bcsqrt($n), 1); if ($checker > $limit) { break; } } } if ($n < 2) { return $factors; } while ($n > 1) { if ($this->isprime($n)) { array_push($factors, $n); break; } $factor = $this->pollard_brent($n); $factors = array_merge($factors, $this->primefactors($factor)); $n = (int) ($n / $factor); } if ($sort) { sort($factors); } return $factors; } private function gcd2($a, $b) { if ($a == $b) { return $a; } while ($b > 0) { $a2 = $a; $a = $b; $b = bcmod($a2, $b); } return $a; } } <?php // autoload_files.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'e8aa6e4b5a1db2f56ae794f1505391a8' => $vendorDir . '/amphp/amp/lib/functions.php', '76cd0796156622033397994f25b0d8fc' => $vendorDir . '/amphp/amp/lib/Internal/functions.php', '6cd5651c4fef5ed6b63e8d8b8ffbf3cc' => $vendorDir . '/amphp/byte-stream/lib/functions.php', '8dc56fe697ca93c4b40d876df1c94584' => $vendorDir . '/amphp/process/lib/functions.php', '445532134d762b3cbc25500cac266092' => $vendorDir . '/daverandom/libdns/src/functions.php', '7863f327e247feb05e3be59a4fe77a6b' => $vendorDir . '/amphp/uri/src/functions.php', '7ebf029ad4b246f1e3f66192b40a932f' => $vendorDir . '/amphp/dns/lib/functions.php', 'd4e415514e4352172d58f02433fa50e4' => $vendorDir . '/amphp/socket/src/functions.php', '1c2dcb9d6851a7abaae89f9586ddd460' => $vendorDir . '/amphp/socket/src/Internal/functions.php', 'b324e763907bc37a8bdf81fa40eb1b39' => $vendorDir . '/amphp/sync/lib/functions.php', '384cf4f2eb4d2f896db72315a76066ad' => $vendorDir . '/amphp/parallel/lib/Worker/functions.php', '68a7b7dddb51c03877a41f03c909bf08' => $vendorDir . '/amphp/file/lib/functions.php', '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', '3d05d4f147c95ba663000bd908d45656' => $vendorDir . '/amphp/websocket/src/functions.php', 'e1e8b49c332434256b5df11b0f0c2a62' => $vendorDir . '/league/uri-parser/src/functions_include.php', '244240de28ad61783068aef6c6b63aea' => $vendorDir . '/league/uri-schemes/src/functions_include.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', '4be4fbd9f5a89207b1fd1c85ae339dd7' => $vendorDir . '/amphp/websocket-client/src/functions.php', 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php', 'efa3b80c61fb35e374f529ec349af098' => $vendorDir . '/danog/madelineproto/src/BigIntegor.php', '81f2b6c0f9b646f6cc1f1a36118d70e9' => $vendorDir . '/danog/madelineproto/src/YieldReturnValue.php', ); <?php // autoload_static.php @generated by Composer namespace Composer\Autoload; class ComposerStaticInit60e6f00cae484812f6daa343f9cc612e { public static $files = array ( 'e8aa6e4b5a1db2f56ae794f1505391a8' => __DIR__ . '/..' . '/amphp/amp/lib/functions.php', '76cd0796156622033397994f25b0d8fc' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/functions.php', '6cd5651c4fef5ed6b63e8d8b8ffbf3cc' => __DIR__ . '/..' . '/amphp/byte-stream/lib/functions.php', '8dc56fe697ca93c4b40d876df1c94584' => __DIR__ . '/..' . '/amphp/process/lib/functions.php', '445532134d762b3cbc25500cac266092' => __DIR__ . '/..' . '/daverandom/libdns/src/functions.php', '7863f327e247feb05e3be59a4fe77a6b' => __DIR__ . '/..' . '/amphp/uri/src/functions.php', '7ebf029ad4b246f1e3f66192b40a932f' => __DIR__ . '/..' . '/amphp/dns/lib/functions.php', 'd4e415514e4352172d58f02433fa50e4' => __DIR__ . '/..' . '/amphp/socket/src/functions.php', '1c2dcb9d6851a7abaae89f9586ddd460' => __DIR__ . '/..' . '/amphp/socket/src/Internal/functions.php', 'b324e763907bc37a8bdf81fa40eb1b39' => __DIR__ . '/..' . '/amphp/sync/lib/functions.php', '384cf4f2eb4d2f896db72315a76066ad' => __DIR__ . '/..' . '/amphp/parallel/lib/Worker/functions.php', '68a7b7dddb51c03877a41f03c909bf08' => __DIR__ . '/..' . '/amphp/file/lib/functions.php', '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', '3d05d4f147c95ba663000bd908d45656' => __DIR__ . '/..' . '/amphp/websocket/src/functions.php', 'e1e8b49c332434256b5df11b0f0c2a62' => __DIR__ . '/..' . '/league/uri-parser/src/functions_include.php', '244240de28ad61783068aef6c6b63aea' => __DIR__ . '/..' . '/league/uri-schemes/src/functions_include.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '4be4fbd9f5a89207b1fd1c85ae339dd7' => __DIR__ . '/..' . '/amphp/websocket-client/src/functions.php', 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', 'efa3b80c61fb35e374f529ec349af098' => __DIR__ . '/..' . '/danog/madelineproto/src/BigIntegor.php', '81f2b6c0f9b646f6cc1f1a36118d70e9' => __DIR__ . '/..' . '/danog/madelineproto/src/YieldReturnValue.php', ); public static $prefixLengthsPsr4 = array ( 'p' => array ( 'phpseclib\\' => 10, ), 'd' => array ( 'danog\\LibDNSJson\\' => 17, ), 'S' => array ( 'Symfony\\Polyfill\\Ctype\\' => 23, ), 'P' => array ( 'Psr\\Http\\Message\\' => 17, 'ParagonIE\\ConstantTime\\' => 23, ), 'L' => array ( 'LibDNS\\' => 7, 'League\\Uri\\' => 11, ), 'K' => array ( 'Kelunik\\Certificate\\' => 20, ), 'D' => array ( 'Dotenv\\' => 7, ), 'A' => array ( 'Amp\\WindowsRegistry\\' => 20, 'Amp\\Websocket\\Client\\' => 21, 'Amp\\Websocket\\' => 14, 'Amp\\Uri\\' => 8, 'Amp\\Sync\\' => 9, 'Amp\\Socket\\' => 11, 'Amp\\Process\\' => 12, 'Amp\\Parser\\' => 11, 'Amp\\Parallel\\' => 13, 'Amp\\Http\\' => 9, 'Amp\\File\\' => 9, 'Amp\\DoH\\' => 8, 'Amp\\Dns\\' => 8, 'Amp\\Cache\\' => 10, 'Amp\\ByteStream\\' => 15, 'Amp\\Artax\\' => 10, 'Amp\\' => 4, ), ); public static $prefixDirsPsr4 = array ( 'phpseclib\\' => array ( 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', ), 'danog\\LibDNSJson\\' => array ( 0 => __DIR__ . '/..' . '/danog/libdns-json/lib', ), 'Symfony\\Polyfill\\Ctype\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', ), 'Psr\\Http\\Message\\' => array ( 0 => __DIR__ . '/..' . '/psr/http-message/src', ), 'ParagonIE\\ConstantTime\\' => array ( 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src', ), 'LibDNS\\' => array ( 0 => __DIR__ . '/..' . '/daverandom/libdns/src', ), 'League\\Uri\\' => array ( 0 => __DIR__ . '/..' . '/league/uri-interfaces/src', 1 => __DIR__ . '/..' . '/league/uri-parser/src', 2 => __DIR__ . '/..' . '/league/uri-schemes/src', ), 'Kelunik\\Certificate\\' => array ( 0 => __DIR__ . '/..' . '/kelunik/certificate/lib', ), 'Dotenv\\' => array ( 0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src', ), 'Amp\\WindowsRegistry\\' => array ( 0 => __DIR__ . '/..' . '/amphp/windows-registry/lib', ), 'Amp\\Websocket\\Client\\' => array ( 0 => __DIR__ . '/..' . '/amphp/websocket-client/src', ), 'Amp\\Websocket\\' => array ( 0 => __DIR__ . '/..' . '/amphp/websocket/src', ), 'Amp\\Uri\\' => array ( 0 => __DIR__ . '/..' . '/amphp/uri/src', ), 'Amp\\Sync\\' => array ( 0 => __DIR__ . '/..' . '/amphp/sync/lib', ), 'Amp\\Socket\\' => array ( 0 => __DIR__ . '/..' . '/amphp/socket/src', ), 'Amp\\Process\\' => array ( 0 => __DIR__ . '/..' . '/amphp/process/lib', ), 'Amp\\Parser\\' => array ( 0 => __DIR__ . '/..' . '/amphp/parser/lib', ), 'Amp\\Parallel\\' => array ( 0 => __DIR__ . '/..' . '/amphp/parallel/lib', ), 'Amp\\Http\\' => array ( 0 => __DIR__ . '/..' . '/amphp/http/src', ), 'Amp\\File\\' => array ( 0 => __DIR__ . '/..' . '/amphp/file/lib', ), 'Amp\\DoH\\' => array ( 0 => __DIR__ . '/..' . '/danog/dns-over-https/lib', ), 'Amp\\Dns\\' => array ( 0 => __DIR__ . '/..' . '/amphp/dns/lib', ), 'Amp\\Cache\\' => array ( 0 => __DIR__ . '/..' . '/amphp/cache/lib', ), 'Amp\\ByteStream\\' => array ( 0 => __DIR__ . '/..' . '/amphp/byte-stream/lib', ), 'Amp\\Artax\\' => array ( 0 => __DIR__ . '/..' . '/amphp/artax/lib', ), 'Amp\\' => array ( 0 => __DIR__ . '/..' . '/amphp/amp/lib', ), ); public static $prefixesPsr0 = array ( 'd' => array ( 'danog\\MadelineProto\\' => array ( 0 => __DIR__ . '/..' . '/danog/madelineproto/src', ), 'danog\\' => array ( 0 => __DIR__ . '/..' . '/danog/magicalserializer/src', 1 => __DIR__ . '/..' . '/danog/primemodule/lib', ), ), 'c' => array ( 'cash' => array ( 0 => __DIR__ . '/..' . '/cash/lrucache/src', ), ), 'P' => array ( 'PhpOption\\' => array ( 0 => __DIR__ . '/..' . '/phpoption/phpoption/src', ), 'Parsedown' => array ( 0 => __DIR__ . '/..' . '/erusev/parsedown', ), ), ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInit60e6f00cae484812f6daa343f9cc612e::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit60e6f00cae484812f6daa343f9cc612e::$prefixDirsPsr4; $loader->prefixesPsr0 = ComposerStaticInit60e6f00cae484812f6daa343f9cc612e::$prefixesPsr0; }, null, ClassLoader::class); } } <?php // autoload_real.php @generated by Composer class ComposerAutoloaderInit60e6f00cae484812f6daa343f9cc612e { private static $loader; public static function loadClassLoader($class) { if ('Composer\Autoload\ClassLoader' === $class) { require __DIR__ . '/ClassLoader.php'; } } public static function getLoader() { if (null !== self::$loader) { return self::$loader; } spl_autoload_register(array('ComposerAutoloaderInit60e6f00cae484812f6daa343f9cc612e', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInit60e6f00cae484812f6daa343f9cc612e', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInit60e6f00cae484812f6daa343f9cc612e::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); } $map = require __DIR__ . '/autoload_psr4.php'; foreach ($map as $namespace => $path) { $loader->setPsr4($namespace, $path); } $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } } $loader->register(true); if ($useStaticLoader) { $includeFiles = Composer\Autoload\ComposerStaticInit60e6f00cae484812f6daa343f9cc612e::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { composerRequire60e6f00cae484812f6daa343f9cc612e($fileIdentifier, $file); } return $loader; } } function composerRequire60e6f00cae484812f6daa343f9cc612e($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; } } <?php // autoload_psr4.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'phpseclib\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'), 'danog\\LibDNSJson\\' => array($vendorDir . '/danog/libdns-json/lib'), 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), 'LibDNS\\' => array($vendorDir . '/daverandom/libdns/src'), 'League\\Uri\\' => array($vendorDir . '/league/uri-interfaces/src', $vendorDir . '/league/uri-parser/src', $vendorDir . '/league/uri-schemes/src'), 'Kelunik\\Certificate\\' => array($vendorDir . '/kelunik/certificate/lib'), 'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'), 'Amp\\WindowsRegistry\\' => array($vendorDir . '/amphp/windows-registry/lib'), 'Amp\\Websocket\\Client\\' => array($vendorDir . '/amphp/websocket-client/src'), 'Amp\\Websocket\\' => array($vendorDir . '/amphp/websocket/src'), 'Amp\\Uri\\' => array($vendorDir . '/amphp/uri/src'), 'Amp\\Sync\\' => array($vendorDir . '/amphp/sync/lib'), 'Amp\\Socket\\' => array($vendorDir . '/amphp/socket/src'), 'Amp\\Process\\' => array($vendorDir . '/amphp/process/lib'), 'Amp\\Parser\\' => array($vendorDir . '/amphp/parser/lib'), 'Amp\\Parallel\\' => array($vendorDir . '/amphp/parallel/lib'), 'Amp\\Http\\' => array($vendorDir . '/amphp/http/src'), 'Amp\\File\\' => array($vendorDir . '/amphp/file/lib'), 'Amp\\DoH\\' => array($vendorDir . '/danog/dns-over-https/lib'), 'Amp\\Dns\\' => array($vendorDir . '/amphp/dns/lib'), 'Amp\\Cache\\' => array($vendorDir . '/amphp/cache/lib'), 'Amp\\ByteStream\\' => array($vendorDir . '/amphp/byte-stream/lib'), 'Amp\\Artax\\' => array($vendorDir . '/amphp/artax/lib'), 'Amp\\' => array($vendorDir . '/amphp/amp/lib'), ); <?php /* * This file is part of Composer. * * (c) Nils Adermann <naderman@naderman.de> * Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Autoload; /** * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. * * $loader = new \Composer\Autoload\ClassLoader(); * * // register classes with namespaces * $loader->add('Symfony\Component', __DIR__.'/component'); * $loader->add('Symfony', __DIR__.'/framework'); * * // activate the autoloader * $loader->register(); * * // to enable searching the include path (eg. for PEAR packages) * $loader->setUseIncludePath(true); * * In this example, if you try to use a class in the Symfony\Component * namespace or one of its children (Symfony\Component\Console for instance), * the autoloader will first look for the class under the component/ * directory, and it will then fallback to the framework/ directory if not * found before giving up. * * This class is loosely based on the Symfony UniversalClassLoader. * * @author Fabien Potencier <fabien@symfony.com> * @author Jordi Boggiano <j.boggiano@seld.be> * @see http://www.php-fig.org/psr/psr-0/ * @see http://www.php-fig.org/psr/psr-4/ */ class ClassLoader { // PSR-4 private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); private $fallbackDirsPsr4 = array(); // PSR-0 private $prefixesPsr0 = array(); private $fallbackDirsPsr0 = array(); private $useIncludePath = false; private $classMap = array(); private $classMapAuthoritative = false; private $missingClasses = array(); private $apcuPrefix; public function getPrefixes() { if (!empty($this->prefixesPsr0)) { return call_user_func_array('array_merge', $this->prefixesPsr0); } return array(); } public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } public function getFallbackDirs() { return $this->fallbackDirsPsr0; } public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } public function getClassMap() { return $this->classMap; } /** * @param array $classMap Class to filename map */ public function addClassMap(array $classMap) { if ($this->classMap) { $this->classMap = array_merge($this->classMap, $classMap); } else { $this->classMap = $classMap; } } /** * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * * @param string $prefix The prefix * @param array|string $paths The PSR-0 root directories * @param bool $prepend Whether to prepend the directories */ public function add($prefix, $paths, $prepend = false) { if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( (array) $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, (array) $paths ); } return; } $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { $this->prefixesPsr0[$first][$prefix] = (array) $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( (array) $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], (array) $paths ); } } /** * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' * @param array|string $paths The PSR-4 base directories * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException */ public function addPsr4($prefix, $paths, $prepend = false) { if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( (array) $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, (array) $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { // Register directories for a new namespace. $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( (array) $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], (array) $paths ); } } /** * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * * @param string $prefix The prefix * @param array|string $paths The PSR-0 base directories */ public function set($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr0 = (array) $paths; } else { $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; } } /** * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' * @param array|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException */ public function setPsr4($prefix, $paths) { if (!$prefix) { $this->fallbackDirsPsr4 = (array) $paths; } else { $length = strlen($prefix); if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } } /** * Turns on searching the include path for class files. * * @param bool $useIncludePath */ public function setUseIncludePath($useIncludePath) { $this->useIncludePath = $useIncludePath; } /** * Can be used to check if the autoloader uses the include path to check * for classes. * * @return bool */ public function getUseIncludePath() { return $this->useIncludePath; } /** * Turns off searching the prefix and fallback directories for classes * that have not been registered with the class map. * * @param bool $classMapAuthoritative */ public function setClassMapAuthoritative($classMapAuthoritative) { $this->classMapAuthoritative = $classMapAuthoritative; } /** * Should class lookup fail if not found in the current class map? * * @return bool */ public function isClassMapAuthoritative() { return $this->classMapAuthoritative; } /** * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix */ public function setApcuPrefix($apcuPrefix) { $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** * The APCu prefix in use, or null if APCu caching is not enabled. * * @return string|null */ public function getApcuPrefix() { return $this->apcuPrefix; } /** * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } /** * Unregisters this instance as an autoloader. */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } /** * Loads the given class or interface. * * @param string $class The name of the class * @return bool|null True if loaded, null otherwise */ public function loadClass($class) { if ($file = $this->findFile($class)) { includeFile($file); return true; } } /** * Finds the path to the file where the class is defined. * * @param string $class The name of the class * * @return string|false The path if found, false otherwise */ public function findFile($class) { // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { return false; } if (null !== $this->apcuPrefix) { $file = apcu_fetch($this->apcuPrefix.$class, $hit); if ($hit) { return $file; } } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM if (false === $file && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } if (null !== $this->apcuPrefix) { apcu_add($this->apcuPrefix.$class, $file); } if (false === $file) { // Remember that this class does not exist. $this->missingClasses[$class] = true; } return $file; } private function findFileWithExtension($class, $ext) { // PSR-4 lookup $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; if (isset($this->prefixLengthsPsr4[$first])) { $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { if (file_exists($file = $dir . $pathEnd)) { return $file; } } } } } // PSR-4 fallback dirs foreach ($this->fallbackDirsPsr4 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { return $file; } } // PSR-0 lookup if (false !== $pos = strrpos($class, '\\')) { // namespaced class name $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); } else { // PEAR-like class name $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; } if (isset($this->prefixesPsr0[$first])) { foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { foreach ($dirs as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } } } } // PSR-0 fallback dirs foreach ($this->fallbackDirsPsr0 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { return $file; } } // PSR-0 include paths. if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } return false; } } /** * Scope isolated include. * * Prevents access to $this/self from included files. */ function includeFile($file) { include $file; } [ { "name": "amphp/amp", "version": "v2.1.2", "version_normalized": "2.1.2.0", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", "reference": "f824f0df1da2cc042934fa267d7a227fff9276c9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/amp/zipball/f824f0df1da2cc042934fa267d7a227fff9276c9", "reference": "f824f0df1da2cc042934fa267d7a227fff9276c9", "shasum": "" }, "require": { "php": ">=7" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "ext-json": "*", "phpstan/phpstan": "^0.8.5", "phpunit/phpunit": "^6.0.9", "react/promise": "^2" }, "time": "2019-05-31T18:42:02+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "Amp\\": "lib" }, "files": [ "lib/functions.php", "lib/Internal/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "A non-blocking concurrency framework for PHP applications.", "homepage": "http://amphp.org/amp", "keywords": [ "async", "asynchronous", "awaitable", "concurrency", "event", "event-loop", "future", "non-blocking", "promise" ] }, { "name": "amphp/artax", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/amphp/artax.git", "reference": "fb8c11fe7530be274483adf63346cc1b0fa1714a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/artax/zipball/fb8c11fe7530be274483adf63346cc1b0fa1714a", "reference": "fb8c11fe7530be274483adf63346cc1b0fa1714a", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.1.6", "amphp/file": "^0.2 || ^0.3", "amphp/socket": "^0.10.5", "amphp/uri": "^0.1", "kelunik/certificate": "^1.1", "php": ">=7.0" }, "require-dev": { "amphp/http-server": "^1", "amphp/phpunit-util": "^1", "friendsofphp/php-cs-fixer": "^2.3", "phpunit/phpunit": "^6" }, "time": "2019-05-29T17:21:51+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "Amp\\Artax\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@gmail.com" } ], "description": "Asynchronous parallel HTTP/1.1 client built on the Amp concurrency framework", "homepage": "https://github.com/amphp/artax", "keywords": [ "async", "client", "http", "non-blocking", "parallel", "rest" ] }, { "name": "amphp/byte-stream", "version": "v1.6.0", "version_normalized": "1.6.0.0", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", "reference": "c75af3778b5511deb1d760e4709cade2dabc2295" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/byte-stream/zipball/c75af3778b5511deb1d760e4709cade2dabc2295", "reference": "c75af3778b5511deb1d760e4709cade2dabc2295", "shasum": "" }, "require": { "amphp/amp": "^2" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "friendsofphp/php-cs-fixer": "^2.3", "infection/infection": "^0.9.3", "phpunit/phpunit": "^6" }, "time": "2019-06-03T21:45:17+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\ByteStream\\": "lib" }, "files": [ "lib/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "A stream abstraction to make working with non-blocking I/O simple.", "homepage": "http://amphp.org/byte-stream", "keywords": [ "amp", "amphp", "async", "io", "non-blocking", "stream" ] }, { "name": "amphp/cache", "version": "v1.2.0", "version_normalized": "1.2.0.0", "source": { "type": "git", "url": "https://github.com/amphp/cache.git", "reference": "ab2339e465d9d383dc748f288d530fd7cd7aadea" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/cache/zipball/ab2339e465d9d383dc748f288d530fd7cd7aadea", "reference": "ab2339e465d9d383dc748f288d530fd7cd7aadea", "shasum": "" }, "require": { "amphp/amp": "^2" }, "require-dev": { "amphp/phpunit-util": "^1", "friendsofphp/php-cs-fixer": "^2.3", "phpunit/phpunit": "^6" }, "time": "2017-10-04T19:22:12+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Cache\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" } ], "description": "A promise-aware caching API for Amp.", "homepage": "https://github.com/amphp/cache" }, { "name": "amphp/dns", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/amphp/dns.git", "reference": "aa1892bd" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/dns/zipball/aa1892bd", "reference": "aa1892bd", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.1", "amphp/cache": "^1.2", "amphp/parser": "^1", "amphp/windows-registry": "^0.3", "daverandom/libdns": "^2.0.1", "ext-filter": "*", "php": ">=7.0" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6" }, "time": "2019-06-13T16:38:23+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Dns\\": "lib" }, "files": [ "lib/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Chris Wright", "email": "addr@daverandom.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Async DNS resolution for Amp.", "homepage": "https://github.com/amphp/dns", "keywords": [ "amp", "amphp", "async", "client", "dns", "resolve" ] }, { "name": "amphp/file", "version": "v0.3.x-dev", "version_normalized": "0.3.9999999.9999999-dev", "source": { "type": "git", "url": "https://github.com/amphp/file.git", "reference": "ba57064e7c0cbcae89429afb2ba93b8f31bd7fc8" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/file/zipball/ba57064e7c0cbcae89429afb2ba93b8f31bd7fc8", "reference": "ba57064e7c0cbcae89429afb2ba93b8f31bd7fc8", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1", "amphp/parallel": "^1" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6" }, "time": "2019-03-01T16:38:04+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "Amp\\File\\": "lib" }, "files": [ "lib/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Allows non-blocking access to the filesystem for Amp.", "homepage": "https://github.com/amphp/file", "keywords": [ "amp", "amphp", "async", "disk", "file", "filesystem", "io", "non-blocking", "static" ] }, { "name": "amphp/http", "version": "v1.2.0", "version_normalized": "1.2.0.0", "source": { "type": "git", "url": "https://github.com/amphp/http.git", "reference": "91c023aec2219aae6cec49a4dc576fb617916f2b" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/http/zipball/91c023aec2219aae6cec49a4dc576fb617916f2b", "reference": "91c023aec2219aae6cec49a4dc576fb617916f2b", "shasum": "" }, "require": { "php": ">=7" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "phpunit/phpunit": "^6.5" }, "time": "2019-06-10T17:53:40+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Http\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "description": "Basic HTTP primitives which can be shared by servers and clients." }, { "name": "amphp/parallel", "version": "v1.1.1", "version_normalized": "1.1.1.0", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", "reference": "687776dc6933af4c6009ac58f915faf45e8463ce" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/parallel/zipball/687776dc6933af4c6009ac58f915faf45e8463ce", "reference": "687776dc6933af4c6009ac58f915faf45e8463ce", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.5", "amphp/parser": "^1", "amphp/process": "^1", "amphp/sync": "^1.0.1" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6" }, "suggest": { "ext-pthreads": "Required for thread contexts" }, "time": "2019-01-09T21:31:46+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Parallel\\": "lib" }, "files": [ "lib/Worker/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Stephen Coakley", "email": "me@stephencoakley.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Parallel processing component for Amp.", "homepage": "https://github.com/amphp/parallel", "keywords": [ "async", "asynchronous", "concurrent", "multi-processing", "multi-threading" ] }, { "name": "amphp/parser", "version": "v1.0.0", "version_normalized": "1.0.0.0", "source": { "type": "git", "url": "https://github.com/amphp/parser.git", "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/parser/zipball/f83e68f03d5b8e8e0365b8792985a7f341c57ae1", "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1", "shasum": "" }, "require": { "php": ">=7" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3", "phpunit/phpunit": "^6" }, "time": "2017-06-06T05:29:10+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Parser\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "A generator parser to make streaming parsers simple.", "homepage": "https://github.com/amphp/parser", "keywords": [ "async", "non-blocking", "parser", "stream" ] }, { "name": "amphp/process", "version": "v1.1.0", "version_normalized": "1.1.0.0", "source": { "type": "git", "url": "https://github.com/amphp/process.git", "reference": "355b1e561b01c16ab3d78fada1ad47ccc96df70e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/process/zipball/355b1e561b01c16ab3d78fada1ad47ccc96df70e", "reference": "355b1e561b01c16ab3d78fada1ad47ccc96df70e", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.4", "php": ">=7" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6" }, "time": "2019-02-26T16:33:03+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Process\\": "lib" }, "files": [ "lib/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Asynchronous process manager.", "homepage": "https://github.com/amphp/process" }, { "name": "amphp/socket", "version": "v0.10.x-dev", "version_normalized": "0.10.9999999.9999999-dev", "source": { "type": "git", "url": "https://github.com/amphp/socket.git", "reference": "e90cda8929462bc563351bf82753ff48d9796ddc" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/socket/zipball/e90cda8929462bc563351bf82753ff48d9796ddc", "reference": "e90cda8929462bc563351bf82753ff48d9796ddc", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.1", "amphp/dns": "^0.9", "amphp/uri": "^0.1", "php": ">=7.0" }, "require-dev": { "amphp/phpunit-util": "^1", "friendsofphp/php-cs-fixer": "^2.3", "phpunit/phpunit": "^6" }, "time": "2019-03-26T04:17:14+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "Amp\\Socket\\": "src" }, "files": [ "src/functions.php", "src/Internal/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@gmail.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Async socket connection / server tools for Amp.", "homepage": "https://github.com/amphp/socket", "keywords": [ "amp", "async", "encryption", "non-blocking", "sockets", "tcp", "tls" ] }, { "name": "amphp/sync", "version": "v1.0.1", "version_normalized": "1.0.1.0", "source": { "type": "git", "url": "https://github.com/amphp/sync.git", "reference": "a1d8f244eb19e3e2a96abc4686cebc80995bbc90" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/sync/zipball/a1d8f244eb19e3e2a96abc4686cebc80995bbc90", "reference": "a1d8f244eb19e3e2a96abc4686cebc80995bbc90", "shasum": "" }, "require": { "amphp/amp": "^2" }, "require-dev": { "amphp/phpunit-util": "^1", "friendsofphp/php-cs-fixer": "^2.3", "phpunit/phpunit": "^6" }, "time": "2017-11-29T21:48:53+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Sync\\": "lib" }, "files": [ "lib/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Stephen Coakley", "email": "me@stephencoakley.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Mutex, Semaphore, and other synchronization tools for Amp.", "homepage": "https://github.com/amphp/sync", "keywords": [ "async", "asynchronous", "mutex", "semaphore", "synchronization" ] }, { "name": "amphp/uri", "version": "v0.1.4", "version_normalized": "0.1.4.0", "source": { "type": "git", "url": "https://github.com/amphp/uri.git", "reference": "30065946d5c69f44c8a47bf8838244029984ff61" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/uri/zipball/30065946d5c69f44c8a47bf8838244029984ff61", "reference": "30065946d5c69f44c8a47bf8838244029984ff61", "shasum": "" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3", "phpunit/phpunit": "^6" }, "time": "2019-05-13T18:25:34+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\Uri\\": "src" }, "files": [ "src/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey" } ], "description": "Uri Parser and Resolver.", "homepage": "https://github.com/amphp/uri" }, { "name": "amphp/websocket", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/amphp/websocket.git", "reference": "db2da8c5b3ed22eae37da5ffa10ab3ea8de19342" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/websocket/zipball/db2da8c5b3ed22eae37da5ffa10ab3ea8de19342", "reference": "db2da8c5b3ed22eae37da5ffa10ab3ea8de19342", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.5", "amphp/socket": "^0.10", "cash/lrucache": "^1.0", "php": ">=7.1" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6" }, "suggest": { "ext-zlib": "Required for compression" }, "time": "2019-04-06T14:39:18+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "Amp\\Websocket\\": "src" }, "files": [ "src/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Shared code for websocket servers and clients.", "keywords": [ "amp", "amphp", "async", "http", "non-blocking", "websocket" ] }, { "name": "amphp/websocket-client", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/amphp/websocket-client.git", "reference": "aff808025637bd705672338b4904ad03a4dbdc04" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/websocket-client/zipball/aff808025637bd705672338b4904ad03a4dbdc04", "reference": "aff808025637bd705672338b4904ad03a4dbdc04", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/http": "^1.1", "amphp/socket": "^0.10", "amphp/websocket": "dev-master as 1.0", "league/uri-schemes": "^1.2", "php": ">=7.1" }, "require-dev": { "amphp/http-server": "^1", "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "amphp/websocket-server": "dev-master as 2.0", "phpunit/phpunit": "^6" }, "time": "2019-04-06T14:53:32+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "Amp\\Websocket\\Client\\": "src" }, "files": [ "src/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "description": "Async WebSocket client for PHP based on Amp.", "keywords": [ "amp", "amphp", "async", "client", "http", "non-blocking", "websocket" ] }, { "name": "amphp/windows-registry", "version": "v0.3.2", "version_normalized": "0.3.2.0", "source": { "type": "git", "url": "https://github.com/amphp/windows-registry.git", "reference": "834af7a30ad7c006b0326ccd2686ddc6e6943366" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/amphp/windows-registry/zipball/834af7a30ad7c006b0326ccd2686ddc6e6943366", "reference": "834af7a30ad7c006b0326ccd2686ddc6e6943366", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.4", "amphp/process": "^1" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master" }, "time": "2018-10-24T03:34:54+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\WindowsRegistry\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "description": "Windows Registry Reader." }, { "name": "cash/lrucache", "version": "1.0.0", "version_normalized": "1.0.0.0", "source": { "type": "git", "url": "https://github.com/cash/LRUCache.git", "reference": "4fa4c6834cec59690b43526c4da41d6153026289" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/cash/LRUCache/zipball/4fa4c6834cec59690b43526c4da41d6153026289", "reference": "4fa4c6834cec59690b43526c4da41d6153026289", "shasum": "" }, "require": { "php": ">=5.3.0" }, "time": "2013-09-20T18:59:12+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-0": { "cash": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Cash Costello", "email": "cash.costello@gmail.com" } ], "description": "An efficient memory-based Least Recently Used (LRU) cache", "homepage": "https://github.com/cash/LRUCache", "keywords": [ "cache", "lru" ] }, { "name": "danog/dns-over-https", "version": "0.1.1", "version_normalized": "0.1.1.0", "source": { "type": "git", "url": "https://github.com/danog/dns-over-https.git", "reference": "44ed129aeb9504b8fa8aa5a7f301001a1a0b13e1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/danog/dns-over-https/zipball/44ed129aeb9504b8fa8aa5a7f301001a1a0b13e1", "reference": "44ed129aeb9504b8fa8aa5a7f301001a1a0b13e1", "shasum": "" }, "require": { "amphp/amp": "^2", "amphp/artax": "dev-master", "amphp/cache": "^1.2", "amphp/dns": "dev-master as v0.9.x-dev", "amphp/parser": "^1", "danog/libdns-json": "^0.1", "daverandom/libdns": "^2.0.1", "ext-filter": "*", "ext-json": "*", "php": ">=7.0" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6" }, "time": "2019-06-12T18:45:19+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Amp\\DoH\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Chris Wright", "email": "addr@daverandom.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "description": "Async DNS-over-HTTPS resolution for Amp.", "homepage": "https://github.com/danog/dns-over-https", "keywords": [ "amp", "amphp", "async", "client", "dns", "dns-over-https", "doh", "https", "resolve" ] }, { "name": "danog/libdns-json", "version": "0.1", "version_normalized": "0.1.0.0", "source": { "type": "git", "url": "https://github.com/danog/LibDNSJson.git", "reference": "24908c65f44d54db04c2c427ba9e752be6701fd0" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/danog/LibDNSJson/zipball/24908c65f44d54db04c2c427ba9e752be6701fd0", "reference": "24908c65f44d54db04c2c427ba9e752be6701fd0", "shasum": "" }, "require": { "daverandom/libdns": "^2.0.1", "ext-json": "*", "php": ">=7.0" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "phpunit/phpunit": "^6" }, "time": "2019-06-12T12:39:17+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "danog\\LibDNSJson\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Chris Wright", "email": "addr@daverandom.com" }, { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "description": "Encoder/decoder for google's JSON DNS message format based on libdns", "homepage": "https://github.com/danog/libdns-json", "keywords": [ "dns", "dns-over-https", "doh", "https", "json", "libdns", "message" ] }, { "name": "danog/madelineproto", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/danog/MadelineProto.git", "reference": "8cd870366ac46cb66f0e00975da38d06fb8bf1d7" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/danog/MadelineProto/zipball/8cd870366ac46cb66f0e00975da38d06fb8bf1d7", "reference": "8cd870366ac46cb66f0e00975da38d06fb8bf1d7", "shasum": "" }, "require": { "amphp/amp": "^2.0", "amphp/artax": "dev-master as 3.0.99", "amphp/byte-stream": "^1.6", "amphp/dns": "dev-master#aa1892bdf13b787d759df6f2523e8027a434d927 as v0.9.x-dev", "amphp/file": "^0.3", "amphp/socket": "^0.10", "amphp/uri": "^0.1.4", "amphp/websocket": "dev-master as 1", "amphp/websocket-client": "dev-master as 1", "danog/dns-over-https": "^0.1", "danog/magicalserializer": "^1.0", "danog/primemodule": "^1", "erusev/parsedown": "^1.6", "ext-fileinfo": "*", "ext-json": "*", "ext-mbstring": "*", "ext-xml": "*", "php": ">=7.1.0", "phpseclib/phpseclib": "dev-master#c62fc0c73373426d3ff8729f10e82e09e1874866 as 2.0.15", "vlucas/phpdotenv": "^3" }, "conflict": { "krakjoe/pthreads-polyfill": "*" }, "require-dev": { "ennexa/amp-update-cache": "dev-master", "phpdocumentor/reflection-docblock": "^3.1", "phpunit/phpunit": "^8" }, "suggest": { "ext-libtgvoip": "Install the php-libtgvoip extension to make phone calls (https://github.com/danog/php-libtgvoip)" }, "time": "2019-06-17T10:19:46+00:00", "type": "project", "installation-source": "source", "autoload": { "psr-0": { "danog\\MadelineProto\\": "src/" }, "files": [ "src/BigIntegor.php", "src/YieldReturnValue.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "AGPL-3.0-only" ], "authors": [ { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "description": "PHP implementation of telegram's MTProto protocol.", "homepage": "https://daniil.it/MadelineProto", "keywords": [ "GB", "Messenger", "audio", "bytes", "client", "files", "mtproto", "php", "protocol", "stickers", "telegram", "video" ] }, { "name": "danog/magicalserializer", "version": "1.0", "version_normalized": "1.0.0.0", "source": { "type": "git", "url": "https://github.com/danog/MagicalSerializer.git", "reference": "87b6ed05a86021e9364f31133089bb83980d5e24" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/danog/MagicalSerializer/zipball/87b6ed05a86021e9364f31133089bb83980d5e24", "reference": "87b6ed05a86021e9364f31133089bb83980d5e24", "shasum": "" }, "time": "2018-02-20T10:35:49+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-0": { "danog\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "AGPL-3.0-only" ], "authors": [ { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "description": "Serialize Volatile, Threaded or any other internal PHP class!", "homepage": "https://daniil.it/MagicalSerializer", "keywords": [ "pthreads", "serializable", "serialize", "threading", "volatile" ] }, { "name": "danog/primemodule", "version": "1.0.3", "version_normalized": "1.0.3.0", "source": { "type": "git", "url": "https://github.com/danog/PrimeModule.git", "reference": "a18918c4092d6d8696521b05a59a3cdb5cdc061e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/danog/PrimeModule/zipball/a18918c4092d6d8696521b05a59a3cdb5cdc061e", "reference": "a18918c4092d6d8696521b05a59a3cdb5cdc061e", "shasum": "" }, "suggest": { "ext-primemodule": "Install the native C++ extension for extremely fast factorization (https://github.com/danog/PrimeModule-ext)" }, "time": "2018-03-21T10:47:51+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-0": { "danog\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "AGPL-3.0-only" ], "authors": [ { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ], "description": "Prime module capable of doing prime factorization of huge numbers very quickly.\"" }, { "name": "daverandom/libdns", "version": "2.x-dev", "version_normalized": "2.9999999.9999999.9999999-dev", "source": { "type": "git", "url": "https://github.com/DaveRandom/LibDNS.git", "reference": "1ecd825b6fa9bb3fddc07751997e29dc78749b95" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/1ecd825b6fa9bb3fddc07751997e29dc78749b95", "reference": "1ecd825b6fa9bb3fddc07751997e29dc78749b95", "shasum": "" }, "require": { "ext-ctype": "*", "php": ">=7.0" }, "suggest": { "ext-intl": "Required for IDN support" }, "time": "2018-01-10T15:56:17+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "LibDNS\\": "src/" }, "files": [ "src/functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "DNS protocol implementation written in pure PHP", "keywords": [ "dns" ] }, { "name": "erusev/parsedown", "version": "1.8.0-beta-7", "version_normalized": "1.8.0.0-beta7", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", "reference": "fe7a50eceb4a3c867cc9fa9c0aa906b1067d1955" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/erusev/parsedown/zipball/fe7a50eceb4a3c867cc9fa9c0aa906b1067d1955", "reference": "fe7a50eceb4a3c867cc9fa9c0aa906b1067d1955", "shasum": "" }, "require": { "ext-mbstring": "*", "php": ">=5.3.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35" }, "time": "2019-03-17T18:47:21+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-0": { "Parsedown": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Emanuil Rusev", "email": "hello@erusev.com", "homepage": "http://erusev.com" } ], "description": "Parser for Markdown.", "homepage": "http://parsedown.org", "keywords": [ "markdown", "parser" ] }, { "name": "kelunik/certificate", "version": "v1.1.2", "version_normalized": "1.1.2.0", "source": { "type": "git", "url": "https://github.com/kelunik/certificate.git", "reference": "56542e62d51533d04d0a9713261fea546bff80f6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/kelunik/certificate/zipball/56542e62d51533d04d0a9713261fea546bff80f6", "reference": "56542e62d51533d04d0a9713261fea546bff80f6", "shasum": "" }, "require": { "ext-openssl": "*", "php": ">=5.4" }, "require-dev": { "fabpot/php-cs-fixer": "^1.9", "phpunit/phpunit": "^4.8" }, "time": "2019-05-29T19:02:31+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Kelunik\\Certificate\\": "lib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "description": "Access certificate details and transform between different formats.", "keywords": [ "DER", "certificate", "certificates", "openssl", "pem", "x509" ] }, { "name": "league/uri-interfaces", "version": "1.1.1", "version_normalized": "1.1.1.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", "reference": "081760c53a4ce76c9935a755a21353610f5495f6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/081760c53a4ce76c9935a755a21353610f5495f6", "reference": "081760c53a4ce76c9935a755a21353610f5495f6", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0.0" }, "time": "2018-11-05T14:00:06+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "League\\Uri\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Ignace Nyamagana Butera", "email": "nyamsprod@gmail.com", "homepage": "https://nyamsprod.com" } ], "description": "Common interface for URI representation", "homepage": "http://github.com/thephpleague/uri-interfaces", "keywords": [ "rfc3986", "rfc3987", "uri", "url" ] }, { "name": "league/uri-parser", "version": "1.4.1", "version_normalized": "1.4.1.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-parser.git", "reference": "671548427e4c932352d9b9279fdfa345bf63fa00" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/thephpleague/uri-parser/zipball/671548427e4c932352d9b9279fdfa345bf63fa00", "reference": "671548427e4c932352d9b9279fdfa345bf63fa00", "shasum": "" }, "require": { "php": ">=7.0.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", "phpstan/phpstan": "^0.9.2", "phpstan/phpstan-phpunit": "^0.9.4", "phpstan/phpstan-strict-rules": "^0.9.0", "phpunit/phpunit": "^6.0" }, "suggest": { "ext-intl": "Allow parsing RFC3987 compliant hosts", "league/uri-schemes": "Allow validating and normalizing URI parsing results" }, "time": "2018-11-22T07:55:51+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "League\\Uri\\": "src" }, "files": [ "src/functions_include.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Ignace Nyamagana Butera", "email": "nyamsprod@gmail.com", "homepage": "https://nyamsprod.com" } ], "description": "userland URI parser RFC 3986 compliant", "homepage": "https://github.com/thephpleague/uri-parser", "keywords": [ "parse_url", "parser", "rfc3986", "rfc3987", "uri", "url" ] }, { "name": "league/uri-schemes", "version": "1.2.1", "version_normalized": "1.2.1.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-schemes.git", "reference": "f821a444785724bcc9bc244b1173b9d6ca4d71e6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/thephpleague/uri-schemes/zipball/f821a444785724bcc9bc244b1173b9d6ca4d71e6", "reference": "f821a444785724bcc9bc244b1173b9d6ca4d71e6", "shasum": "" }, "require": { "ext-fileinfo": "*", "league/uri-interfaces": "^1.1", "league/uri-parser": "^1.4.0", "php": ">=7.0.13", "psr/http-message": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", "phpstan/phpstan": "^0.9.2", "phpstan/phpstan-phpunit": "^0.9.4", "phpstan/phpstan-strict-rules": "^0.9.0", "phpunit/phpunit": "^6.0" }, "suggest": { "ext-intl": "Allow parsing RFC3987 compliant hosts", "league/uri-manipulations": "Needed to easily manipulate URI objects" }, "time": "2018-11-26T08:09:30+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "League\\Uri\\": "src" }, "files": [ "src/functions_include.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Ignace Nyamagana Butera", "email": "nyamsprod@gmail.com", "homepage": "https://nyamsprod.com" } ], "description": "URI manipulation library", "homepage": "http://uri.thephpleague.com", "keywords": [ "data-uri", "file", "ftp", "http", "https", "parse_url", "psr-7", "rfc3986", "uri", "url", "ws", "wss" ] }, { "name": "paragonie/constant_time_encoding", "version": "v1.x-dev", "version_normalized": "1.9999999.9999999.9999999-dev", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", "shasum": "" }, "require": { "php": "^5.3|^7" }, "require-dev": { "paragonie/random_compat": "^1.4|^2", "phpunit/phpunit": "4.*|5.*", "vimeo/psalm": "^0.3|^1" }, "time": "2018-04-30T17:57:16+00:00", "type": "library", "installation-source": "source", "autoload": { "psr-4": { "ParagonIE\\ConstantTime\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Paragon Initiative Enterprises", "email": "security@paragonie.com", "homepage": "https://paragonie.com", "role": "Maintainer" }, { "name": "Steve 'Sc00bz' Thomas", "email": "steve@tobtu.com", "homepage": "https://www.tobtu.com", "role": "Original Developer" } ], "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", "keywords": [ "base16", "base32", "base32_decode", "base32_encode", "base64", "base64_decode", "base64_encode", "bin2hex", "encoding", "hex", "hex2bin", "rfc4648" ] }, { "name": "paragonie/random_compat", "version": "v2.0.18", "version_normalized": "2.0.18.0", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", "shasum": "" }, "require": { "php": ">=5.2.0" }, "require-dev": { "phpunit/phpunit": "4.*|5.*" }, "suggest": { "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." }, "time": "2019-01-03T20:59:08+00:00", "type": "library", "installation-source": "dist", "autoload": { "files": [ "lib/random.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Paragon Initiative Enterprises", "email": "security@paragonie.com", "homepage": "https://paragonie.com" } ], "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ "csprng", "polyfill", "pseudorandom", "random" ] }, { "name": "phpoption/phpoption", "version": "1.5.0", "version_normalized": "1.5.0.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { "phpunit/phpunit": "4.7.*" }, "time": "2015-07-25T16:39:46+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.3-dev" } }, "installation-source": "dist", "autoload": { "psr-0": { "PhpOption\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "Apache2" ], "authors": [ { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" } ], "description": "Option Type for PHP", "keywords": [ "language", "option", "php", "type" ] }, { "name": "phpseclib/phpseclib", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/danog/phpseclib", "reference": "2dc143a4865b00998240068e72fcfc0c10a3d9f7" }, "require": { "paragonie/constant_time_encoding": "^1", "paragonie/random_compat": "^1.4|^2.0", "php": ">=5.6.1" }, "require-dev": { "phing/phing": "~2.7", "phpunit/phpunit": "^4.8.35|^5.7|^6.0", "sami/sami": "~2.0", "squizlabs/php_codesniffer": "~2.0" }, "suggest": { "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." }, "time": "2019-06-17T10:22:52+00:00", "type": "library", "installation-source": "source", "autoload": { "files": [ "phpseclib/bootstrap.php" ], "psr-4": { "phpseclib\\": "phpseclib/" } }, "license": [ "MIT" ], "authors": [ { "name": "Jim Wigginton", "email": "terrafrost@php.net", "role": "Lead Developer" }, { "name": "Patrick Monnerat", "email": "pm@datasphere.ch", "role": "Developer" }, { "name": "Andreas Fischer", "email": "bantu@phpbb.com", "role": "Developer" }, { "name": "Hans-Jürgen Petrich", "email": "petrich@tronic-media.com", "role": "Developer" }, { "name": "Graham Campbell", "email": "graham@alt-three.com", "role": "Developer" } ], "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", "homepage": "http://phpseclib.sourceforge.net", "keywords": [ "BigInteger", "aes", "asn.1", "asn1", "blowfish", "crypto", "cryptography", "encryption", "rsa", "security", "sftp", "signature", "signing", "ssh", "twofish", "x.509", "x509" ] }, { "name": "psr/http-message", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "shasum": "" }, "require": { "php": ">=5.3.0" }, "time": "2016-08-06T14:39:51+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "installation-source": "source", "autoload": { "psr-4": { "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "PHP-FIG", "homepage": "http://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", "homepage": "https://github.com/php-fig/http-message", "keywords": [ "http", "http-message", "psr", "psr-7", "request", "response" ] }, { "name": "symfony/polyfill-ctype", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", "reference": "82ebae02209c21113908c229e9883c419720738a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", "reference": "82ebae02209c21113908c229e9883c419720738a", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { "ext-ctype": "For best performance" }, "time": "2019-02-06T07:57:58+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.11-dev" } }, "installation-source": "source", "autoload": { "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, "files": [ "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", "ctype", "polyfill", "portable" ] }, { "name": "vlucas/phpdotenv", "version": "dev-master", "version_normalized": "9999999-dev", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", "reference": "5084b23845c24dbff8ac6c204290c341e4776c92" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/5084b23845c24dbff8ac6c204290c341e4776c92", "reference": "5084b23845c24dbff8ac6c204290c341e4776c92", "shasum": "" }, "require": { "php": "^5.4 || ^7.0", "phpoption/phpoption": "^1.5", "symfony/polyfill-ctype": "^1.9" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0" }, "time": "2019-06-15T22:40:20+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "3.4-dev" } }, "installation-source": "source", "autoload": { "psr-4": { "Dotenv\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Vance Lucas", "email": "vance@vancelucas.com", "homepage": "http://www.vancelucas.com" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", "keywords": [ "dotenv", "env", "environment" ] } ] <?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( ); <?php // autoload_namespaces.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'danog\\MadelineProto\\' => array($vendorDir . '/danog/madelineproto/src'), 'danog\\' => array($vendorDir . '/danog/magicalserializer/src', $vendorDir . '/danog/primemodule/lib'), 'cash' => array($vendorDir . '/cash/lrucache/src'), 'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src'), 'Parsedown' => array($vendorDir . '/erusev/parsedown'), ); { "name": "amphp/amp", "homepage": "http://amphp.org/amp", "description": "A non-blocking concurrency framework for PHP applications.", "keywords": [ "async", "asynchronous", "concurrency", "promise", "awaitable", "future", "non-blocking", "event", "event-loop" ], "license": "MIT", "authors": [ { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "require": { "php": ">=7" }, "require-dev": { "ext-json": "*", "amphp/phpunit-util": "^1", "amphp/php-cs-fixer-config": "dev-master", "react/promise": "^2", "phpunit/phpunit": "^6.0.9", "phpstan/phpstan": "^0.8.5" }, "autoload": { "psr-4": { "Amp\\": "lib" }, "files": [ "lib/functions.php", "lib/Internal/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Test\\": "test" } }, "support": { "issues": "https://github.com/amphp/amp/issues", "irc": "irc://irc.freenode.org/amphp" }, "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "config": { "platform": { "php": "7.0.0" } }, "scripts": { "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit", "code-style": "@php ./vendor/bin/php-cs-fixer fix" } } <?php namespace Amp; /** * A TimeoutCancellationToken automatically requests cancellation after the timeout has elapsed. */ final class TimeoutCancellationToken implements CancellationToken { /** @var string */ private $watcher; /** @var \Amp\CancellationToken */ private $token; /** * @param int $timeout Milliseconds until cancellation is requested. */ public function __construct(int $timeout) { $source = new CancellationTokenSource; $this->token = $source->getToken(); $this->watcher = Loop::delay($timeout, static function () use ($source) { $source->cancel(new TimeoutException); }); Loop::unreference($this->watcher); } /** * Cancels the delay watcher. */ public function __destruct() { Loop::cancel($this->watcher); } /** * {@inheritdoc} */ public function subscribe(callable $callback): string { return $this->token->subscribe($callback); } /** * {@inheritdoc} */ public function unsubscribe(string $id) { $this->token->unsubscribe($id); } /** * {@inheritdoc} */ public function isRequested(): bool { return $this->token->isRequested(); } /** * {@inheritdoc} */ public function throwIfRequested() { $this->token->throwIfRequested(); } } <?php namespace Amp; /** * Will be thrown in case an operation is cancelled. * * @see CancellationToken * @see CancellationTokenSource */ class CancelledException extends \Exception { public function __construct(\Throwable $previous = null) { parent::__construct("The operation was cancelled", 0, $previous); } } <?php namespace Amp; /** * Emitter is a container for an iterator that can emit values using the emit() method and completed using the * complete() and fail() methods of this object. The contained iterator may be accessed using the iterate() * method. This object should not be part of a public API, but used internally to create and emit values to an * iterator. */ final class Emitter { /** @var object Has public emit, complete, and fail methods. */ private $emitter; /** @var \Amp\Iterator Hides producer methods. */ private $iterator; public function __construct() { $this->emitter = new class implements Iterator { use Internal\Producer { emit as public; complete as public; fail as public; } }; $this->iterator = new Internal\PrivateIterator($this->emitter); } /** * @return \Amp\Promise */ public function iterate(): Iterator { return $this->iterator; } /** * Emits a value to the iterator. * * @param mixed $value * * @return \Amp\Promise */ public function emit($value): Promise { return $this->emitter->emit($value); } /** * Completes the iterator. */ public function complete() { $this->emitter->complete(); } /** * Fails the iterator with the given reason. * * @param \Throwable $reason */ public function fail(\Throwable $reason) { $this->emitter->fail($reason); } } <?php namespace Amp; /** * Defines an asynchronous iterator over a set of values that is designed to be used within a coroutine. */ interface Iterator { /** * Succeeds with true if an emitted value is available by calling getCurrent() or false if the iterator has * resolved. If the iterator fails, the returned promise will fail with the same exception. * * @return \Amp\Promise<bool> * * @throws \Error If the prior promise returned from this method has not resolved. * @throws \Throwable The exception used to fail the iterator. */ public function advance(): Promise; /** * Gets the last emitted value or throws an exception if the iterator has completed. * * @return mixed Value emitted from the iterator. * * @throws \Error If the iterator has resolved or advance() was not called before calling this method. * @throws \Throwable The exception used to fail the iterator. */ public function getCurrent(); } <?php namespace Amp; /** * Thrown if a promise doesn't resolve within a specified timeout. * * @see \Amp\Promise\timeout() */ class TimeoutException extends \Exception { /** * @param string|null $message Exception message. */ public function __construct(string $message = "Operation timed out") { parent::__construct($message); } } <?php namespace Amp; final class Producer implements Iterator { use CallableMaker, Internal\Producer; /** * @param callable(callable(mixed $value): Promise $emit): \Generator $producer * * @throws \Error Thrown if the callable does not return a Generator. */ public function __construct(callable $producer) { $result = $producer($this->callableFromInstanceMethod("emit")); if (!$result instanceof \Generator) { throw new \Error("The callable did not return a Generator"); } $coroutine = new Coroutine($result); $coroutine->onResolve(function ($exception) { if ($this->complete) { return; } if ($exception) { $this->fail($exception); return; } $this->complete(); }); } } <?php namespace Amp; use Amp\Loop\Driver; use Amp\Loop\DriverFactory; use Amp\Loop\InvalidWatcherError; use Amp\Loop\UnsupportedFeatureException; use Amp\Loop\Watcher; /** * Accessor to allow global access to the event loop. * * @see \Amp\Loop\Driver */ final class Loop { /** * @var Driver */ private static $driver; /** * Disable construction as this is a static class. */ private function __construct() { // intentionally left blank } /** * Sets the driver to be used for `Loop::run()`. * * @param Driver $driver */ public static function set(Driver $driver) { try { self::$driver = new class extends Driver { protected function activate(array $watchers) { throw new \Error("Can't activate watcher during garbage collection."); } protected function dispatch(bool $blocking) { throw new \Error("Can't dispatch during garbage collection."); } protected function deactivate(Watcher $watcher) { // do nothing } public function getHandle() { return null; } }; \gc_collect_cycles(); } finally { self::$driver = $driver; } } /** * Run the event loop and optionally execute a callback within the scope of it. * * The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an * error handler or exceptions that would be passed to an error handler but none exists to handle them. * * @param callable|null $callback The callback to execute. * * @return void */ public static function run(callable $callback = null) { if ($callback) { self::$driver->defer($callback); } self::$driver->run(); } /** * Stop the event loop. * * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls * to stop MUST be ignored and MUST NOT raise an exception. * * @return void */ public static function stop() { self::$driver->stop(); } /** * Defer the execution of a callback. * * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be * preserved when executing the callbacks. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function defer(callable $callback, $data = null): string { return self::$driver->defer($callback, $data); } /** * Delay the execution of a callback. * * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which * timers expire first, but timers with the same expiration time MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $delay The amount of time, in milliseconds, to delay the execution for. * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function delay(int $delay, callable $callback, $data = null): string { return self::$driver->delay($delay, $callback, $data); } /** * Repeatedly execute a callback. * * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function repeat(int $interval, callable $callback, $data = null): string { return self::$driver->repeat($interval, $callback, $data); } /** * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function onReadable($stream, callable $callback, $data = null): string { return self::$driver->onReadable($stream, $callback, $data); } /** * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function onWritable($stream, callable $callback, $data = null): string { return self::$driver->onWritable($stream, $callback, $data); } /** * Execute a callback when a signal is received. * * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * * Multiple watchers on the same signal MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. * * @throws UnsupportedFeatureException If signal handling is not supported. */ public static function onSignal(int $signo, callable $callback, $data = null): string { return self::$driver->onSignal($signo, $callback, $data); } /** * Enable a watcher to be active starting in the next tick. * * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public static function enable(string $watcherId) { self::$driver->enable($watcherId); } /** * Disable a watcher immediately. * * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer * watcher isn't executed in this tick. * * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an * invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public static function disable(string $watcherId) { if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { // Prior to PHP 7.2, self::$driver may be unset during destruct. // See https://github.com/amphp/amp/issues/212. return; } self::$driver->disable($watcherId); } /** * Cancel a watcher. * * This will detatch the event loop from all resources that are associated to the watcher. After this operation the * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public static function cancel(string $watcherId) { if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { // Prior to PHP 7.2, self::$driver may be unset during destruct. // See https://github.com/amphp/amp/issues/212. return; } self::$driver->cancel($watcherId); } /** * Reference a watcher. * * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by * default. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public static function reference(string $watcherId) { self::$driver->reference($watcherId); } /** * Unreference a watcher. * * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers * are all referenced by default. * * @param string $watcherId The watcher identifier. * * @return void */ public static function unreference(string $watcherId) { if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { // Prior to PHP 7.2, self::$driver may be unset during destruct. // See https://github.com/amphp/amp/issues/212. return; } self::$driver->unreference($watcherId); } /** * Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to * wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned * by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick. * * @return int */ public static function now(): int { return self::$driver->now(); } /** * Stores information in the loop bound registry. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * @param mixed $value The value to be stored. * * @return void */ public static function setState(string $key, $value) { self::$driver->setState($key, $value); } /** * Gets information stored bound to the loop. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * * @return mixed The previously stored value or `null` if it doesn't exist. */ public static function getState(string $key) { return self::$driver->getState($key); } /** * Set a callback to be executed when an error occurs. * * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation * MUST be thrown into the `run` loop and stop the driver. * * Subsequent calls to this method will overwrite the previous handler. * * @param callable(\Throwable $error)|null $callback The callback to execute. `null` will clear the * current handler. * * @return callable(\Throwable $error)|null The previous handler, `null` if there was none. */ public static function setErrorHandler(callable $callback = null) { return self::$driver->setErrorHandler($callback); } /** * Retrieve an associative array of information about the event loop driver. * * The returned array MUST contain the following data describing the driver's currently registered watchers: * * [ * "defer" => ["enabled" => int, "disabled" => int], * "delay" => ["enabled" => int, "disabled" => int], * "repeat" => ["enabled" => int, "disabled" => int], * "on_readable" => ["enabled" => int, "disabled" => int], * "on_writable" => ["enabled" => int, "disabled" => int], * "on_signal" => ["enabled" => int, "disabled" => int], * "enabled_watchers" => ["referenced" => int, "unreferenced" => int], * "running" => bool * ]; * * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * * @return array Statistics about the loop in the described format. */ public static function getInfo(): array { return self::$driver->getInfo(); } /** * Retrieve the event loop driver that is in scope. * * @return Driver */ public static function get(): Driver { return self::$driver; } } // Default factory, don't move this to a file loaded by the composer "files" autoload mechanism, otherwise custom // implementations might have issues setting a default loop, because it's overridden by us then. // @codeCoverageIgnoreStart Loop::set((new DriverFactory)->create()); // @codeCoverageIgnoreEnd <?php namespace Amp\Internal; use Amp\Coroutine; use Amp\Loop; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; /** * Stores a set of functions to be invoked when a promise is resolved. * * @internal */ class ResolutionQueue { /** @var callable[] */ private $queue = []; /** * @param callable|null $callback Initial callback to add to queue. */ public function __construct(callable $callback = null) { if (null !== $callback) { $this->push($callback); } } /** * Unrolls instances of self to avoid blowing up the call stack on resolution. * * @param callable $callback */ public function push(callable $callback) { if ($callback instanceof self) { $this->queue = \array_merge($this->queue, $callback->queue); return; } $this->queue[] = $callback; } /** * Calls each callback in the queue, passing the provided values to the function. * * @param \Throwable|null $exception * @param mixed $value */ public function __invoke($exception, $value) { foreach ($this->queue as $callback) { try { $result = $callback($exception, $value); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use ($exception) { throw $exception; }); } } } } <?php namespace Amp\Internal; use Amp\Deferred; use Amp\Failure; use Amp\Promise; use Amp\Success; use React\Promise\PromiseInterface as ReactPromise; /** * Trait used by Iterator implementations. Do not use this trait in your code, instead compose your class from one of * the available classes implementing \Amp\Iterator. * Note that it is the responsibility of the user of this trait to ensure that listeners have a chance to listen first * before emitting values. * * @internal */ trait Producer { /** @var \Amp\Promise|null */ private $complete; /** @var mixed[] */ private $values = []; /** @var \Amp\Deferred[] */ private $backPressure = []; /** @var int */ private $position = -1; /** @var \Amp\Deferred|null */ private $waiting; /** @var null|array */ private $resolutionTrace; /** * {@inheritdoc} */ public function advance(): Promise { if ($this->waiting !== null) { throw new \Error("The prior promise returned must resolve before invoking this method again"); } if (isset($this->backPressure[$this->position])) { $future = $this->backPressure[$this->position]; unset($this->values[$this->position], $this->backPressure[$this->position]); $future->resolve(); } ++$this->position; if (\array_key_exists($this->position, $this->values)) { return new Success(true); } if ($this->complete) { return $this->complete; } $this->waiting = new Deferred; return $this->waiting->promise(); } /** * {@inheritdoc} */ public function getCurrent() { if (empty($this->values) && $this->complete) { throw new \Error("The iterator has completed"); } if (!\array_key_exists($this->position, $this->values)) { throw new \Error("Promise returned from advance() must resolve before calling this method"); } return $this->values[$this->position]; } /** * Emits a value from the iterator. The returned promise is resolved with the emitted value once all listeners * have been invoked. * * @param mixed $value * * @return \Amp\Promise * * @throws \Error If the iterator has completed. */ private function emit($value): Promise { if ($this->complete) { throw new \Error("Iterators cannot emit values after calling complete"); } if ($value instanceof ReactPromise) { $value = Promise\adapt($value); } if ($value instanceof Promise) { $deferred = new Deferred; $value->onResolve(function ($e, $v) use ($deferred) { if ($this->complete) { $deferred->fail( new \Error("The iterator was completed before the promise result could be emitted") ); return; } if ($e) { $this->fail($e); $deferred->fail($e); return; } $deferred->resolve($this->emit($v)); }); return $deferred->promise(); } $this->values[] = $value; $this->backPressure[] = $pressure = new Deferred; if ($this->waiting !== null) { $waiting = $this->waiting; $this->waiting = null; $waiting->resolve(true); } return $pressure->promise(); } /** * Completes the iterator. * * @throws \Error If the iterator has already been completed. */ private function complete() { if ($this->complete) { $message = "Iterator has already been completed"; if (isset($this->resolutionTrace)) { $trace = formatStacktrace($this->resolutionTrace); $message .= ". Previous completion trace:\n\n{$trace}\n\n"; } else { // @codeCoverageIgnoreStart $message .= ", define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions " . "for a stacktrace of the previous resolution."; // @codeCoverageIgnoreEnd } throw new \Error($message); } \assert((function () { $env = \getenv("AMP_DEBUG") ?: "0"; if (($env !== "0" && $env !== "false") || (\defined("AMP_DEBUG") && \AMP_DEBUG)) { $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); \array_shift($trace); // remove current closure $this->resolutionTrace = $trace; } return true; })()); $this->complete = new Success(false); if ($this->waiting !== null) { $waiting = $this->waiting; $this->waiting = null; $waiting->resolve($this->complete); } } private function fail(\Throwable $exception) { $this->complete = new Failure($exception); if ($this->waiting !== null) { $waiting = $this->waiting; $this->waiting = null; $waiting->resolve($this->complete); } } } <?php namespace Amp\Internal; use Amp\Promise; /** * Wraps a Promise instance that has public methods to resolve and fail the promise into an object that only allows * access to the public API methods. */ class PrivatePromise implements Promise { /** @var \Amp\Promise */ private $promise; public function __construct(Promise $promise) { $this->promise = $promise; } public function onResolve(callable $onResolved) { $this->promise->onResolve($onResolved); } } <?php namespace Amp\Internal; /** * Formats a stacktrace obtained via `debug_backtrace()`. * * @param array $trace Output of `debug_backtrace()`. * * @return string Formatted stacktrace. * * @codeCoverageIgnore * @internal */ function formatStacktrace(array $trace): string { return \implode("\n", \array_map(function ($e, $i) { $line = "#{$i} "; if (isset($e["file"])) { $line .= "{$e['file']}:{$e['line']} "; } if (isset($e["type"])) { $line .= $e["class"] . $e["type"]; } return $line . $e["function"] . "()"; }, $trace, \array_keys($trace))); } /** * Creates a `TypeError` with a standardized error message. * * @param string[] $expected Expected types. * @param mixed $given Given value. * * @return \TypeError * * @internal */ function createTypeError(array $expected, $given): \TypeError { $givenType = \is_object($given) ? \sprintf("instance of %s", \get_class($given)) : \gettype($given); if (\count($expected) === 1) { $expectedType = "Expected the following type: " . \array_pop($expected); } else { $expectedType = "Expected one of the following types: " . \implode(", ", $expected); } return new \TypeError("{$expectedType}; {$givenType} given"); } /** * Returns the current time relative to an arbitrary point in time. * * @return int Time in milliseconds. */ function getCurrentTime(): int { static $startTime; static $nextWarning; if (\PHP_INT_SIZE === 4) { // @codeCoverageIgnoreStart if ($startTime === null) { $startTime = \PHP_VERSION_ID >= 70300 ? \hrtime(false)[0] : \time(); $nextWarning = \PHP_INT_MAX - 86400 * 7; } if (\PHP_VERSION_ID >= 70300) { list($seconds, $nanoseconds) = \hrtime(false); $seconds -= $startTime; if ($seconds >= $nextWarning) { $timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000; \trigger_error( "getCurrentTime() will overflow in $timeToOverflow seconds, please restart the process before that. " . "You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.", \E_USER_WARNING ); $nextWarning += 600; // every 10 minutes } return (int) ($seconds * 1000 + $nanoseconds / 1000000); } $seconds = \microtime(true) - $startTime; if ($seconds >= $nextWarning) { $timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000; \trigger_error( "getCurrentTime() will overflow in $timeToOverflow seconds, please restart the process before that. " . "You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.", \E_USER_WARNING ); $nextWarning += 600; // every 10 minutes } return $seconds * 1000; // @codeCoverageIgnoreEnd } if (\PHP_VERSION_ID >= 70300) { list($seconds, $nanoseconds) = \hrtime(false); return (int) ($seconds * 1000 + $nanoseconds / 1000000); } return (\microtime(true) * 1000); } <?php namespace Amp\Internal; use Amp\Coroutine; use Amp\Failure; use Amp\Loop; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; /** * Trait used by Promise implementations. Do not use this trait in your code, instead compose your class from one of * the available classes implementing \Amp\Promise. * * @internal */ trait Placeholder { /** @var bool */ private $resolved = false; /** @var mixed */ private $result; /** @var callable|ResolutionQueue|null */ private $onResolved; /** @var null|array */ private $resolutionTrace; /** * @inheritdoc */ public function onResolve(callable $onResolved) { if ($this->resolved) { if ($this->result instanceof Promise) { $this->result->onResolve($onResolved); return; } try { $result = $onResolved(null, $this->result); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use ($exception) { throw $exception; }); } return; } if (null === $this->onResolved) { $this->onResolved = $onResolved; return; } if (!$this->onResolved instanceof ResolutionQueue) { $this->onResolved = new ResolutionQueue($this->onResolved); } $this->onResolved->push($onResolved); } /** * @param mixed $value * * @throws \Error Thrown if the promise has already been resolved. */ private function resolve($value = null) { if ($this->resolved) { $message = "Promise has already been resolved"; if (isset($this->resolutionTrace)) { $trace = formatStacktrace($this->resolutionTrace); $message .= ". Previous resolution trace:\n\n{$trace}\n\n"; } else { // @codeCoverageIgnoreStart $message .= ", define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions " . "for a stacktrace of the previous resolution."; // @codeCoverageIgnoreEnd } throw new \Error($message); } \assert((function () { $env = \getenv("AMP_DEBUG") ?: "0"; if (($env !== "0" && $env !== "false") || (\defined("AMP_DEBUG") && \AMP_DEBUG)) { $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); \array_shift($trace); // remove current closure $this->resolutionTrace = $trace; } return true; })()); if ($value instanceof ReactPromise) { $value = Promise\adapt($value); } $this->resolved = true; $this->result = $value; if ($this->onResolved === null) { return; } $onResolved = $this->onResolved; $this->onResolved = null; if ($this->result instanceof Promise) { $this->result->onResolve($onResolved); return; } try { $result = $onResolved(null, $this->result); $onResolved = null; // allow garbage collection of $onResolved, to catch any exceptions from destructors if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use ($exception) { throw $exception; }); } } /** * @param \Throwable $reason Failure reason. */ private function fail(\Throwable $reason) { $this->resolve(new Failure($reason)); } public function __destruct() { try { $this->result = null; } catch (\Throwable $e) { Loop::defer(static function () use ($e) { throw $e; }); } } } <?php namespace Amp\Internal; use Amp\Iterator; use Amp\Promise; /** * Wraps an Iterator instance that has public methods to emit, complete, and fail into an object that only allows * access to the public API methods. */ class PrivateIterator implements Iterator { /** @var \Amp\Iterator */ private $iterator; public function __construct(Iterator $iterator) { $this->iterator = $iterator; } public function advance(): Promise { return $this->iterator->advance(); } public function getCurrent() { return $this->iterator->getCurrent(); } } <?php namespace Amp\Loop; use Amp\Struct; class Watcher { use Struct; const IO = 0b00000011; const READABLE = 0b00000001; const WRITABLE = 0b00000010; const DEFER = 0b00000100; const TIMER = 0b00011000; const DELAY = 0b00001000; const REPEAT = 0b00010000; const SIGNAL = 0b00100000; /** @var int */ public $type; /** @var bool */ public $enabled = true; /** @var bool */ public $referenced = true; /** @var string */ public $id; /** @var callable */ public $callback; /** * Data provided to the watcher callback. * * @var mixed */ public $data; /** * Watcher-dependent value storage. Stream for IO watchers, signal number for signal watchers, interval for timers. * * @var mixed */ public $value; } <?php namespace Amp\Loop; /** * MUST be thrown if any operation (except disable() and cancel()) is attempted with an invalid watcher identifier. * * An invalid watcher identifier is any identifier that is not yet emitted by the driver or cancelled by the user. */ class InvalidWatcherError extends \Error { /** @var string */ private $watcherId; /** * @param string $watcherId The watcher identifier. * @param string|null $message The exception message. */ public function __construct(string $watcherId, string $message) { $this->watcherId = $watcherId; parent::__construct($message); } /** * @return string The watcher identifier. */ public function getWatcherId() { return $this->watcherId; } } <?php namespace Amp\Loop; use Amp\Coroutine; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; use function Amp\Internal\getCurrentTime; use function Amp\Promise\rethrow; class EvDriver extends Driver { /** @var \EvSignal[]|null */ private static $activeSignals; /** @var \EvLoop */ private $handle; /** @var \EvWatcher[] */ private $events = []; /** @var callable */ private $ioCallback; /** @var callable */ private $timerCallback; /** @var callable */ private $signalCallback; /** @var \EvSignal[] */ private $signals = []; /** @var int Internal timestamp for now. */ private $now; /** @var bool */ private $nowUpdateNeeded = false; /** @var int Loop time offset */ private $nowOffset; public function __construct() { $this->handle = new \EvLoop; $this->nowOffset = getCurrentTime(); $this->now = \random_int(0, $this->nowOffset); $this->nowOffset -= $this->now; if (self::$activeSignals === null) { self::$activeSignals = &$this->signals; } $this->ioCallback = function (\EvIO $event) { /** @var \Amp\Loop\Watcher $watcher */ $watcher = $event->data; try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; $this->timerCallback = function (\EvTimer $event) { /** @var \Amp\Loop\Watcher $watcher */ $watcher = $event->data; if ($watcher->type & Watcher::DELAY) { $this->cancel($watcher->id); } elseif ($watcher->value === 0) { // Disable and re-enable so it's not executed repeatedly in the same tick // See https://github.com/amphp/amp/issues/131 $this->disable($watcher->id); $this->enable($watcher->id); } try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; $this->signalCallback = function (\EvSignal $event) { /** @var \Amp\Loop\Watcher $watcher */ $watcher = $event->data; try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; } /** * {@inheritdoc} */ public function cancel(string $watcherId) { parent::cancel($watcherId); unset($this->events[$watcherId]); } public static function isSupported(): bool { return \extension_loaded("ev"); } public function __destruct() { foreach ($this->events as $event) { if ($event !== null) { // Events may have been nulled in extension depending on destruct order. $event->stop(); } } // We need to clear all references to events manually, see // https://bitbucket.org/osmanov/pecl-ev/issues/31/segfault-in-ev_timer_stop $this->events = []; } /** * {@inheritdoc} */ public function run() { $active = self::$activeSignals; foreach ($active as $event) { $event->stop(); } self::$activeSignals = &$this->signals; foreach ($this->signals as $event) { $event->start(); } try { parent::run(); } finally { foreach ($this->signals as $event) { $event->stop(); } self::$activeSignals = &$active; foreach ($active as $event) { $event->start(); } } } /** * {@inheritdoc} */ public function stop() { $this->handle->stop(); parent::stop(); } /** * {@inheritdoc} */ public function now(): int { if ($this->nowUpdateNeeded) { $this->now = getCurrentTime() - $this->nowOffset; $this->nowUpdateNeeded = false; } return $this->now; } /** * {@inheritdoc} */ public function getHandle(): \EvLoop { return $this->handle; } /** * {@inheritdoc} */ protected function dispatch(bool $blocking) { $this->nowUpdateNeeded = true; $this->handle->run($blocking ? \Ev::RUN_ONCE : \Ev::RUN_ONCE | \Ev::RUN_NOWAIT); } /** * {@inheritdoc} */ protected function activate(array $watchers) { foreach ($watchers as $watcher) { if (!isset($this->events[$id = $watcher->id])) { switch ($watcher->type) { case Watcher::READABLE: $this->events[$id] = $this->handle->io($watcher->value, \Ev::READ, $this->ioCallback, $watcher); break; case Watcher::WRITABLE: $this->events[$id] = $this->handle->io($watcher->value, \Ev::WRITE, $this->ioCallback, $watcher); break; case Watcher::DELAY: case Watcher::REPEAT: $interval = $watcher->value / self::MILLISEC_PER_SEC; $this->events[$id] = $this->handle->timer( $interval, $watcher->type & Watcher::REPEAT ? $interval : 0, $this->timerCallback, $watcher ); break; case Watcher::SIGNAL: $this->events[$id] = $this->handle->signal($watcher->value, $this->signalCallback, $watcher); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } } else { $this->events[$id]->start(); } if ($watcher->type === Watcher::SIGNAL) { $this->signals[$id] = $this->events[$id]; } } } /** * {@inheritdoc} */ protected function deactivate(Watcher $watcher) { if (isset($this->events[$id = $watcher->id])) { $this->events[$id]->stop(); if ($watcher->type === Watcher::SIGNAL) { unset($this->signals[$id]); } } } } <?php namespace Amp\Loop\Internal; use Amp\Loop\Watcher; /** * Uses a binary tree stored in an array to implement a heap. */ class TimerQueue { /** @var TimerQueueEntry[] */ private $data = []; /** * Inserts the watcher into the queue. Time complexity: O(log(n)). * * @param Watcher $watcher * @param int $expiration */ public function insert(Watcher $watcher, int $expiration) { $entry = new TimerQueueEntry; $entry->watcher = $watcher; $entry->expiration = $expiration; $node = \count($this->data); $this->data[$node] = $entry; while ($node !== 0 && $entry->expiration < $this->data[$parent = ($node - 1) >> 1]->expiration) { $this->data[$node] = $this->data[$parent]; $this->data[$parent] = $entry; $node = $parent; } } /** * Removes the given watcher from the queue. Time complexity: O(n). * * @param Watcher $watcher */ public function remove(Watcher $watcher) { foreach ($this->data as $node => $entry) { if ($entry->watcher === $watcher) { $this->removeAndRebuild($node); return; } } } /** * Deletes and returns the Watcher on top of the heap. Time complexity: O(log(n)). * * @return [Watcher, int] Tuple of the watcher and the expiration time. */ public function extract(): array { if ($this->isEmpty()) { throw new \Error('No data left in the heap.'); } $data = $this->removeAndRebuild(0); return [$data->watcher, $data->expiration]; } /** * @param int $node Remove the given node and then rebuild the data array from that node downward. * * @return TimerQueueEntry Removed entry. */ private function removeAndRebuild(int $node): TimerQueueEntry { $length = \count($this->data) - 1; $data = $this->data[$node]; $this->data[$node] = $this->data[$length]; unset($this->data[$length]); while (($child = ($node << 1) + 1) < $length) { if ($this->data[$child]->expiration < $this->data[$node]->expiration && ($child + 1 >= $length || $this->data[$child]->expiration < $this->data[$child + 1]->expiration) ) { // Left child is less than parent and right child. $swap = $child; } elseif ($child + 1 < $length && $this->data[$child + 1]->expiration < $this->data[$node]->expiration) { // Right child is less than parent and left child. $swap = $child + 1; } else { // Left and right child are greater than parent. break; } $temp = $this->data[$node]; $this->data[$node] = $this->data[$swap]; $this->data[$swap] = $temp; $node = $swap; } return $data; } /** * Returns the value at the top of the heap (without removing it). Time complexity: O(1). * * @return [Watcher, int] Tuple of the watcher and the expiration time. */ public function peek(): array { if ($this->isEmpty()) { throw new \Error('No data in the heap.'); } return [$this->data[0]->watcher, $this->data[0]->expiration]; } /** * Determines if the heap is empty. * @return bool */ public function isEmpty(): bool { return empty($this->data); } } <?php namespace Amp\Loop\Internal; use Amp\Loop\Watcher; use Amp\Struct; class TimerQueueEntry { use Struct; /** @var Watcher */ public $watcher; /** @var int */ public $expiration; } <?php namespace Amp\Loop; use Amp\CallableMaker; use Amp\Coroutine; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; use function Amp\Internal\getCurrentTime; use function Amp\Promise\rethrow; class NativeDriver extends Driver { use CallableMaker; /** @var resource[] */ private $readStreams = []; /** @var \Amp\Loop\Watcher[][] */ private $readWatchers = []; /** @var resource[] */ private $writeStreams = []; /** @var \Amp\Loop\Watcher[][] */ private $writeWatchers = []; /** @var Internal\TimerQueue */ private $timerQueue; /** @var \Amp\Loop\Watcher[][] */ private $signalWatchers = []; /** @var bool */ private $nowUpdateNeeded = false; /** @var int Internal timestamp for now. */ private $now; /** @var int Loop time offset */ private $nowOffset; /** @var bool */ private $signalHandling; public function __construct() { $this->timerQueue = new Internal\TimerQueue; $this->signalHandling = \extension_loaded("pcntl"); $this->nowOffset = getCurrentTime(); $this->now = \random_int(0, $this->nowOffset); $this->nowOffset -= $this->now; } /** * {@inheritdoc} * * @throws \Amp\Loop\UnsupportedFeatureException If the pcntl extension is not available. */ public function onSignal(int $signo, callable $callback, $data = null): string { if (!$this->signalHandling) { throw new UnsupportedFeatureException("Signal handling requires the pcntl extension"); } return parent::onSignal($signo, $callback, $data); } /** * {@inheritdoc} */ public function now(): int { if ($this->nowUpdateNeeded) { $this->now = getCurrentTime() - $this->nowOffset; $this->nowUpdateNeeded = false; } return $this->now; } /** * {@inheritdoc} */ public function getHandle() { return null; } protected function dispatch(bool $blocking) { $this->nowUpdateNeeded = true; $this->selectStreams( $this->readStreams, $this->writeStreams, $blocking ? $this->getTimeout() : 0 ); $scheduleQueue = []; try { while (!$this->timerQueue->isEmpty()) { list($watcher, $expiration) = $this->timerQueue->peek(); if ($expiration > $this->now()) { // Timer at top of queue has not expired. break; } $this->timerQueue->extract(); if ($watcher->type & Watcher::REPEAT) { $expiration = $this->now() + $watcher->value; $scheduleQueue[] = [$watcher, $expiration]; } else { $this->cancel($watcher->id); } try { // Execute the timer. $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } finally { foreach ($scheduleQueue as list($watcher, $expiration)) { if ($watcher->enabled) { $this->timerQueue->insert($watcher, $expiration); } } } if ($this->signalHandling) { \pcntl_signal_dispatch(); } } /** * @param resource[] $read * @param resource[] $write * @param int $timeout */ private function selectStreams(array $read, array $write, int $timeout) { $timeout /= self::MILLISEC_PER_SEC; if (!empty($read) || !empty($write)) { // Use stream_select() if there are any streams in the loop. if ($timeout >= 0) { $seconds = (int) $timeout; $microseconds = (int) (($timeout - $seconds) * self::MICROSEC_PER_SEC); } else { $seconds = null; $microseconds = null; } $except = null; // Error reporting suppressed since stream_select() emits an E_WARNING if it is interrupted by a signal. if (!($result = @\stream_select($read, $write, $except, $seconds, $microseconds))) { if ($result === 0) { return; } $error = \error_get_last(); if (\strpos($error["message"], "unable to select") !== 0) { return; } $this->error(new \Exception($error["message"])); } foreach ($read as $stream) { $streamId = (int) $stream; if (!isset($this->readWatchers[$streamId])) { continue; // All read watchers disabled. } foreach ($this->readWatchers[$streamId] as $watcher) { if (!isset($this->readWatchers[$streamId][$watcher->id])) { continue; // Watcher disabled by another IO watcher. } try { $result = ($watcher->callback)($watcher->id, $stream, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } foreach ($write as $stream) { $streamId = (int) $stream; if (!isset($this->writeWatchers[$streamId])) { continue; // All write watchers disabled. } foreach ($this->writeWatchers[$streamId] as $watcher) { if (!isset($this->writeWatchers[$streamId][$watcher->id])) { continue; // Watcher disabled by another IO watcher. } try { $result = ($watcher->callback)($watcher->id, $stream, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } return; } if ($timeout > 0) { // Otherwise sleep with usleep() if $timeout > 0. \usleep($timeout * self::MICROSEC_PER_SEC); } } /** * @return int Milliseconds until next timer expires or -1 if there are no pending times. */ private function getTimeout(): int { if (!$this->timerQueue->isEmpty()) { list($watcher, $expiration) = $this->timerQueue->peek(); $expiration -= getCurrentTime() - $this->nowOffset; if ($expiration < 0) { return 0; } return $expiration; } return -1; } /** * {@inheritdoc} */ protected function activate(array $watchers) { foreach ($watchers as $watcher) { switch ($watcher->type) { case Watcher::READABLE: $streamId = (int) $watcher->value; $this->readWatchers[$streamId][$watcher->id] = $watcher; $this->readStreams[$streamId] = $watcher->value; break; case Watcher::WRITABLE: $streamId = (int) $watcher->value; $this->writeWatchers[$streamId][$watcher->id] = $watcher; $this->writeStreams[$streamId] = $watcher->value; break; case Watcher::DELAY: case Watcher::REPEAT: $expiration = $this->now() + $watcher->value; $this->timerQueue->insert($watcher, $expiration); break; case Watcher::SIGNAL: if (!isset($this->signalWatchers[$watcher->value])) { if (!@\pcntl_signal($watcher->value, $this->callableFromInstanceMethod('handleSignal'))) { $message = "Failed to register signal handler"; if ($error = \error_get_last()) { $message .= \sprintf("; Errno: %d; %s", $error["type"], $error["message"]); } throw new \Error($message); } } $this->signalWatchers[$watcher->value][$watcher->id] = $watcher; break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } } } /** * {@inheritdoc} */ protected function deactivate(Watcher $watcher) { switch ($watcher->type) { case Watcher::READABLE: $streamId = (int) $watcher->value; unset($this->readWatchers[$streamId][$watcher->id]); if (empty($this->readWatchers[$streamId])) { unset($this->readWatchers[$streamId], $this->readStreams[$streamId]); } break; case Watcher::WRITABLE: $streamId = (int) $watcher->value; unset($this->writeWatchers[$streamId][$watcher->id]); if (empty($this->writeWatchers[$streamId])) { unset($this->writeWatchers[$streamId], $this->writeStreams[$streamId]); } break; case Watcher::DELAY: case Watcher::REPEAT: $this->timerQueue->remove($watcher); break; case Watcher::SIGNAL: if (isset($this->signalWatchers[$watcher->value])) { unset($this->signalWatchers[$watcher->value][$watcher->id]); if (empty($this->signalWatchers[$watcher->value])) { unset($this->signalWatchers[$watcher->value]); @\pcntl_signal($watcher->value, \SIG_DFL); } } break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } } /** * @param int $signo */ private function handleSignal(int $signo) { foreach ($this->signalWatchers[$signo] as $watcher) { if (!isset($this->signalWatchers[$signo][$watcher->id])) { continue; } try { $result = ($watcher->callback)($watcher->id, $signo, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } } } <?php namespace Amp\Loop; use Amp\Coroutine; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; use function Amp\Promise\rethrow; class UvDriver extends Driver { /** @var resource A uv_loop resource created with uv_loop_new() */ private $handle; /** @var resource[] */ private $events = []; /** @var \Amp\Loop\Watcher[][] */ private $watchers = []; /** @var resource[] */ private $streams = []; /** @var callable */ private $ioCallback; /** @var callable */ private $timerCallback; /** @var callable */ private $signalCallback; public function __construct() { $this->handle = \uv_loop_new(); $this->ioCallback = function ($event, $status, $events, $resource) { $watchers = $this->watchers[(int) $event]; switch ($status) { case 0: // OK break; default: // Invoke the callback on errors, as this matches behavior with other loop back-ends. // Re-enable watcher as libuv disables the watcher on non-zero status. $flags = 0; foreach ($this->watchers[(int) $event] as $watcher) { $flags |= $watcher->enabled ? $watcher->type : 0; } \uv_poll_start($event, $flags, $this->ioCallback); break; } foreach ($watchers as $watcher) { // $events is OR'ed with 4 to trigger watcher if no events are indicated (0) or on UV_DISCONNECT (4). // http://docs.libuv.org/en/v1.x/poll.html if (!($watcher->enabled && ($watcher->type & $events || ($events | 4) === 4))) { continue; } try { $result = ($watcher->callback)($watcher->id, $resource, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } }; $this->timerCallback = function ($event) { $watcher = $this->watchers[(int) $event]; if ($watcher->type & Watcher::DELAY) { unset($this->events[$watcher->id], $this->watchers[(int) $event]); // Avoid call to uv_is_active(). $this->cancel($watcher->id); // Remove reference to watcher in parent. } elseif ($watcher->value === 0) { // Disable and re-enable so it's not executed repeatedly in the same tick // See https://github.com/amphp/amp/issues/131 $this->disable($watcher->id); $this->enable($watcher->id); } try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; $this->signalCallback = function ($event, $signo) { $watcher = $this->watchers[(int) $event]; try { $result = ($watcher->callback)($watcher->id, $signo, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; } /** * {@inheritdoc} */ public function cancel(string $watcherId) { parent::cancel($watcherId); if (!isset($this->events[$watcherId])) { return; } $event = $this->events[$watcherId]; $eventId = (int) $event; if ($this->watchers[$eventId] instanceof Watcher) { // All except IO watchers. unset($this->watchers[$eventId]); } else { $watcher = $this->watchers[$eventId][$watcherId]; unset($this->watchers[$eventId][$watcherId]); if (empty($this->watchers[$eventId])) { unset($this->watchers[$eventId], $this->streams[(int) $watcher->value]); } } unset($this->events[$watcherId]); } public static function isSupported(): bool { return \extension_loaded("uv"); } /** * {@inheritdoc} */ public function now(): int { return \uv_now($this->handle); } /** * {@inheritdoc} */ public function getHandle() { return $this->handle; } /** * {@inheritdoc} */ protected function dispatch(bool $blocking) { \uv_run($this->handle, $blocking ? \UV::RUN_ONCE : \UV::RUN_NOWAIT); } /** * {@inheritdoc} */ protected function activate(array $watchers) { foreach ($watchers as $watcher) { $id = $watcher->id; switch ($watcher->type) { case Watcher::READABLE: case Watcher::WRITABLE: $streamId = (int) $watcher->value; if (isset($this->streams[$streamId])) { $event = $this->streams[$streamId]; } elseif (isset($this->events[$id])) { $event = $this->streams[$streamId] = $this->events[$id]; } else { $event = $this->streams[$streamId] = \uv_poll_init_socket($this->handle, $watcher->value); } $eventId = (int) $event; $this->events[$id] = $event; $this->watchers[$eventId][$id] = $watcher; $flags = 0; foreach ($this->watchers[$eventId] as $watcher) { $flags |= $watcher->enabled ? $watcher->type : 0; } \uv_poll_start($event, $flags, $this->ioCallback); break; case Watcher::DELAY: case Watcher::REPEAT: if (isset($this->events[$id])) { $event = $this->events[$id]; } else { $event = $this->events[$id] = \uv_timer_init($this->handle); } $this->watchers[(int) $event] = $watcher; \uv_timer_start( $event, $watcher->value, $watcher->type & Watcher::REPEAT ? $watcher->value : 0, $this->timerCallback ); break; case Watcher::SIGNAL: if (isset($this->events[$id])) { $event = $this->events[$id]; } else { $event = $this->events[$id] = \uv_signal_init($this->handle); } $this->watchers[(int) $event] = $watcher; \uv_signal_start($event, $this->signalCallback, $watcher->value); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } } } /** * {@inheritdoc} */ protected function deactivate(Watcher $watcher) { $id = $watcher->id; if (!isset($this->events[$id])) { return; } $event = $this->events[$id]; if (!\uv_is_active($event)) { return; } switch ($watcher->type) { case Watcher::READABLE: case Watcher::WRITABLE: $flags = 0; foreach ($this->watchers[(int) $event] as $watcher) { $flags |= $watcher->enabled ? $watcher->type : 0; } if ($flags) { \uv_poll_start($event, $flags, $this->ioCallback); } else { \uv_poll_stop($event); } break; case Watcher::DELAY: case Watcher::REPEAT: \uv_timer_stop($event); break; case Watcher::SIGNAL: \uv_signal_stop($event); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } } } <?php namespace Amp\Loop; // @codeCoverageIgnoreStart class DriverFactory { /** * Creates a new loop instance and chooses the best available driver. * * @return Driver * * @throws \Error If an invalid class has been specified via AMP_LOOP_DRIVER */ public function create(): Driver { if ($driver = $this->createDriverFromEnv()) { return $driver; } if (UvDriver::isSupported()) { return new UvDriver; } if (EvDriver::isSupported()) { return new EvDriver; } if (EventDriver::isSupported()) { return new EventDriver; } return new NativeDriver; } private function createDriverFromEnv() { $driver = \getenv("AMP_LOOP_DRIVER"); if (!$driver) { return null; } if (!\class_exists($driver)) { throw new \Error(\sprintf( "Driver '%s' does not exist.", $driver )); } if (!\is_subclass_of($driver, Driver::class)) { throw new \Error(\sprintf( "Driver '%s' is not a subclass of '%s'.", $driver, Driver::class )); } return new $driver; } } // @codeCoverageIgnoreEnd <?php namespace Amp\Loop; /** * MUST be thrown if a feature is not supported by the system. * * This might happen if ext-pcntl is missing and the loop driver doesn't support another way to dispatch signals. */ class UnsupportedFeatureException extends \Exception { } <?php namespace Amp\Loop; use Amp\Coroutine; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; use function Amp\Promise\rethrow; /** * Event loop driver which implements all basic operations to allow interoperability. * * Watchers (enabled or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks can * be called) right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * All registered callbacks MUST NOT be called from a file with strict types enabled (`declare(strict_types=1)`). */ abstract class Driver { // Don't use 1e3 / 1e6, they result in a float instead of int const MILLISEC_PER_SEC = 1000; const MICROSEC_PER_SEC = 1000000; /** @var string */ private $nextId = "a"; /** @var \Amp\Loop\Watcher[] */ private $watchers = []; /** @var \Amp\Loop\Watcher[] */ private $enableQueue = []; /** @var \Amp\Loop\Watcher[] */ private $deferQueue = []; /** @var \Amp\Loop\Watcher[] */ private $nextTickQueue = []; /** @var callable|null */ private $errorHandler; /** @var bool */ private $running = false; /** @var array */ private $registry = []; /** * Run the event loop. * * One iteration of the loop is called one "tick". A tick covers the following steps: * * 1. Activate watchers created / enabled in the last tick / before `run()`. * 2. Execute all enabled defer watchers. * 3. Execute all due timer, pending signal and actionable stream callbacks, each only once per tick. * * The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an * error handler or exceptions that would be passed to an error handler but none exists to handle them. * * @return void */ public function run() { $this->running = true; try { while ($this->running) { if ($this->isEmpty()) { return; } $this->tick(); } } finally { $this->stop(); } } /** * @return bool True if no enabled and referenced watchers remain in the loop. */ private function isEmpty() { foreach ($this->watchers as $watcher) { if ($watcher->enabled && $watcher->referenced) { return false; } } return true; } /** * Executes a single tick of the event loop. */ private function tick() { if (empty($this->deferQueue)) { $this->deferQueue = $this->nextTickQueue; } else { $this->deferQueue = \array_merge($this->deferQueue, $this->nextTickQueue); } $this->nextTickQueue = []; $this->activate($this->enableQueue); $this->enableQueue = []; foreach ($this->deferQueue as $watcher) { if (!isset($this->deferQueue[$watcher->id])) { continue; // Watcher disabled by another defer watcher. } unset($this->watchers[$watcher->id], $this->deferQueue[$watcher->id]); try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { continue; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } } $this->dispatch(empty($this->nextTickQueue) && empty($this->enableQueue) && $this->running && !$this->isEmpty()); } /** * Activates (enables) all the given watchers. * * @param \Amp\Loop\Watcher[] $watchers */ abstract protected function activate(array $watchers); /** * Dispatches any pending read/write, timer, and signal events. * * @param bool $blocking */ abstract protected function dispatch(bool $blocking); /** * Stop the event loop. * * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls * to stop MUST be ignored and MUST NOT raise an exception. * * @return void */ public function stop() { $this->running = false; } /** * Defer the execution of a callback. * * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be * preserved when executing the callbacks. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param callable (string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function defer(callable $callback, $data = null): string { $watcher = new Watcher; $watcher->type = Watcher::DEFER; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->nextTickQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Delay the execution of a callback. * * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which * timers expire first, but timers with the same expiration time MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $delay The amount of time, in milliseconds, to delay the execution for. * @param callable (string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function delay(int $delay, callable $callback, $data = null): string { if ($delay < 0) { throw new \Error("Delay must be greater than or equal to zero"); } $watcher = new Watcher; $watcher->type = Watcher::DELAY; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $delay; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Repeatedly execute a callback. * * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable (string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function repeat(int $interval, callable $callback, $data = null): string { if ($interval < 0) { throw new \Error("Interval must be greater than or equal to zero"); } $watcher = new Watcher; $watcher->type = Watcher::REPEAT; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $interval; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function onReadable($stream, callable $callback, $data = null): string { $watcher = new Watcher; $watcher->type = Watcher::READABLE; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $stream; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * * Multiple watchers on the same stream MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param resource $stream The stream to monitor. * @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public function onWritable($stream, callable $callback, $data = null): string { $watcher = new Watcher; $watcher->type = Watcher::WRITABLE; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $stream; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Execute a callback when a signal is received. * * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * * Multiple watchers on the same signal MAY be executed in any order. * * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param int $signo The signal number to monitor. * @param callable (string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. * * @throws UnsupportedFeatureException If signal handling is not supported. */ public function onSignal(int $signo, callable $callback, $data = null): string { $watcher = new Watcher; $watcher->type = Watcher::SIGNAL; $watcher->id = $this->nextId++; $watcher->callback = $callback; $watcher->value = $signo; $watcher->data = $data; $this->watchers[$watcher->id] = $watcher; $this->enableQueue[$watcher->id] = $watcher; return $watcher->id; } /** * Enable a watcher to be active starting in the next tick. * * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public function enable(string $watcherId) { if (!isset($this->watchers[$watcherId])) { throw new InvalidWatcherError($watcherId, "Cannot enable an invalid watcher identifier: '{$watcherId}'"); } $watcher = $this->watchers[$watcherId]; if ($watcher->enabled) { return; // Watcher already enabled. } $watcher->enabled = true; switch ($watcher->type) { case Watcher::DEFER: $this->nextTickQueue[$watcher->id] = $watcher; break; default: $this->enableQueue[$watcher->id] = $watcher; break; } } /** * Cancel a watcher. * * This will detatch the event loop from all resources that are associated to the watcher. After this operation the * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public function cancel(string $watcherId) { $this->disable($watcherId); unset($this->watchers[$watcherId]); } /** * Disable a watcher immediately. * * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer * watcher isn't executed in this tick. * * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an * invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void */ public function disable(string $watcherId) { if (!isset($this->watchers[$watcherId])) { return; } $watcher = $this->watchers[$watcherId]; if (!$watcher->enabled) { return; // Watcher already disabled. } $watcher->enabled = false; $id = $watcher->id; switch ($watcher->type) { case Watcher::DEFER: if (isset($this->nextTickQueue[$id])) { // Watcher was only queued to be enabled. unset($this->nextTickQueue[$id]); } else { unset($this->deferQueue[$id]); } break; default: if (isset($this->enableQueue[$id])) { // Watcher was only queued to be enabled. unset($this->enableQueue[$id]); } else { $this->deactivate($watcher); } break; } } /** * Deactivates (disables) the given watcher. * * @param \Amp\Loop\Watcher $watcher */ abstract protected function deactivate(Watcher $watcher); /** * Reference a watcher. * * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by * default. * * @param string $watcherId The watcher identifier. * * @return void * * @throws InvalidWatcherError If the watcher identifier is invalid. */ public function reference(string $watcherId) { if (!isset($this->watchers[$watcherId])) { throw new InvalidWatcherError($watcherId, "Cannot reference an invalid watcher identifier: '{$watcherId}'"); } $this->watchers[$watcherId]->referenced = true; } /** * Unreference a watcher. * * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers * are all referenced by default. * * @param string $watcherId The watcher identifier. * * @return void */ public function unreference(string $watcherId) { if (!isset($this->watchers[$watcherId])) { return; } $this->watchers[$watcherId]->referenced = false; } /** * Stores information in the loop bound registry. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * @param mixed $value The value to be stored. * * @return void */ final public function setState(string $key, $value) { if ($value === null) { unset($this->registry[$key]); } else { $this->registry[$key] = $value; } } /** * Gets information stored bound to the loop. * * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. * * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated * interface for that purpose instead of sharing the storage key. * * @param string $key The namespaced storage key. * * @return mixed The previously stored value or `null` if it doesn't exist. */ final public function getState(string $key) { return isset($this->registry[$key]) ? $this->registry[$key] : null; } /** * Set a callback to be executed when an error occurs. * * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation * MUST be thrown into the `run` loop and stop the driver. * * Subsequent calls to this method will overwrite the previous handler. * * @param callable (\Throwable|\Exception $error)|null $callback The callback to execute. `null` will clear the * current handler. * * @return callable(\Throwable|\Exception $error)|null The previous handler, `null` if there was none. */ public function setErrorHandler(callable $callback = null) { $previous = $this->errorHandler; $this->errorHandler = $callback; return $previous; } /** * Invokes the error handler with the given exception. * * @param \Throwable $exception The exception thrown from a watcher callback. * * @throws \Throwable If no error handler has been set. */ protected function error(\Throwable $exception) { if ($this->errorHandler === null) { throw $exception; } ($this->errorHandler)($exception); } /** * Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to * wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned * by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick. * * Extending classes should override this function to return a value cached once per loop tick. * * @return int */ public function now(): int { return \microtime(true) * self::MILLISEC_PER_SEC; } /** * Get the underlying loop handle. * * Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a native driver. * * Note: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop * instance. * * @return null|object|resource The loop handle the event loop operates on. `null` if there is none. */ abstract public function getHandle(); /** * Returns the same array of data as getInfo(). * * @return array */ public function __debugInfo() { // @codeCoverageIgnoreStart return $this->getInfo(); // @codeCoverageIgnoreEnd } /** * Retrieve an associative array of information about the event loop driver. * * The returned array MUST contain the following data describing the driver's currently registered watchers: * * [ * "defer" => ["enabled" => int, "disabled" => int], * "delay" => ["enabled" => int, "disabled" => int], * "repeat" => ["enabled" => int, "disabled" => int], * "on_readable" => ["enabled" => int, "disabled" => int], * "on_writable" => ["enabled" => int, "disabled" => int], * "on_signal" => ["enabled" => int, "disabled" => int], * "enabled_watchers" => ["referenced" => int, "unreferenced" => int], * "running" => bool * ]; * * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * * @return array Statistics about the loop in the described format. */ public function getInfo(): array { $watchers = [ "referenced" => 0, "unreferenced" => 0, ]; $defer = $delay = $repeat = $onReadable = $onWritable = $onSignal = [ "enabled" => 0, "disabled" => 0, ]; foreach ($this->watchers as $watcher) { switch ($watcher->type) { case Watcher::READABLE: $array = &$onReadable; break; case Watcher::WRITABLE: $array = &$onWritable; break; case Watcher::SIGNAL: $array = &$onSignal; break; case Watcher::DEFER: $array = &$defer; break; case Watcher::DELAY: $array = &$delay; break; case Watcher::REPEAT: $array = &$repeat; break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } if ($watcher->enabled) { ++$array["enabled"]; if ($watcher->referenced) { ++$watchers["referenced"]; } else { ++$watchers["unreferenced"]; } } else { ++$array["disabled"]; } } return [ "enabled_watchers" => $watchers, "defer" => $defer, "delay" => $delay, "repeat" => $repeat, "on_readable" => $onReadable, "on_writable" => $onWritable, "on_signal" => $onSignal, "running" => (bool) $this->running, ]; } } <?php namespace Amp\Loop; use Amp\Coroutine; use Amp\Promise; use React\Promise\PromiseInterface as ReactPromise; use function Amp\Internal\getCurrentTime; use function Amp\Promise\rethrow; class EventDriver extends Driver { /** @var \Event[]|null */ private static $activeSignals; /** @var \EventBase */ private $handle; /** @var \Event[] */ private $events = []; /** @var callable */ private $ioCallback; /** @var callable */ private $timerCallback; /** @var callable */ private $signalCallback; /** @var \Event[] */ private $signals = []; /** @var bool */ private $nowUpdateNeeded = false; /** @var int Internal timestamp for now. */ private $now; /** @var int Loop time offset */ private $nowOffset; public function __construct() { $this->handle = new \EventBase; $this->nowOffset = getCurrentTime(); $this->now = \random_int(0, $this->nowOffset); $this->nowOffset -= $this->now; if (self::$activeSignals === null) { self::$activeSignals = &$this->signals; } $this->ioCallback = function ($resource, $what, Watcher $watcher) { try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; $this->timerCallback = function ($resource, $what, Watcher $watcher) { if ($watcher->type & Watcher::DELAY) { $this->cancel($watcher->id); } else { $this->events[$watcher->id]->add($watcher->value / self::MILLISEC_PER_SEC); } try { $result = ($watcher->callback)($watcher->id, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; $this->signalCallback = function ($signum, $what, Watcher $watcher) { try { $result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { $this->error($exception); } }; } /** * {@inheritdoc} */ public function cancel(string $watcherId) { parent::cancel($watcherId); if (isset($this->events[$watcherId])) { $this->events[$watcherId]->free(); unset($this->events[$watcherId]); } } public static function isSupported(): bool { return \extension_loaded("event"); } /** * @codeCoverageIgnore */ public function __destruct() { foreach ($this->events as $event) { if ($event !== null) { // Events may have been nulled in extension depending on destruct order. $event->free(); } } // Unset here, otherwise $event->del() fails with a warning, because __destruct order isn't defined. // See https://github.com/amphp/amp/issues/159. $this->events = []; // Manually free the loop handle to fully release loop resources. // See https://github.com/amphp/amp/issues/177. if ($this->handle !== null) { $this->handle->free(); $this->handle = null; } } /** * {@inheritdoc} */ public function run() { $active = self::$activeSignals; foreach ($active as $event) { $event->del(); } self::$activeSignals = &$this->signals; foreach ($this->signals as $event) { $event->add(); } try { parent::run(); } finally { foreach ($this->signals as $event) { $event->del(); } self::$activeSignals = &$active; foreach ($active as $event) { $event->add(); } } } /** * {@inheritdoc} */ public function stop() { $this->handle->stop(); parent::stop(); } /** * {@inheritdoc} */ public function now(): int { if ($this->nowUpdateNeeded) { $this->now = getCurrentTime() - $this->nowOffset; $this->nowUpdateNeeded = false; } return $this->now; } /** * {@inheritdoc} */ public function getHandle(): \EventBase { return $this->handle; } /** * {@inheritdoc} */ protected function dispatch(bool $blocking) { $this->nowUpdateNeeded = true; $this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK); } /** * {@inheritdoc} */ protected function activate(array $watchers) { $now = getCurrentTime() - $this->nowOffset; foreach ($watchers as $watcher) { if (!isset($this->events[$id = $watcher->id])) { switch ($watcher->type) { case Watcher::READABLE: $this->events[$id] = new \Event( $this->handle, $watcher->value, \Event::READ | \Event::PERSIST, $this->ioCallback, $watcher ); break; case Watcher::WRITABLE: $this->events[$id] = new \Event( $this->handle, $watcher->value, \Event::WRITE | \Event::PERSIST, $this->ioCallback, $watcher ); break; case Watcher::DELAY: case Watcher::REPEAT: $this->events[$id] = new \Event( $this->handle, -1, \Event::TIMEOUT, $this->timerCallback, $watcher ); break; case Watcher::SIGNAL: $this->events[$id] = new \Event( $this->handle, $watcher->value, \Event::SIGNAL | \Event::PERSIST, $this->signalCallback, $watcher ); break; default: // @codeCoverageIgnoreStart throw new \Error("Unknown watcher type"); // @codeCoverageIgnoreEnd } } switch ($watcher->type) { case Watcher::DELAY: case Watcher::REPEAT: $interval = $watcher->value - ($now - $this->now()); $this->events[$id]->add($interval > 0 ? $interval / self::MILLISEC_PER_SEC : 0); break; case Watcher::SIGNAL: $this->signals[$id] = $this->events[$id]; // no break default: $this->events[$id]->add(); break; } } } /** * {@inheritdoc} */ protected function deactivate(Watcher $watcher) { if (isset($this->events[$id = $watcher->id])) { $this->events[$id]->del(); if ($watcher->type === Watcher::SIGNAL) { unset($this->signals[$id]); } } } } <?php namespace Amp; /** * Cancellation tokens are simple objects that allow registering handlers to subscribe to cancellation requests. */ interface CancellationToken { /** * Subscribes a new handler to be invoked on a cancellation request. * * This handler might be invoked immediately in case the token has already been cancelled. Returned generators will * automatically be run as coroutines. Any unhandled exceptions will be throw into the event loop. * * @param callable $callback Callback to be invoked on a cancellation request. Will receive a `CancelledException` * as first argument that may be used to fail the operation's promise. * * @return string Identifier that can be used to cancel the subscription. */ public function subscribe(callable $callback): string; /** * Unsubscribes a previously registered handler. * * The handler will no longer be called as long as this method isn't invoked from a subscribed callback. * * @param string $id * * @return void */ public function unsubscribe(string $id); /** * Returns whether cancellation has been requested yet. * * @return bool */ public function isRequested(): bool; /** * Throws the `CancelledException` if cancellation has been requested, otherwise does nothing. * * @return void * * @throws CancelledException */ public function throwIfRequested(); } <?php namespace Amp { use React\Promise\PromiseInterface as ReactPromise; /** * Returns a new function that wraps $callback in a promise/coroutine-aware function that automatically runs * Generators as coroutines. The returned function always returns a promise when invoked. Errors have to be handled * by the callback caller or they will go unnoticed. * * Use this function to create a coroutine-aware callable for a promise-aware callback caller. * * @param callable(...$args): mixed $callback * * @return callable(...$args): \Amp\Promise * * @see asyncCoroutine() */ function coroutine(callable $callback): callable { return function (...$args) use ($callback): Promise { return call($callback,...$args); }; } /** * Returns a new function that wraps $callback in a promise/coroutine-aware function that automatically runs * Generators as coroutines. The returned function always returns void when invoked. Errors are forwarded to the * loop's error handler using `Amp\Promise\rethrow()`. * * Use this function to create a coroutine-aware callable for a non-promise-aware callback caller. * * @param callable(...$args): \Generator|\Amp\Promise|mixed $callback * * @return callable(...$args): void * * @see coroutine() */ function asyncCoroutine(callable $callback): callable { return function (...$args) use ($callback) { Promise\rethrow(call($callback,...$args)); }; } /** * Calls the given function, always returning a promise. If the function returns a Generator, it will be run as a * coroutine. If the function throws, a failed promise will be returned. * * @param callable(...$args):\Generator|mixed $callback * @param ...$args Arguments to pass to the function. * * @return \Amp\Promise */ function call(callable $callback,...$args): Promise { try { $result = $callback(...$args); } catch (\Throwable $exception) { return new Failure($exception); } if ($result instanceof \Generator) { return new Coroutine($result); } if ($result instanceof Promise) { return $result; } if ($result instanceof ReactPromise) { return Promise\adapt($result); } return new Success($result); } /** * Calls the given function. If the function returns a Generator, it will be run as a coroutine. If the function * throws or returns a failing promise, the failure is forwarded to the loop error handler. * * @param callable(...$args):\Generator|mixed $callback * @param mixed ...$args * * @throws \TypeError */ function asyncCall(callable $callback,...$args) { Promise\rethrow(call($callback,...$args)); } } namespace Amp\Promise { use Amp\Deferred; use Amp\Failure; use Amp\Loop; use Amp\MultiReasonException; use Amp\Promise; use Amp\Success; use Amp\TimeoutException; use React\Promise\PromiseInterface as ReactPromise; use function Amp\call; use function Amp\Internal\createTypeError; /** * Registers a callback that will forward the failure reason to the event loop's error handler if the promise fails. * * Use this function if you neither return the promise nor handle a possible error yourself to prevent errors from * going entirely unnoticed. * * @param \Amp\Promise|\React\Promise\PromiseInterface $promise Promise to register the handler on. * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. */ function rethrow($promise) { if (!$promise instanceof Promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } else { throw createTypeError([Promise::class, ReactPromise::class], $promise); } } $promise->onResolve(function ($exception) { if ($exception) { throw $exception; } }); } /** * Runs the event loop until the promise is resolved. Should not be called within a running event loop. * * Use this function only in synchronous contexts to wait for an asynchronous operation. Use coroutines and yield to * await promise resolution in a fully asynchronous application instead. * * @param \Amp\Promise|\React\Promise\PromiseInterface $promise Promise to wait for. * * @return mixed Promise success value. * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. * @throws \Error If the event loop stopped without the $promise being resolved. * @throws \Throwable Promise failure reason. */ function wait($promise) { if (!$promise instanceof Promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } else { throw createTypeError([Promise::class, ReactPromise::class], $promise); } } $resolved = false; try { Loop::run(function () use (&$resolved, &$value, &$exception, $promise) { $promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) { Loop::stop(); $resolved = true; $exception = $e; $value = $v; }); }); } catch (\Throwable $throwable) { throw new \Error("Loop exceptionally stopped without resolving the promise", 0, $throwable); } if (!$resolved) { throw new \Error("Loop stopped without resolving the promise"); } if ($exception) { throw $exception; } return $value; } /** * Creates an artificial timeout for any `Promise`. * * If the timeout expires before the promise is resolved, the returned promise fails with an instance of * `Amp\TimeoutException`. * * @param \Amp\Promise|\React\Promise\PromiseInterface $promise Promise to which the timeout is applied. * @param int $timeout Timeout in milliseconds. * * @return \Amp\Promise * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. */ function timeout($promise, int $timeout): Promise { if (!$promise instanceof Promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } else { throw createTypeError([Promise::class, ReactPromise::class], $promise); } } $deferred = new Deferred; $watcher = Loop::delay($timeout, function () use (&$deferred) { $temp = $deferred; // prevent double resolve $deferred = null; $temp->fail(new TimeoutException); }); Loop::unreference($watcher); $promise->onResolve(function () use (&$deferred, $promise, $watcher) { if ($deferred !== null) { Loop::cancel($watcher); $deferred->resolve($promise); } }); return $deferred->promise(); } /** * Creates an artificial timeout for any `Promise`. * * If the promise is resolved before the timeout expires, the result is returned * * If the timeout expires before the promise is resolved, a default value is returned * * @param \Amp\Promise|\React\Promise\PromiseInterface $promise Promise to which the timeout is applied. * @param int $timeout Timeout in milliseconds. * @param mixed $default * * @return \Amp\Promise * * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. */ function timeoutWithDefault($promise, int $timeout, $default = null): Promise { $promise = timeout($promise, $timeout); return call(function () use ($promise, $default) { try { return yield $promise; } catch (TimeoutException $exception) { return $default; } }); } /** * Adapts any object with a done(callable $onFulfilled, callable $onRejected) or then(callable $onFulfilled, * callable $onRejected) method to a promise usable by components depending on placeholders implementing * \AsyncInterop\Promise. * * @param object $promise Object with a done() or then() method. * * @return \Amp\Promise Promise resolved by the $thenable object. * * @throws \Error If the provided object does not have a then() method. */ function adapt($promise): Promise { $deferred = new Deferred; if (\method_exists($promise, 'done')) { $promise->done([$deferred, 'resolve'], [$deferred, 'fail']); } elseif (\method_exists($promise, 'then')) { $promise->then([$deferred, 'resolve'], [$deferred, 'fail']); } else { throw new \Error("Object must have a 'then' or 'done' method"); } return $deferred->promise(); } /** * Returns a promise that is resolved when all promises are resolved. The returned promise will not fail. * Returned promise succeeds with a two-item array delineating successful and failed promise results, * with keys identical and corresponding to the original given array. * * This function is the same as some() with the notable exception that it will never fail even * if all promises in the array resolve unsuccessfully. * * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises * * @return \Amp\Promise * * @throws \Error If a non-Promise is in the array. */ function any(array $promises): Promise { return some($promises, 0); } /** * Returns a promise that succeeds when all promises succeed, and fails if any promise fails. Returned * promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to * the array of promises. * * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises Array of only promises. * * @return \Amp\Promise * * @throws \Error If a non-Promise is in the array. */ function all(array $promises): Promise { if (empty($promises)) { return new Success([]); } $deferred = new Deferred; $result = $deferred->promise(); $pending = \count($promises); $values = []; foreach ($promises as $key => $promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $values[$key] = null; // add entry to array to preserve order $promise->onResolve(function ($exception, $value) use (&$deferred, &$values, &$pending, $key) { if ($pending === 0) { return; } if ($exception) { $pending = 0; $deferred->fail($exception); $deferred = null; return; } $values[$key] = $value; if (0 === --$pending) { $deferred->resolve($values); } }); } return $result; } /** * Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail. * * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises Array of only promises. * * @return \Amp\Promise * * @throws \Error If the array is empty or a non-Promise is in the array. */ function first(array $promises): Promise { if (empty($promises)) { throw new \Error("No promises provided"); } $deferred = new Deferred; $result = $deferred->promise(); $pending = \count($promises); $exceptions = []; foreach ($promises as $key => $promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $exceptions[$key] = null; // add entry to array to preserve order $promise->onResolve(function ($error, $value) use (&$deferred, &$exceptions, &$pending, $key) { if ($pending === 0) { return; } if (!$error) { $pending = 0; $deferred->resolve($value); $deferred = null; return; } $exceptions[$key] = $error; if (0 === --$pending) { $deferred->fail(new MultiReasonException($exceptions)); } }); } return $result; } /** * Resolves with a two-item array delineating successful and failed Promise results. * * The returned promise will only fail if the given number of required promises fail. * * @param \Amp\Promise[]|\React\Promise\PromiseInterface[] $promises Array of only promises. * @param int $required Number of promises that must succeed for the returned promise to succeed. * * @return \Amp\Promise * * @throws \Error If a non-Promise is in the array. */ function some(array $promises, int $required = 1): Promise { if ($required < 0) { throw new \Error("Number of promises required must be non-negative"); } $pending = \count($promises); if ($required > $pending) { throw new \Error("Too few promises provided"); } if (empty($promises)) { return new Success([[], []]); } $deferred = new Deferred; $result = $deferred->promise(); $values = []; $exceptions = []; foreach ($promises as $key => $promise) { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $values[$key] = $exceptions[$key] = null; // add entry to arrays to preserve order $promise->onResolve(function ($exception, $value) use ( &$values, &$exceptions, &$pending, $key, $required, $deferred ) { if ($exception) { $exceptions[$key] = $exception; unset($values[$key]); } else { $values[$key] = $value; unset($exceptions[$key]); } if (0 === --$pending) { if (\count($values) < $required) { $deferred->fail(new MultiReasonException($exceptions)); } else { $deferred->resolve([$exceptions, $values]); } } }); } return $result; } /** * Wraps a promise into another promise, altering the exception or result. * * @param \Amp\Promise|\React\Promise\PromiseInterface $promise * @param callable $callback * @return Promise */ function wrap($promise, callable $callback): Promise { if ($promise instanceof ReactPromise) { $promise = adapt($promise); } elseif (!$promise instanceof Promise) { throw createTypeError([Promise::class, ReactPromise::class], $promise); } $deferred = new Deferred(); $promise->onResolve(function (\Throwable $exception = null, $result) use ($deferred, $callback) { try { $result = $callback($exception, $result); } catch (\Throwable $exception) { $deferred->fail($exception); return; } $deferred->resolve($result); }); return $deferred->promise(); } } namespace Amp\Iterator { use Amp\Delayed; use Amp\Emitter; use Amp\Iterator; use Amp\Producer; use Amp\Promise; use function Amp\call; use function Amp\coroutine; use function Amp\Internal\createTypeError; /** * Creates an iterator from the given iterable, emitting the each value. The iterable may contain promises. If any * promise fails, the iterator will fail with the same reason. * * @param array|\Traversable $iterable Elements to emit. * @param int $delay Delay between element emissions in milliseconds. * * @return \Amp\Iterator * * @throws \TypeError If the argument is not an array or instance of \Traversable. */ function fromIterable(/* iterable */ $iterable, int $delay = 0 ): Iterator { if (!$iterable instanceof \Traversable && !\is_array($iterable)) { throw createTypeError(["array", "Traversable"], $iterable); } return new Producer(function (callable $emit) use ($iterable, $delay) { foreach ($iterable as $value) { if ($delay) { yield new Delayed($delay); } yield $emit($value); } }); } /** * @param \Amp\Iterator $iterator * @param callable (mixed $value): mixed $onEmit * * @return \Amp\Iterator */ function map(Iterator $iterator, callable $onEmit): Iterator { return new Producer(function (callable $emit) use ($iterator, $onEmit) { while (yield $iterator->advance()) { yield $emit($onEmit($iterator->getCurrent())); } }); } /** * @param \Amp\Iterator $iterator * @param callable (mixed $value): bool $filter * * @return \Amp\Iterator */ function filter(Iterator $iterator, callable $filter): Iterator { return new Producer(function (callable $emit) use ($iterator, $filter) { while (yield $iterator->advance()) { if ($filter($iterator->getCurrent())) { yield $emit($iterator->getCurrent()); } } }); } /** * Creates an iterator that emits values emitted from any iterator in the array of iterators. * * @param \Amp\Iterator[] $iterators * * @return \Amp\Iterator */ function merge(array $iterators): Iterator { $emitter = new Emitter; $result = $emitter->iterate(); $coroutine = coroutine(function (Iterator $iterator) use (&$emitter) { while ((yield $iterator->advance()) && $emitter !== null) { yield $emitter->emit($iterator->getCurrent()); } }); $coroutines = []; foreach ($iterators as $iterator) { if (!$iterator instanceof Iterator) { throw createTypeError([Iterator::class], $iterator); } $coroutines[] = $coroutine($iterator); } Promise\all($coroutines)->onResolve(function ($exception) use (&$emitter) { if ($exception) { $emitter->fail($exception); $emitter = null; } else { $emitter->complete(); } }); return $result; } /** * Concatenates the given iterators into a single iterator, emitting values from a single iterator at a time. The * prior iterator must complete before values are emitted from any subsequent iterators. Iterators are concatenated * in the order given (iteration order of the array). * * @param array $iterators * * @return \Amp\Iterator */ function concat(array $iterators): Iterator { foreach ($iterators as $iterator) { if (!$iterator instanceof Iterator) { throw createTypeError([Iterator::class], $iterator); } } $emitter = new Emitter; $previous = []; $promise = Promise\all($previous); $coroutine = coroutine(function (Iterator $iterator, callable $emit) { while (yield $iterator->advance()) { yield $emit($iterator->getCurrent()); } }); foreach ($iterators as $iterator) { $emit = coroutine(function ($value) use ($emitter, $promise) { static $pending = true, $failed = false; if ($failed) { return; } if ($pending) { try { yield $promise; $pending = false; } catch (\Throwable $exception) { $failed = true; return; // Prior iterator failed. } } yield $emitter->emit($value); }); $previous[] = $coroutine($iterator, $emit); $promise = Promise\all($previous); } $promise->onResolve(function ($exception) use ($emitter) { if ($exception) { $emitter->fail($exception); return; } $emitter->complete(); }); return $emitter->iterate(); } /** * Collects all items from an iterator into an array. * * @param Iterator $iterator * * @return Promise<array> */ function toArray(Iterator $iterator): Promise { return call(function () use ($iterator) { $array = []; while (yield $iterator->advance()) { $array[] = $iterator->getCurrent(); } return $array; }); } } <?php namespace Amp; use React\Promise\PromiseInterface as ReactPromise; /** * Creates a failed promise using the given exception. */ final class Failure implements Promise { /** @var \Throwable $exception */ private $exception; /** * @param \Throwable $exception Rejection reason. */ public function __construct(\Throwable $exception) { $this->exception = $exception; } /** * {@inheritdoc} */ public function onResolve(callable $onResolved) { try { $result = $onResolved($this->exception, null); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use ($exception) { throw $exception; }); } } } <?php namespace Amp; /** * Deferred is a container for a promise that is resolved using the resolve() and fail() methods of this object. * The contained promise may be accessed using the promise() method. This object should not be part of a public * API, but used internally to create and resolve a promise. */ final class Deferred { /** @var object Has public resolve and fail methods. */ private $resolver; /** @var \Amp\Promise Hides placeholder methods */ private $promise; public function __construct() { $this->resolver = new class implements Promise { use Internal\Placeholder { resolve as public; fail as public; } }; $this->promise = new Internal\PrivatePromise($this->resolver); } /** * @return \Amp\Promise */ public function promise(): Promise { return $this->promise; } /** * Fulfill the promise with the given value. * * @param mixed $value */ public function resolve($value = null) { $this->resolver->resolve($value); } /** * Fails the promise the the given reason. * * @param \Throwable $reason */ public function fail(\Throwable $reason) { $this->resolver->fail($reason); } } <?php namespace Amp; /** * A NullCancellationToken can be used to avoid conditionals to check whether a token has been provided. * * Instead of writing * * ```php * if ($token) { * $token->throwIfRequested(); * } * ``` * * potentially multiple times, it allows writing * * ```php * $token = $token ?? new NullCancellationToken; * * //... * * $token->throwIfRequested(); * ``` * * instead. */ final class NullCancellationToken implements CancellationToken { /** @inheritdoc */ public function subscribe(callable $callback): string { return "null-token"; } /** @inheritdoc */ public function unsubscribe(string $id) { // nothing to do } /** @inheritdoc */ public function isRequested(): bool { return false; } /** @inheritdoc */ public function throwIfRequested() { // nothing to do } } <?php namespace Amp; class MultiReasonException extends \Exception { /** @var \Throwable[] */ private $reasons; /** * @param \Throwable[] $reasons Array of exceptions rejecting the promise. * @param string|null $message */ public function __construct(array $reasons, string $message = null) { parent::__construct($message ?: "Multiple errors encountered; use " . self::class . "::getReasons() to retrieve the array of exceptions thrown"); $this->reasons = $reasons; } /** * @return \Throwable[] */ public function getReasons(): array { return $this->reasons; } } <?php namespace Amp; /** * Creates a promise that calls $promisor only when the result of the promise is requested (i.e. onResolve() is called * on the promise). $promisor can return a promise or any value. If $promisor throws an exception, the promise fails * with that exception. If $promisor returns a Generator, it will be run as a coroutine. */ final class LazyPromise implements Promise { /** @var callable|null */ private $promisor; /** @var \Amp\Promise|null */ private $promise; /** * @param callable $promisor Function which starts an async operation, returning a Promise (or any value). * Generators will be run as a coroutine. */ public function __construct(callable $promisor) { $this->promisor = $promisor; } /** * {@inheritdoc} */ public function onResolve(callable $onResolved) { if ($this->promise === null) { $provider = $this->promisor; $this->promisor = null; $this->promise = call($provider); } $this->promise->onResolve($onResolved); } } <?php namespace Amp; use React\Promise\PromiseInterface as ReactPromise; /** * Creates a successful promise using the given value (which can be any value except an object implementing * `Amp\Promise` or `React\Promise\PromiseInterface`). */ final class Success implements Promise { /** @var mixed */ private $value; /** * @param mixed $value Anything other than a Promise object. * * @throws \Error If a promise is given as the value. */ public function __construct($value = null) { if ($value instanceof Promise || $value instanceof ReactPromise) { throw new \Error("Cannot use a promise as success value"); } $this->value = $value; } /** * {@inheritdoc} */ public function onResolve(callable $onResolved) { try { $result = $onResolved(null, $this->value); if ($result === null) { return; } if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { Promise\rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use ($exception) { throw $exception; }); } } } <?php namespace Amp; /** * Representation of the future value of an asynchronous operation. */ interface Promise { /** * Registers a callback to be invoked when the promise is resolved. * * If this method is called multiple times, additional handlers will be registered instead of replacing any already * existing handlers. * * If the promise is already resolved, the callback MUST be executed immediately. * * Exceptions MUST NOT be thrown from this method. Any exceptions thrown from invoked callbacks MUST be * forwarded to the event-loop error handler. * * Note: You shouldn't implement this interface yourself. Instead, provide a method that returns a promise for the * operation you're implementing. Objects other than pure placeholders implementing it are a very bad idea. * * @param callable(\Throwable|null $reason, $value) $onResolved `$reason` shall be `null` on * success, `$value` shall be `null` on failure. * * @return void */ public function onResolve(callable $onResolved); } <?php namespace Amp; /** * A "safe" struct trait for public property aggregators. * * This trait is intended to make using public properties a little safer by throwing when * nonexistent property names are read or written. */ trait Struct { /** * The minimum percentage [0-100] at which to recommend a similar property * name when generating error messages. */ private $__propertySuggestThreshold = 70; public function __get(string $property) { throw new \Error( $this->generateStructPropertyError($property) ); } public function __set(string $property, $value) { throw new \Error( $this->generateStructPropertyError($property) ); } private function generateStructPropertyError(string $property): string { $suggestion = $this->suggestPropertyName($property); $suggestStr = ($suggestion == "") ? "" : "... did you mean \"{$suggestion}?\""; return \sprintf( "%s property \"%s\" does not exist%s", \str_replace("\0", "@", \get_class($this)), // Handle anonymous class names. $property, $suggestStr ); } private function suggestPropertyName(string $badProperty): string { $badProperty = \strtolower($badProperty); $bestMatch = ""; $bestMatchPercentage = 0; foreach ($this as $property => $value) { // Never suggest properties that begin with an underscore if ($property[0] === "_") { continue; } \similar_text($badProperty, \strtolower($property), $byRefPercentage); if ($byRefPercentage > $bestMatchPercentage) { $bestMatchPercentage = $byRefPercentage; $bestMatch = $property; } } return ($bestMatchPercentage >= $this->__propertySuggestThreshold) ? $bestMatch : ""; } } <?php namespace Amp; use React\Promise\PromiseInterface as ReactPromise; /** * Creates a promise from a generator function yielding promises. * * When a promise is yielded, execution of the generator is interrupted until the promise is resolved. A success * value is sent into the generator, while a failure reason is thrown into the generator. Using a coroutine, * asynchronous code can be written without callbacks and be structured like synchronous code. */ final class Coroutine implements Promise { use Internal\Placeholder; /** * Attempts to transform the non-promise yielded from the generator into a promise, otherwise returns an instance * `Amp\Failure` failed with an instance of `Amp\InvalidYieldError`. * * @param mixed $yielded Non-promise yielded from generator. * @param \Generator $generator No type for performance, we already know the type. * * @return Promise */ private static function transform($yielded, $generator): Promise { try { if (\is_array($yielded)) { return Promise\all($yielded); } if ($yielded instanceof ReactPromise) { return Promise\adapt($yielded); } // No match, continue to returning Failure below. } catch (\Throwable $exception) { // Conversion to promise failed, fall-through to returning Failure below. } return new Failure(new InvalidYieldError( $generator, \sprintf( "Unexpected yield; Expected an instance of %s or %s or an array of such instances", Promise::class, ReactPromise::class ), $exception ?? null )); } /** * @param \Generator $generator */ public function __construct(\Generator $generator) { try { $yielded = $generator->current(); if (!$yielded instanceof Promise) { if (!$generator->valid()) { $this->resolve($generator->getReturn()); return; } $yielded = self::transform($yielded, $generator); } } catch (\Throwable $exception) { $this->fail($exception); return; } /** * @param \Throwable|null $e Exception to be thrown into the generator. * @param mixed $v Value to be sent into the generator. */ $onResolve = function ($e, $v) use ($generator, &$onResolve) { /** @var bool Used to control iterative coroutine continuation. */ static $immediate = true; /** @var \Throwable|null Promise failure reason when executing next coroutine step, null at all other times. */ static $exception; /** @var mixed Promise success value when executing next coroutine step, null at all other times. */ static $value; $exception = $e; $value = $v; if (!$immediate) { $immediate = true; return; } try { try { do { if ($exception) { // Throw exception at current execution point. $yielded = $generator->throw($exception); } else { // Send the new value and execute to next yield statement. $yielded = $generator->send($value); } if (!$yielded instanceof Promise) { if (!$generator->valid()) { $this->resolve($generator->getReturn()); $onResolve = null; return; } $yielded = self::transform($yielded, $generator); } $immediate = false; $yielded->onResolve($onResolve); } while ($immediate); $immediate = true; } catch (\Throwable $exception) { $this->fail($exception); $onResolve = null; } finally { $exception = null; $value = null; } } catch (\Throwable $e) { Loop::defer(static function () use ($e) { throw $e; }); } }; try { $yielded->onResolve($onResolve); unset($generator, $yielded, $onResolve); } catch (\Throwable $e) { Loop::defer(static function () use ($e) { throw $e; }); } } } <?php namespace Amp; // @codeCoverageIgnoreStart if (\PHP_VERSION_ID < 70100) { trait CallableMaker { /** @var \ReflectionClass */ private static $__reflectionClass; /** @var \ReflectionMethod[] */ private static $__reflectionMethods = []; /** * Creates a callable from a protected or private instance method that may be invoked by callers requiring a * publicly invokable callback. * * @param string $method Instance method name. * * @return callable */ private function callableFromInstanceMethod(string $method): callable { if (!isset(self::$__reflectionMethods[$method])) { if (self::$__reflectionClass === null) { self::$__reflectionClass = new \ReflectionClass(self::class); } self::$__reflectionMethods[$method] = self::$__reflectionClass->getMethod($method); } return self::$__reflectionMethods[$method]->getClosure($this); } /** * Creates a callable from a protected or private static method that may be invoked by methods requiring a * publicly invokable callback. * * @param string $method Static method name. * * @return callable */ private static function callableFromStaticMethod(string $method): callable { if (!isset(self::$__reflectionMethods[$method])) { if (self::$__reflectionClass === null) { self::$__reflectionClass = new \ReflectionClass(self::class); } self::$__reflectionMethods[$method] = self::$__reflectionClass->getMethod($method); } return self::$__reflectionMethods[$method]->getClosure(); } } } else { trait CallableMaker { /** * @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1. */ private function callableFromInstanceMethod(string $method): callable { return \Closure::fromCallable([$this, $method]); } /** * @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1. */ private static function callableFromStaticMethod(string $method): callable { return \Closure::fromCallable([self::class, $method]); } } } // @codeCoverageIgnoreEnd <?php namespace Amp; /** * Creates a promise that resolves itself with a given value after a number of milliseconds. */ final class Delayed implements Promise { use Internal\Placeholder; /** @var string Event loop watcher identifier. */ private $watcher; /** * @param int $time Milliseconds before succeeding the promise. * @param mixed $value Succeed the promise with this value. */ public function __construct(int $time, $value = null) { $this->watcher = Loop::delay($time, function () use ($value) { $this->resolve($value); }); } /** * References the internal watcher in the event loop, keeping the loop running while this promise is pending. */ public function reference() { Loop::reference($this->watcher); } /** * Unreferences the internal watcher in the event loop, allowing the loop to stop while this promise is pending if * no other events are pending in the loop. */ public function unreference() { Loop::unreference($this->watcher); } } <?php namespace Amp; class InvalidYieldError extends \Error { /** * @param \Generator $generator * @param string $prefix * @param \Throwable|null $previous */ public function __construct(\Generator $generator, string $prefix, \Throwable $previous = null) { $yielded = $generator->current(); $prefix .= \sprintf( "; %s yielded at key %s", \is_object($yielded) ? \get_class($yielded) : \gettype($yielded), \var_export($generator->key(), true) ); if (!$generator->valid()) { parent::__construct($prefix, 0, $previous); return; } $reflGen = new \ReflectionGenerator($generator); $exeGen = $reflGen->getExecutingGenerator(); if ($isSubgenerator = ($exeGen !== $generator)) { $reflGen = new \ReflectionGenerator($exeGen); } parent::__construct(\sprintf( "%s on line %s in %s", $prefix, $reflGen->getExecutingLine(), $reflGen->getExecutingFile() ), 0, $previous); } } <?php namespace Amp; use React\Promise\PromiseInterface as ReactPromise; use function Amp\Promise\rethrow; /** * A cancellation token source provides a mechanism to cancel operations. * * Cancellation of operation works by creating a cancellation token source and passing the corresponding token when * starting the operation. To cancel the operation, invoke `CancellationTokenSource::cancel()`. * * Any operation can decide what to do on a cancellation request, it has "don't care" semantics. An operation SHOULD be * aborted, but MAY continue. Example: A DNS client might continue to receive and cache the response, as the query has * been sent anyway. An HTTP client would usually close a connection, but might not do so in case a response is close to * be fully received to reuse the connection. * * **Example** * * ```php * $tokenSource = new CancellationTokenSource; * $token = $tokenSource->getToken(); * * $response = yield $httpClient->request("https://example.com/stream", $token); * $responseBody = $response->getBody(); * * while (($chunk = yield $response->read()) !== null) { * // consume $chunk * * if ($noLongerInterested) { * $cancellationTokenSource->cancel(); * break; * } * } * ``` * * @see CancellationToken * @see CancelledException */ final class CancellationTokenSource { private $token; private $onCancel; public function __construct() { $this->token = new class($this->onCancel) implements CancellationToken { /** @var string */ private $nextId = "a"; /** @var callable[] */ private $callbacks = []; /** @var \Throwable|null */ private $exception = null; public function __construct(&$onCancel) { $onCancel = function (\Throwable $exception) { $this->exception = $exception; $callbacks = $this->callbacks; $this->callbacks = []; foreach ($callbacks as $callback) { $this->invokeCallback($callback); } }; } private function invokeCallback($callback) { // No type declaration to prevent exception outside the try! try { $result = $callback($this->exception); if ($result instanceof \Generator) { $result = new Coroutine($result); } if ($result instanceof Promise || $result instanceof ReactPromise) { rethrow($result); } } catch (\Throwable $exception) { Loop::defer(static function () use ($exception) { throw $exception; }); } } public function subscribe(callable $callback): string { $id = $this->nextId++; if ($this->exception) { $this->invokeCallback($callback); } else { $this->callbacks[$id] = $callback; } return $id; } public function unsubscribe(string $id) { unset($this->callbacks[$id]); } public function isRequested(): bool { return isset($this->exception); } public function throwIfRequested() { if (isset($this->exception)) { throw $this->exception; } } }; } public function getToken(): CancellationToken { return $this->token; } /** * @param \Throwable|null $previous Exception to be used as the previous exception to CancelledException. */ public function cancel(\Throwable $previous = null) { if ($this->onCancel === null) { return; } $onCancel = $this->onCancel; $this->onCancel = null; $onCancel(new CancelledException($previous)); } } <?php // Adopted from ReactPHP's stream package // https://github.com/reactphp/stream/blob/b996af99fd1169ff74e93ef69c1513b7d0db19d0/examples/benchmark-throughput.php use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::set(new Loop\NativeDriver()); $args = \getopt('i:o:t:'); $if = isset($args['i']) ? $args['i'] : '/dev/zero'; $of = isset($args['o']) ? $args['o'] : '/dev/null'; $t = isset($args['t']) ? $args['t'] : 30; // passing file descriptors requires mapping paths (https://bugs.php.net/bug.php?id=53465) $if = \preg_replace('(^/dev/fd/)', 'php://fd/', $if); $of = \preg_replace('(^/dev/fd/)', 'php://fd/', $of); $stderr = new ResourceOutputStream(STDERR); $in = new ResourceInputStream(\fopen($if, 'r'), 65536 /* Default size used by React to allow comparisons */); $out = new ResourceOutputStream(\fopen($of, 'w')); if (\extension_loaded('xdebug')) { $stderr->write('NOTICE: The "xdebug" extension is loaded, this has a major impact on performance.' . PHP_EOL); } try { if (!@\assert(false)) { $stderr->write("NOTICE: Assertions are enabled, this has a major impact on performance." . PHP_EOL); } } catch (AssertionError $exception) { $stderr->write("NOTICE: Assertions are enabled, this has a major impact on performance." . PHP_EOL); } $stderr->write('piping from ' . $if . ' to ' . $of . ' (for max ' . $t . ' second(s))...'. PHP_EOL); Loop::delay($t * 1000, [$in, "close"]); Loop::run(function () use ($stderr, $in, $out) { $start = \microtime(true); while (($chunk = yield $in->read()) !== null) { yield $out->write($chunk); } $t = \microtime(true) - $start; $bytes = \ftell($out->getResource()); $stderr->write('read ' . $bytes . ' byte(s) in ' . \round($t, 3) . ' second(s) => ' . \round($bytes / 1024 / 1024 / $t, 1) . ' MiB/s' . PHP_EOL); $stderr->write('peak memory usage of ' . \round(\memory_get_peak_usage(true) / 1024 / 1024, 1) . ' MiB' . PHP_EOL); }); <?php use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\ByteStream\ZlibInputStream; use Amp\Loop; require __DIR__ . "/../vendor/autoload.php"; Loop::run(function () { $stdin = new ResourceInputStream(STDIN); $stdout = new ResourceOutputStream(STDOUT); $gzin = new ZlibInputStream($stdin, ZLIB_ENCODING_GZIP); while (($chunk = yield $gzin->read()) !== null) { yield $stdout->write($chunk); } }); <?php use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\ByteStream\ZlibOutputStream; use Amp\Loop; require __DIR__ . "/../vendor/autoload.php"; Loop::run(function () { $stdin = new ResourceInputStream(STDIN); $stdout = new ResourceOutputStream(STDOUT); $gzout = new ZlibOutputStream($stdout, ZLIB_ENCODING_GZIP); while (($chunk = yield $stdin->read()) !== null) { yield $gzout->write($chunk); } }); { "name": "amphp/byte-stream", "homepage": "http://amphp.org/byte-stream", "description": "A stream abstraction to make working with non-blocking I/O simple.", "support": { "issues": "https://github.com/amphp/byte-stream/issues", "irc": "irc://irc.freenode.org/amphp" }, "keywords": [ "stream", "async", "non-blocking", "amp", "amphp", "io" ], "license": "MIT", "authors": [ { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "require": { "amphp/amp": "^2" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "friendsofphp/php-cs-fixer": "^2.3", "amphp/php-cs-fixer-config": "dev-master", "infection/infection": "^0.9.3" }, "autoload": { "psr-4": { "Amp\\ByteStream\\": "lib" }, "files": [ "lib/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\ByteStream\\Test\\": "test" } }, "config": { "platform": { "php": "7.0.0" } } } <?php namespace Amp\ByteStream; use Amp\Deferred; use Amp\Failure; use Amp\Iterator; use Amp\Promise; final class IteratorStream implements InputStream { private $iterator; private $exception; private $pending = false; public function __construct(Iterator $iterator) { $this->iterator = $iterator; } /** @inheritdoc */ public function read(): Promise { if ($this->exception) { return new Failure($this->exception); } if ($this->pending) { throw new PendingReadError; } $this->pending = true; $deferred = new Deferred; $this->iterator->advance()->onResolve(function ($error, $hasNextElement) use ($deferred) { $this->pending = false; if ($error) { $this->exception = $error; $deferred->fail($error); } elseif ($hasNextElement) { $chunk = $this->iterator->getCurrent(); if (!\is_string($chunk)) { $this->exception = new StreamException(\sprintf( "Unexpected iterator value of type '%s', expected string", \is_object($chunk) ? \get_class($chunk) : \gettype($chunk) )); $deferred->fail($this->exception); return; } $deferred->resolve($chunk); } else { $deferred->resolve(); } }); return $deferred->promise(); } } <?php namespace Amp\ByteStream; use Amp\Loop; use Amp\Promise; use function Amp\call; // @codeCoverageIgnoreStart if (\strlen('…') !== 3) { throw new \Error( 'The mbstring.func_overload ini setting is enabled. It must be disabled to use the stream package.' ); } // @codeCoverageIgnoreEnd if (!\defined('STDOUT')) { \define('STDOUT', \fopen('php://stdout', 'w')); } if (!\defined('STDERR')) { \define('STDERR', \fopen('php://stderr', 'w')); } /** * @param \Amp\ByteStream\InputStream $source * @param \Amp\ByteStream\OutputStream $destination * * @return \Amp\Promise */ function pipe(InputStream $source, OutputStream $destination): Promise { return call(function () use ($source, $destination): \Generator { $written = 0; while (($chunk = yield $source->read()) !== null) { $written += \strlen($chunk); $writePromise = $destination->write($chunk); $chunk = null; // free memory yield $writePromise; } return $written; }); } /** * @param \Amp\ByteStream\InputStream $source * * @return \Amp\Promise */ function buffer(InputStream $source): Promise { return call(function () use ($source): \Generator { $buffer = ""; while (($chunk = yield $source->read()) !== null) { $buffer .= $chunk; $chunk = null; // free memory } return $buffer; }); } /** * The php://input input buffer stream for the process associated with the currently active event loop. * * @return ResourceInputStream */ function getInputBufferStream(): ResourceInputStream { static $key = InputStream::class . '\\input'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceInputStream(\fopen('php://input', 'rb')); Loop::setState($key, $stream); } return $stream; } /** * The php://output output buffer stream for the process associated with the currently active event loop. * * @return ResourceOutputStream */ function getOutputBufferStream(): ResourceOutputStream { static $key = OutputStream::class . '\\output'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceOutputStream(\fopen('php://output', 'wb')); Loop::setState($key, $stream); } return $stream; } /** * The STDIN stream for the process associated with the currently active event loop. * * @return ResourceInputStream */ function getStdin(): ResourceInputStream { static $key = InputStream::class . '\\stdin'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceInputStream(\STDIN); Loop::setState($key, $stream); } return $stream; } /** * The STDOUT stream for the process associated with the currently active event loop. * * @return ResourceOutputStream */ function getStdout(): ResourceOutputStream { static $key = OutputStream::class . '\\stdout'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceOutputStream(\STDOUT); Loop::setState($key, $stream); } return $stream; } /** * The STDERR stream for the process associated with the currently active event loop. * * @return ResourceOutputStream */ function getStderr(): ResourceOutputStream { static $key = OutputStream::class . '\\stderr'; $stream = Loop::getState($key); if (!$stream) { $stream = new ResourceOutputStream(\STDERR); Loop::setState($key, $stream); } return $stream; } <?php namespace Amp\ByteStream; /** * Thrown in case a second read operation is attempted while another read operation is still pending. */ final class PendingReadError extends \Error { public function __construct( string $message = "The previous read operation must complete before read can be called again", int $code = 0, \Throwable $previous = null ) { parent::__construct($message, $code, $previous); } } <?php namespace Amp\ByteStream; use Amp\Promise; use function Amp\call; /** * Allows decompression of input streams using Zlib. */ final class ZlibInputStream implements InputStream { private $source; private $encoding; private $options; private $resource; /** * @param InputStream $source Input stream to read compressed data from. * @param int $encoding Compression algorithm used, see `inflate_init()`. * @param array $options Algorithm options, see `inflate_init()`. * * @throws StreamException * @throws \Error * * @see http://php.net/manual/en/function.inflate-init.php */ public function __construct(InputStream $source, int $encoding, array $options = []) { $this->source = $source; $this->encoding = $encoding; $this->options = $options; $this->resource = @\inflate_init($encoding, $options); if ($this->resource === false) { throw new StreamException("Failed initializing deflate context"); } } /** @inheritdoc */ public function read(): Promise { return call(function () { if ($this->resource === null) { return null; } $data = yield $this->source->read(); // Needs a double guard, as stream might have been closed while reading if ($this->resource === null) { return null; } if ($data === null) { $decompressed = @\inflate_add($this->resource, "", \ZLIB_FINISH); if ($decompressed === false) { throw new StreamException("Failed adding data to deflate context"); } $this->close(); return $decompressed; } $decompressed = @\inflate_add($this->resource, $data, \ZLIB_SYNC_FLUSH); if ($decompressed === false) { throw new StreamException("Failed adding data to deflate context"); } return $decompressed; }); } /** @internal */ private function close() { $this->resource = null; $this->source = null; } /** * Gets the used compression encoding. * * @return int Encoding specified on construction time. */ public function getEncoding(): int { return $this->encoding; } /** * Gets the used compression options. * * @return array Options array passed on construction time. */ public function getOptions(): array { return $this->options; } } <?php namespace Amp\ByteStream; use Amp\Promise; /** * An `OutputStream` allows writing data in chunks. Writers can wait on the returned promises to feel the backpressure. */ interface OutputStream { /** * Writes data to the stream. * * @param string $data Bytes to write. * * @return Promise Succeeds once the data has been successfully written to the stream. * * @throws ClosedException If the stream has already been closed. */ public function write(string $data): Promise; /** * Marks the stream as no longer writable. Optionally writes a final data chunk before. Note that this is not the * same as forcefully closing the stream. This method waits for all pending writes to complete before closing the * stream. Socket streams implementing this interface should only close the writable side of the stream. * * @param string $finalData Bytes to write. * * @return Promise Succeeds once the data has been successfully written to the stream. * * @throws ClosedException If the stream has already been closed. */ public function end(string $finalData = ""): Promise; } <?php namespace Amp\ByteStream; final class ClosedException extends StreamException { } <?php namespace Amp\ByteStream; use Amp\Deferred; use Amp\Promise; use Amp\Success; class OutputBuffer implements OutputStream, Promise { /** @var \Amp\Deferred|null */ private $deferred; /** @var string */ private $contents; private $closed = false; public function __construct() { $this->deferred = new Deferred; } public function write(string $data): Promise { if ($this->closed) { throw new ClosedException("The stream has already been closed."); } $this->contents .= $data; return new Success(\strlen($data)); } public function end(string $finalData = ""): Promise { if ($this->closed) { throw new ClosedException("The stream has already been closed."); } $this->contents .= $finalData; $this->closed = true; $this->deferred->resolve($this->contents); $this->contents = ""; return new Success(\strlen($finalData)); } public function onResolve(callable $onResolved) { $this->deferred->promise()->onResolve($onResolved); } } <?php namespace Amp\ByteStream; use Amp\Promise; /** * An `InputStream` allows reading byte streams in chunks. * * **Example** * * ```php * function readAll(InputStream $in): Promise { * return Amp\call(function () use ($in) { * $buffer = ""; * * while (($chunk = yield $in->read()) !== null) { * $buffer .= $chunk; * } * * return $buffer; * }); * } * ``` */ interface InputStream { /** * Reads data from the stream. * * @return Promise Resolves with a string when new data is available or `null` if the stream has closed. * * @throws PendingReadError Thrown if another read operation is still pending. */ public function read(): Promise; } <?php namespace Amp\ByteStream; use Amp\Deferred; use Amp\Loop; use Amp\Promise; use Amp\Success; /** * Input stream abstraction for PHP's stream resources. */ final class ResourceInputStream implements InputStream { const DEFAULT_CHUNK_SIZE = 8192; /** @var resource */ private $resource; /** @var string */ private $watcher; /** @var \Amp\Deferred|null */ private $deferred; /** @var bool */ private $readable = true; /** @var int */ private $chunkSize; /** @var bool */ private $useSingleRead; /** @var callable */ private $immediateCallable; /** @var string */ private $immediateWatcher; /** * @param resource $stream Stream resource. * @param int $chunkSize Chunk size per read operation. * * @throws \Error If an invalid stream or parameter has been passed. */ public function __construct($stream, int $chunkSize = self::DEFAULT_CHUNK_SIZE) { if (!\is_resource($stream) || \get_resource_type($stream) !== 'stream') { throw new \Error("Expected a valid stream"); } $meta = \stream_get_meta_data($stream); $useSingleRead = $meta["stream_type"] === "udp_socket" || $meta["stream_type"] === "STDIO"; $this->useSingleRead = $useSingleRead; if (\strpos($meta["mode"], "r") === false && \strpos($meta["mode"], "+") === false) { throw new \Error("Expected a readable stream"); } \stream_set_blocking($stream, false); \stream_set_read_buffer($stream, 0); $this->resource = $stream; $this->chunkSize = &$chunkSize; $deferred = &$this->deferred; $readable = &$this->readable; $this->watcher = Loop::onReadable($this->resource, static function ($watcher, $stream) use ( &$deferred, &$readable, &$chunkSize, $useSingleRead ) { if ($useSingleRead) { $data = @\fread($stream, $chunkSize); } else { $data = @\stream_get_contents($stream, $chunkSize); } \assert($data !== false, "Trying to read from a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); // Error suppression, because pthreads does crazy things with resources, // which might be closed during two operations. // See https://github.com/amphp/byte-stream/issues/32 if ($data === '' && @\feof($stream)) { $readable = false; Loop::cancel($watcher); $data = null; // Stream closed, resolve read with null. } Loop::disable($watcher); $temp = $deferred; $deferred = null; \assert($temp instanceof Deferred); $temp->resolve($data); }); $this->immediateCallable = static function ($watcherId, $data) use (&$deferred) { $temp = $deferred; $deferred = null; \assert($temp instanceof Deferred); $temp->resolve($data); }; Loop::disable($this->watcher); } /** @inheritdoc */ public function read(): Promise { if ($this->deferred !== null) { throw new PendingReadError; } if (!$this->readable) { return new Success; // Resolve with null on closed stream. } // Attempt a direct read, because Windows suffers from slow I/O on STDIN otherwise. if ($this->useSingleRead) { $data = @\fread($this->resource, $this->chunkSize); } else { $data = @\stream_get_contents($this->resource, $this->chunkSize); } \assert($data !== false, "Trying to read from a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); if ($data === '') { // Error suppression, because pthreads does crazy things with resources, // which might be closed during two operations. // See https://github.com/amphp/byte-stream/issues/32 if (@\feof($this->resource)) { $this->readable = false; Loop::cancel($this->watcher); $data = null; // Stream closed, resolve read with null. } else { $this->deferred = new Deferred; Loop::enable($this->watcher); return $this->deferred->promise(); } } // Prevent an immediate read → write loop from blocking everything // See e.g. examples/benchmark-throughput.php $this->deferred = new Deferred; $this->immediateWatcher = Loop::defer($this->immediateCallable, $data); return $this->deferred->promise(); } /** * Closes the stream forcefully. Multiple `close()` calls are ignored. * * @return void */ public function close() { if ($this->resource) { // Error suppression, as resource might already be closed $meta = @\stream_get_meta_data($this->resource); if ($meta && \strpos($meta["mode"], "+") !== false) { @\stream_socket_shutdown($this->resource, \STREAM_SHUT_RD); } else { @\fclose($this->resource); } $this->resource = null; } $this->free(); } /** * Nulls reference to resource, marks stream unreadable, and succeeds any pending read with null. */ private function free() { $this->readable = false; if ($this->deferred !== null) { $deferred = $this->deferred; $this->deferred = null; $deferred->resolve(); } Loop::cancel($this->watcher); if ($this->immediateWatcher !== null) { Loop::cancel($this->immediateWatcher); } } /** * @return resource|null The stream resource or null if the stream has closed. */ public function getResource() { return $this->resource; } public function setChunkSize(int $chunkSize) { $this->chunkSize = $chunkSize; } /** * References the read watcher, so the loop keeps running in case there's an active read. * * @see Loop::reference() */ public function reference() { if (!$this->resource) { throw new \Error("Resource has already been freed"); } Loop::reference($this->watcher); } /** * Unreferences the read watcher, so the loop doesn't keep running even if there are active reads. * * @see Loop::unreference() */ public function unreference() { if (!$this->resource) { throw new \Error("Resource has already been freed"); } Loop::unreference($this->watcher); } public function __destruct() { if ($this->resource !== null) { $this->free(); } } } <?php namespace Amp\ByteStream; use Amp\Coroutine; use Amp\Deferred; use Amp\Failure; use Amp\Promise; use Amp\Success; /** * Creates a buffered message from an InputStream. The message can be consumed in chunks using the read() API or it may * be buffered and accessed in its entirety by waiting for the promise to resolve. * * Other implementations may extend this class to add custom properties such as a `isBinary()` flag for WebSocket * messages. * * Buffering Example: * * $stream = new Message($inputStream); * $content = yield $stream; * * Streaming Example: * * $stream = new Message($inputStream); * * while (($chunk = yield $stream->read()) !== null) { * // Immediately use $chunk, reducing memory consumption since the entire message is never buffered. * } * * @deprecated Use Amp\ByteStream\Payload instead. */ class Message implements InputStream, Promise { /** @var InputStream */ private $source; /** @var string */ private $buffer = ""; /** @var \Amp\Deferred|null */ private $pendingRead; /** @var \Amp\Coroutine */ private $coroutine; /** @var bool True if onResolve() has been called. */ private $buffering = false; /** @var \Amp\Deferred|null */ private $backpressure; /** @var bool True if the iterator has completed. */ private $complete = false; /** @var \Throwable Used to fail future reads on failure. */ private $error; /** * @param InputStream $source An iterator that only emits strings. */ public function __construct(InputStream $source) { $this->source = $source; } private function consume(): \Generator { while (($chunk = yield $this->source->read()) !== null) { $buffer = $this->buffer .= $chunk; if ($buffer === "") { continue; // Do not succeed reads with empty string. } elseif ($this->pendingRead) { $deferred = $this->pendingRead; $this->pendingRead = null; $this->buffer = ""; $deferred->resolve($buffer); $buffer = ""; // Destroy last emitted chunk to free memory. } elseif (!$this->buffering) { $buffer = ""; // Destroy last emitted chunk to free memory. $this->backpressure = new Deferred; yield $this->backpressure->promise(); } } $this->complete = true; if ($this->pendingRead) { $deferred = $this->pendingRead; $this->pendingRead = null; $deferred->resolve($this->buffer !== "" ? $this->buffer : null); $this->buffer = ""; } return $this->buffer; } /** @inheritdoc */ final public function read(): Promise { if ($this->pendingRead) { throw new PendingReadError; } if ($this->coroutine === null) { $this->coroutine = new Coroutine($this->consume()); $this->coroutine->onResolve(function ($error) { if ($error) { $this->error = $error; } if ($this->pendingRead) { $deferred = $this->pendingRead; $this->pendingRead = null; $deferred->fail($error); } }); } if ($this->error) { return new Failure($this->error); } if ($this->buffer !== "") { $buffer = $this->buffer; $this->buffer = ""; if ($this->backpressure) { $backpressure = $this->backpressure; $this->backpressure = null; $backpressure->resolve(); } return new Success($buffer); } if ($this->complete) { return new Success; } $this->pendingRead = new Deferred; return $this->pendingRead->promise(); } /** @inheritdoc */ final public function onResolve(callable $onResolved) { $this->buffering = true; if ($this->coroutine === null) { $this->coroutine = new Coroutine($this->consume()); } if ($this->backpressure) { $backpressure = $this->backpressure; $this->backpressure = null; $backpressure->resolve(); } $this->coroutine->onResolve($onResolved); } /** * Exposes the source input stream. * * This might be required to resolve a promise with an InputStream, because promises in Amp can't be resolved with * other promises. * * @return InputStream */ final public function getInputStream(): InputStream { return $this->source; } } <?php namespace Amp\ByteStream; use Amp\Promise; /** * Allows compression of output streams using Zlib. */ final class ZlibOutputStream implements OutputStream { private $destination; private $encoding; private $options; private $resource; /** * @param OutputStream $destination Output stream to write the compressed data to. * @param int $encoding Compression encoding to use, see `deflate_init()`. * @param array $options Compression options to use, see `deflate_init()`. * * @throws StreamException If an invalid encoding or invalid options have been passed. * * @see http://php.net/manual/en/function.deflate-init.php */ public function __construct(OutputStream $destination, int $encoding, array $options = []) { $this->destination = $destination; $this->encoding = $encoding; $this->options = $options; $this->resource = @\deflate_init($encoding, $options); if ($this->resource === false) { throw new StreamException("Failed initializing deflate context"); } } /** @inheritdoc */ public function write(string $data): Promise { if ($this->resource === null) { throw new ClosedException("The stream has already been closed"); } $compressed = \deflate_add($this->resource, $data, \ZLIB_SYNC_FLUSH); if ($compressed === false) { throw new StreamException("Failed adding data to deflate context"); } $promise = $this->destination->write($compressed); $promise->onResolve(function ($error) { if ($error) { $this->close(); } }); return $promise; } /** @inheritdoc */ public function end(string $finalData = ""): Promise { if ($this->resource === null) { throw new ClosedException("The stream has already been closed"); } $compressed = \deflate_add($this->resource, $finalData, \ZLIB_FINISH); if ($compressed === false) { throw new StreamException("Failed adding data to deflate context"); } $promise = $this->destination->end($compressed); $promise->onResolve(function () { $this->close(); }); return $promise; } /** @internal */ private function close() { $this->resource = null; $this->destination = null; } /** * Gets the used compression encoding. * * @return int Encoding specified on construction time. */ public function getEncoding(): int { return $this->encoding; } /** * Gets the used compression options. * * @return array Options array passed on construction time. */ public function getOptions(): array { return $this->options; } } <?php namespace Amp\ByteStream; use Amp\Promise; use Amp\Success; /** * Input stream with a single already known data chunk. */ final class InMemoryStream implements InputStream { private $contents; /** * @param string|null $contents Data chunk or `null` for no data chunk. */ public function __construct(string $contents = null) { $this->contents = $contents; } /** * Reads data from the stream. * * @return Promise Resolves with the full contents or `null` if the stream has closed / already been consumed. */ public function read(): Promise { if ($this->contents === null) { return new Success; } $promise = new Success($this->contents); $this->contents = null; return $promise; } } <?php namespace Amp\ByteStream; class StreamException extends \Exception { } <?php namespace Amp\ByteStream; use Amp\Coroutine; use Amp\Promise; use function Amp\call; /** * Creates a buffered message from an InputStream. The message can be consumed in chunks using the read() API or it may * be buffered and accessed in its entirety by calling buffer(). Once buffering is requested through buffer(), the * stream cannot be read in chunks. On destruct any remaining data is read from the InputStream given to this class. */ class Payload implements InputStream { /** @var InputStream */ private $stream; /** @var \Amp\Promise|null */ private $promise; /** @var \Amp\Promise|null */ private $lastRead; /** * @param \Amp\ByteStream\InputStream $stream */ public function __construct(InputStream $stream) { $this->stream = $stream; } public function __destruct() { if (!$this->promise) { Promise\rethrow(new Coroutine($this->consume())); } } private function consume(): \Generator { try { if ($this->lastRead && null === yield $this->lastRead) { return; } while (null !== yield $this->stream->read()) { // Discard unread bytes from message. } } catch (\Throwable $exception) { // If exception is thrown here the connection closed anyway. } } /** * @inheritdoc * * @throws \Error If a buffered message was requested by calling buffer(). */ final public function read(): Promise { if ($this->promise) { throw new \Error("Cannot stream message data once a buffered message has been requested"); } return $this->lastRead = $this->stream->read(); } /** * Buffers the entire message and resolves the returned promise then. * * @return Promise<string> Resolves with the entire message contents. */ final public function buffer(): Promise { if ($this->promise) { return $this->promise; } return $this->promise = call(function () { $buffer = ''; if ($this->lastRead && null === yield $this->lastRead) { return $buffer; } while (null !== $chunk = yield $this->stream->read()) { $buffer .= $chunk; } return $buffer; }); } } <?php namespace Amp\ByteStream; use Amp\Deferred; use Amp\Failure; use Amp\Loop; use Amp\Promise; use Amp\Success; /** * Output stream abstraction for PHP's stream resources. */ final class ResourceOutputStream implements OutputStream { const MAX_CONSECUTIVE_EMPTY_WRITES = 3; const LARGE_CHUNK_SIZE = 128 * 1024; /** @var resource */ private $resource; /** @var string */ private $watcher; /** @var \SplQueue */ private $writes; /** @var bool */ private $writable = true; /** @var int|null */ private $chunkSize; /** * @param resource $stream Stream resource. * @param int|null $chunkSize Chunk size per `fwrite()` operation. */ public function __construct($stream, int $chunkSize = null) { if (!\is_resource($stream) || \get_resource_type($stream) !== 'stream') { throw new \Error("Expected a valid stream"); } $meta = \stream_get_meta_data($stream); if (\strpos($meta["mode"], "r") !== false && \strpos($meta["mode"], "+") === false) { throw new \Error("Expected a writable stream"); } \stream_set_blocking($stream, false); \stream_set_write_buffer($stream, 0); $this->resource = $stream; $this->chunkSize = &$chunkSize; $writes = $this->writes = new \SplQueue; $writable = &$this->writable; $resource = &$this->resource; $this->watcher = Loop::onWritable($stream, static function ($watcher, $stream) use ($writes, &$chunkSize, &$writable, &$resource) { static $emptyWrites = 0; try { while (!$writes->isEmpty()) { /** @var \Amp\Deferred $deferred */ list($data, $previous, $deferred) = $writes->shift(); $length = \strlen($data); if ($length === 0) { $deferred->resolve(0); continue; } if (!\is_resource($stream) || (($metaData = @\stream_get_meta_data($stream)) && $metaData['eof'])) { throw new StreamException("The stream was closed by the peer"); } // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. // Use conditional, because PHP doesn't like getting null passed if ($chunkSize) { $written = @\fwrite($stream, $data, $chunkSize); } else { $written = @\fwrite($stream, $data); } \assert($written !== false, "Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); // Broken pipes between processes on macOS/FreeBSD do not detect EOF properly. if ($written === 0) { if ($emptyWrites++ > self::MAX_CONSECUTIVE_EMPTY_WRITES) { $message = "Failed to write to stream after multiple attempts"; if ($error = \error_get_last()) { $message .= \sprintf("; %s", $error["message"]); } throw new StreamException($message); } $writes->unshift([$data, $previous, $deferred]); return; } $emptyWrites = 0; if ($length > $written) { $data = \substr($data, $written); $writes->unshift([$data, $written + $previous, $deferred]); return; } $deferred->resolve($written + $previous); } } catch (\Throwable $exception) { $resource = null; $writable = false; $deferred->fail($exception); while (!$writes->isEmpty()) { list(, , $deferred) = $writes->shift(); $deferred->fail($exception); } Loop::cancel($watcher); } finally { if ($writes->isEmpty()) { Loop::disable($watcher); } } }); Loop::disable($this->watcher); } /** * Writes data to the stream. * * @param string $data Bytes to write. * * @return Promise Succeeds once the data has been successfully written to the stream. * * @throws ClosedException If the stream has already been closed. */ public function write(string $data): Promise { return $this->send($data, false); } /** * Closes the stream after all pending writes have been completed. Optionally writes a final data chunk before. * * @param string $finalData Bytes to write. * * @return Promise Succeeds once the data has been successfully written to the stream. * * @throws ClosedException If the stream has already been closed. */ public function end(string $finalData = ""): Promise { return $this->send($finalData, true); } private function send(string $data, bool $end = false): Promise { if (!$this->writable) { return new Failure(new ClosedException("The stream is not writable")); } $length = \strlen($data); $written = 0; if ($end) { $this->writable = false; } if ($this->writes->isEmpty()) { if ($length === 0) { if ($end) { $this->close(); } return new Success(0); } if (!\is_resource($this->resource) || (($metaData = @\stream_get_meta_data($this->resource)) && $metaData['eof'])) { throw new StreamException("The stream was closed by the peer"); } // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. // Use conditional, because PHP doesn't like getting null passed. if ($this->chunkSize) { $written = @\fwrite($this->resource, $data, $this->chunkSize); } else { $written = @\fwrite($this->resource, $data); } \assert($written !== false, "Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); if ($length === $written) { if ($end) { $this->close(); } return new Success($written); } $data = \substr($data, $written); } $deferred = new Deferred; if ($length - $written > self::LARGE_CHUNK_SIZE) { $chunks = \str_split($data, self::LARGE_CHUNK_SIZE); $data = \array_pop($chunks); foreach ($chunks as $chunk) { $this->writes->push([$chunk, $written, new Deferred]); $written += self::LARGE_CHUNK_SIZE; } } $this->writes->push([$data, $written, $deferred]); Loop::enable($this->watcher); $promise = $deferred->promise(); if ($end) { $promise->onResolve([$this, "close"]); } return $promise; } /** * Closes the stream forcefully. Multiple `close()` calls are ignored. * * @return void */ public function close() { if ($this->resource) { // Error suppression, as resource might already be closed $meta = @\stream_get_meta_data($this->resource); if ($meta && \strpos($meta["mode"], "+") !== false) { @\stream_socket_shutdown($this->resource, \STREAM_SHUT_WR); } else { @\fclose($this->resource); } } $this->free(); } /** * Nulls reference to resource, marks stream unwritable, and fails any pending write. */ private function free() { $this->resource = null; $this->writable = false; if (!$this->writes->isEmpty()) { $exception = new ClosedException("The socket was closed before writing completed"); do { /** @var \Amp\Deferred $deferred */ list(, , $deferred) = $this->writes->shift(); $deferred->fail($exception); } while (!$this->writes->isEmpty()); } Loop::cancel($this->watcher); } /** * @return resource|null Stream resource or null if end() has been called or the stream closed. */ public function getResource() { return $this->resource; } public function setChunkSize(int $chunkSize) { $this->chunkSize = $chunkSize; } public function __destruct() { if ($this->resource !== null) { $this->free(); } } } <?php // basic (and dumb) HTTP server require __DIR__ . '/../vendor/autoload.php'; // This is a very simple HTTP server that just prints a message to each client that connects. // It doesn't check whether the client sent an HTTP request. // You might notice that your browser opens several connections instead of just one, even when only making one request. use Amp\Loop; use Amp\Socket\ServerSocket; use function Amp\asyncCoroutine; Loop::run(function () { $clientHandler = asyncCoroutine(function (ServerSocket $socket) { list($ip, $port) = explode(":", $socket->getRemoteAddress()); echo "Accepted connection from {$ip}:{$port}." . PHP_EOL; $body = "Hey, your IP is {$ip} and your local port used is {$port}."; $bodyLength = \strlen($body); yield $socket->end("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}"); }); $server = Amp\Socket\listen("127.0.0.1:0"); echo "Listening for new connections on " . $server->getAddress() . "..." . PHP_EOL; echo "Open your browser and visit http://" . $server->getAddress() . "/" . PHP_EOL; while ($socket = yield $server->accept()) { $clientHandler($socket); } }); <?php // basic (and dumb) HTTP client require __DIR__ . '/../vendor/autoload.php'; // This is a very simple HTTP client that just prints the response without parsing. use Amp\ByteStream\ResourceOutputStream; use Amp\Loop; use Amp\Socket\Socket; use Amp\Uri\Uri; use function Amp\Socket\connect; use function Amp\Socket\cryptoConnect; Loop::run(function () use ($argv) { $stdout = new ResourceOutputStream(STDOUT); if (count($argv) !== 2) { yield $stdout->write("Usage: examples/simple-http-client.php url" . PHP_EOL); exit(1); } $uri = new Uri($argv[1]); $host = $uri->getHost(); if ($uri->getScheme() === "https") { /** @var Socket $socket */ $socket = yield cryptoConnect("tcp://" . $host . ":" . $uri->getPort()); } else { /** @var Socket $socket */ $socket = yield connect("tcp://" . $host . ":" . $uri->getPort()); } yield $socket->write("GET {$uri} HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n"); while (null !== $chunk = yield $socket->read()) { yield $stdout->write($chunk); } // If the promise returned from `read()` resolves to `null`, the socket closed and we're done. // In this case you can also use `yield Amp\ByteStream\pipe($socket, $stdout)` instead of the while loop, // but we want to demonstate the `read()` method here. }); { "name": "amphp/socket", "homepage": "https://github.com/amphp/socket", "description": "Async socket connection / server tools for Amp.", "support": { "issues": "https://github.com/amphp/socket/issues" }, "keywords": [ "tcp", "sockets", "tls", "encryption", "async", "non-blocking", "amp" ], "license": "MIT", "authors": [ { "name": "Daniel Lowrey", "email": "rdlowrey@gmail.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "require": { "php": ">=7.0", "amphp/amp": "^2", "amphp/dns": "^0.9", "amphp/byte-stream": "^1.1", "amphp/uri": "^0.1" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "friendsofphp/php-cs-fixer": "^2.3" }, "autoload": { "psr-4": { "Amp\\Socket\\": "src" }, "files": [ "src/functions.php", "src/Internal/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Socket\\Test\\": "test" } }, "config": { "platform": { "php": "7.0.0" } }, "scripts": { "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit", "code-style": "@php ./vendor/bin/php-cs-fixer fix" } } <?php namespace Amp\Socket\Test\Internal; use Amp\Socket\Internal; use PHPUnit\Framework\TestCase; class functionsTest extends TestCase { public function parseUriDataProvider() { return [ [ 'unix:///tmp/test', ['unix', 'tmp/test', 0], ], [ 'udg://test', ['udg', 'test', 0], ], [ 'tcp://test:1234', ['tcp', 'test', 1234], ], [ 'udp://host:4321', ['udp', 'host', 4321], ], [ 'tcp://[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443', ['tcp', '[2001:db8:85a3:8d3:1319:8a2e:370:7348]', 443], ], ]; } /** * @dataProvider parseUriDataProvider */ public function testParseUri($uri, $expected) { $this->assertEquals($expected, Internal\parseUri($uri)); } public function parseUriInvalidUriDataProvider() { return [ ['///////'], ]; } /** * @dataProvider parseUriInvalidUriDataProvider * @expectedException \Error * @expectedExceptionMessage Invalid URI: */ public function testParseUriInvalidUri($uri) { Internal\parseUri($uri); } public function parseUriInvalidSchemeDataProvider() { return [ ['http://example.com'], ['https://example.com'], ['xml://example.com'], ]; } /** * @dataProvider parseUriInvalidSchemeDataProvider * @expectedException \Error * @expectedExceptionMessageRegExp "Invalid URI scheme (.*); tcp, udp, unix or udg scheme expected" */ public function testParseUriInvalidScheme($uri) { Internal\parseUri($uri); } public function normalizeBindToOptionDataProvider() { return [ [null, null], ['127.0.0.1', '127.0.0.1:0'], ['127.0.0.1:0', '127.0.0.1:0'], ['123.123.123.123:1234', '123.123.123.123:1234'], ['[::1]', '[::1]:0'], ['[a:b::c]', '[a:b::c]:0'], ['[1:2::3]:4', '[1:2::3]:4'], ['[0000:abcd:0000:abcd:0000:abcd:0127:2258]:4567', '[0000:abcd:0000:abcd:0000:abcd:0127:2258]:4567'], ]; } /** * @dataProvider normalizeBindToOptionDataProvider */ public function testNormalizeBindToOption($bindTo, $expected) { $actual = Internal\normalizeBindToOption($bindTo); $this->assertSame($expected, $actual); } public function normalizeBindToOptionInvalidBindToDataProvider() { return [ ['-1.-1.-1.-1'], ['a.b.c.d'], ['123.123.123.123:-0'], ['123.123.123.123:-1234567'], ['[0000:abcd:0000:abcd:0000:abcd:0127:2258]:-67899'], ['[e:f:g:h]'], ]; } /** * @dataProvider normalizeBindToOptionInvalidBindToDataProvider * @expectedException \Error * @expectedExceptionMessage Invalid bindTo value: */ public function testNormalizeBindToOptionInvalidBindTo($bindTo) { Internal\normalizeBindToOption($bindTo); } public function normalizeBindToOptionInvalidPortDataProvider() { return [ ['123.123.123.123:123456'], ['[0000:abcd:0000:abcd:0000:abcd:0127:2258]:67899'], ]; } /** * @dataProvider normalizeBindToOptionInvalidPortDataProvider * @expectedException \Error * @expectedExceptionMessage Invalid port: */ public function testNormalizeBindToOptionInvalidPort($bindTo) { Internal\normalizeBindToOption($bindTo); } public function normalizeBindToOptionInvalidIpv6DataProvider() { return [ ['[::::]'], ['[:::1]'], ]; } /** * @dataProvider normalizeBindToOptionInvalidIpv6DataProvider * @expectedException \Error * @expectedExceptionMessage Invalid IPv6 address: */ public function testNormalizeBindToOptionInvalidIpv6($bindTo) { Internal\normalizeBindToOption($bindTo); } public function normalizeBindToOptionInvalidIpv4DataProvider() { return [ ['256.256.256.256'], ['1234.12.12.12'], ]; } /** * @dataProvider normalizeBindToOptionInvalidIpv4DataProvider * @expectedException \Error * @expectedExceptionMessage Invalid IPv4 address: */ public function testNormalizeBindToOptionInvalidIpv4($bindTo) { Internal\normalizeBindToOption($bindTo); } } <?php namespace Amp\Socket\Test; use Amp\ByteStream; use Amp\Delayed; use Amp\Loop; use Amp\PHPUnit\TestCase; use Amp\Socket; use function Amp\asyncCall; class TlsFragmentationTest extends TestCase { public function testTls() { Loop::run(function () { $proxyServer = Socket\listen("127.0.0.1:0"); $tlsContext = (new Socket\ServerTlsContext) ->withDefaultCertificate(new Socket\Certificate(__DIR__ . "/tls/amphp.org.pem")); $server = Socket\listen("127.0.0.1:0", null, $tlsContext); // Proxy to apply chunking of single bytes asyncCall(function () use ($proxyServer, $server) { /** @var Socket\ServerSocket $proxyClient */ while ($proxyClient = yield $proxyServer->accept()) { asyncCall(function () use ($proxyClient, $server) { $proxyUpstream = yield Socket\connect($server->getAddress()); $this->pipe($proxyClient, $proxyUpstream); $this->pipe($proxyUpstream, $proxyClient); }); } }); asyncCall(function () use ($server) { /** @var Socket\ServerSocket $client */ while ($client = yield $server->accept()) { asyncCall(function () use ($client) { yield $client->enableCrypto(); $this->assertInstanceOf(Socket\ServerSocket::class, $client); $this->assertSame("Hello World", yield from $this->read($client, 11)); $client->write("test"); }); } }); $context = (new Socket\ClientTlsContext) ->withPeerName("amphp.org") ->withCaFile(__DIR__ . "/tls/amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($proxyServer->getAddress(), null, $context); yield $client->write("Hello World"); $this->assertSame("test", yield from $this->read($client, 4)); $server->close(); Loop::stop(); }); } private function pipe(ByteStream\InputStream $source, ByteStream\OutputStream $destination) { asyncCall(function () use ($source, $destination): \Generator { while (($chunk = yield $source->read()) !== null) { foreach (\str_split($chunk, 1) as $byte) { yield $destination->write($byte); yield new Delayed(1); } } }); } private function read(ByteStream\InputStream $source, int $minLength) { $buffer = ""; while (null !== $chunk = yield $source->read()) { $buffer .= $chunk; if (\strlen($buffer) >= $minLength) { return $buffer; } } throw new \RuntimeException("Stream ended prior to {$minLength} bytes being read."); } } <?php namespace Amp\Socket\Test; use Amp\Socket; use PHPUnit\Framework\TestCase; class functionsTest extends TestCase { /** * @expectedException \Error * @expectedExceptionMessage Only tcp, udp, unix and udg schemes allowed for server creation */ public function testListenInvalidScheme() { Socket\listen("invalid://127.0.0.1:0"); } /** * @expectedException \Amp\Socket\SocketException * @expectedExceptionMessageRegExp /Could not create server .*: \[Error: #.*\] .*$/ */ public function testListenStreamSocketServerError() { Socket\listen('error'); } public function testListenIPv6() { try { $socket = Socket\listen('[::1]:0'); $this->assertRegExp('(\[::1\]:\d+)', $socket->getAddress()); } catch (Socket\SocketException $e) { if ($e->getMessage() === 'Could not create server [::1]:0: [Error: #0] Cannot assign requested address') { $this->markTestSkipped('Missing IPv6 support'); } throw $e; } } } <?php namespace Amp\Socket\Test; use Amp\Socket\PendingAcceptError; use PHPUnit\Framework\TestCase; class PendingAcceptErrorTest extends TestCase { public function constructorParametersProvider() { $exception = new \Exception('test'); return [ [ null, [ 'The previous accept operation must complete before accept can be called again', 0, null ] ], [ ['message', 1, $exception], [ 'message', 1, $exception ] ], ]; } /** * @param $params * @param $expectedValues * * @dataProvider constructorParametersProvider */ public function testConstruct($params, $expectedValues) { $error = $params ? new PendingAcceptError(...$params) : new PendingAcceptError(); $this->assertSame($expectedValues, [$error->getMessage(), $error->getCode(), $error->getPrevious()]); } } <?php namespace Amp\Socket\Test; use Amp\Loop; use Amp\Socket; use PHPUnit\Framework\TestCase; use function Amp\asyncCall; use function Amp\Promise\wait; class SocketTest extends TestCase { public function testReadAndClose() { Loop::run(function () { $data = "Testing\n"; list($serverSock, $clientSock) = Socket\pair(); \fwrite($serverSock, $data); \fclose($serverSock); $client = new Socket\ClientSocket($clientSock); while (($chunk = yield $client->read()) !== null) { $this->assertSame($data, $chunk); } }); } public function testSocketAddress() { @unlink(__DIR__ . '/socket.sock'); $s = stream_socket_server('unix://' . __DIR__ . '/socket.sock'); $c = stream_socket_client('unix://' . __DIR__ . '/socket.sock'); $clientSocket = new Socket\ClientSocket($c); $serverSocket = new Socket\ServerSocket($s); $this->assertNotNull($clientSocket->getRemoteAddress()); $this->assertSame(__DIR__ . '/socket.sock', $clientSocket->getLocalAddress()); $this->assertSame($clientSocket->getRemoteAddress(), $clientSocket->getLocalAddress()); $this->assertSame($serverSocket->getRemoteAddress(), $serverSocket->getLocalAddress()); $this->assertSame($serverSocket->getRemoteAddress(), $clientSocket->getLocalAddress()); } public function testEnableCryptoWithoutTlsContext() { $server = Socket\listen('127.0.0.1:0'); asyncCall(function () use ($server) { yield Socket\connect($server->getAddress()); }); /** @var Socket\ServerSocket $client */ $client = wait($server->accept()); $this->expectException(Socket\CryptoException::class); $this->expectExceptionMessage("Can't enable TLS without configuration."); wait($client->enableCrypto()); } } <?php namespace Amp\Socket\Test; use Amp\Socket\ServerListenContext; use PHPUnit\Framework\TestCase; class ServerListenContextTest extends TestCase { public function bindToDataProvider() { return [ [null], ['127.0.0.1:123'], ]; } /** * @dataProvider bindToDataProvider */ public function testWithBindTo($bindTo) { $origContext = new ServerListenContext(); $clonedContext = $origContext->withBindTo($bindTo); $this->assertNull($origContext->getBindTo()); $this->assertSame($bindTo, $clonedContext->getBindTo()); } public function testWithTcpNoDelay() { $context = new ServerListenContext(); $clonedContext = $context->withTcpNoDelay(); $this->assertFalse($context->hasTcpNoDelay()); $this->assertTrue($clonedContext->hasTcpNoDelay()); } public function backlogDataProvider() { return [ [10], [123], ]; } /** * @dataProvider backlogDataProvider */ public function testWithBacklog($backlog) { $origContext = new ServerListenContext(); $clonedContext = $origContext->withBacklog($backlog); $this->assertSame(128, $origContext->getBacklog()); $this->assertSame($backlog, $clonedContext->getBacklog()); } public function testWithReusePort() { $origContext = new ServerListenContext(); $clonedContext = $origContext->withReusePort(); $this->assertFalse($origContext->hasReusePort()); $this->assertTrue($clonedContext->hasReusePort()); } public function testWithoutReusePort() { $origContext = new ServerListenContext(); $clonedContext = $origContext->withoutReusePort(); $this->assertFalse($origContext->hasReusePort()); $this->assertFalse($clonedContext->hasReusePort()); } public function testWithBroadcast() { $origContext = new ServerListenContext(); $clonedContext = $origContext->withBroadcast(); $this->assertFalse($origContext->hasBroadcast()); $this->assertTrue($clonedContext->hasBroadcast()); } public function testWithoutBroadcast() { $origContext = new ServerListenContext(); $clonedContext = $origContext->withoutBroadcast(); $this->assertFalse($origContext->hasBroadcast()); $this->assertFalse($clonedContext->hasBroadcast()); } } <?php namespace Amp\Socket\Test; use Amp\Socket\Certificate; use Amp\Socket\ServerTlsContext; use PHPUnit\Framework\TestCase; class ServerTlsContextTest extends TestCase { public function minimumVersionDataProvider() { return [ [ServerTlsContext::TLSv1_0], [ServerTlsContext::TLSv1_1], [ServerTlsContext::TLSv1_2], ]; } /** * @dataProvider minimumVersionDataProvider */ public function testWithMinimumVersion($version) { $context = new ServerTlsContext; $clonedContext = $context->withMinimumVersion($version); $this->assertSame(ServerTlsContext::TLSv1_0, $context->getMinimumVersion()); $this->assertSame($version, $clonedContext->getMinimumVersion()); } public function minimumVersionInvalidDataProvider() { return [ [-1], ]; } /** * @dataProvider minimumVersionInvalidDataProvider * @expectedException \Error * @expectedExceptionMessage Invalid minimum version, only TLSv1.0, TLSv1.1 or TLSv1.2 allowed */ public function testWithMinimumVersionInvalid($version) { (new ServerTlsContext)->withMinimumVersion($version); } public function peerNameDataProvider() { return [ [null], ['test'], ]; } /** * @dataProvider peerNameDataProvider */ public function testWithPeerName($peerName) { $context = new ServerTlsContext; $clonedContext = $context->withPeerName($peerName); $this->assertNull($context->getPeerName()); $this->assertSame($peerName, $clonedContext->getPeerName()); } public function testWithPeerVerification() { $context = new ServerTlsContext; $clonedContext = $context->withPeerVerification(); $this->assertFalse($context->hasPeerVerification()); $this->assertTrue($clonedContext->hasPeerVerification()); } public function testWithoutPeerVerification() { $context = new ServerTlsContext; $clonedContext = $context->withoutPeerVerification(); $this->assertFalse($context->hasPeerVerification()); $this->assertFalse($clonedContext->hasPeerVerification()); } public function verifyDepthDataProvider() { return [ [0], [123], ]; } /** * @dataProvider verifyDepthDataProvider */ public function testWithVerificationDepth($verifyDepth) { $context = new ServerTlsContext; $clonedContext = $context->withVerificationDepth($verifyDepth); $this->assertSame(10, $context->getVerificationDepth()); $this->assertSame($verifyDepth, $clonedContext->getVerificationDepth()); } public function verifyDepthInvalidDataProvider() { return [ [-1], [-123], ]; } /** * @dataProvider verifyDepthInvalidDataProvider * @expectedException \Error * @expectedExceptionMessageRegExp /Invalid verification depth (.*), must be greater than or equal to 0/ */ public function testWithVerificationDepthInvalid($verifyDepth) { (new ServerTlsContext)->withVerificationDepth($verifyDepth); } public function ciphersDataProvider() { return [ ['ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256'], ['DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256'], ]; } /** * @dataProvider ciphersDataProvider */ public function testWithCiphers($ciphers) { $context = new ServerTlsContext; $clonedContext = $context->withCiphers($ciphers); $this->assertSame(\OPENSSL_DEFAULT_STREAM_CIPHERS, $context->getCiphers()); $this->assertSame($ciphers, $clonedContext->getCiphers()); } public function caFileDataProvider() { return [ [null], ['test'], ]; } /** * @dataProvider caFileDataProvider */ public function testWithCaFile($caFile) { $context = new ServerTlsContext; $clonedContext = $context->withCaFile($caFile); $this->assertNull($context->getCaFile()); $this->assertSame($caFile, $clonedContext->getCaFile()); } public function caPathDataProvider() { return [ [null], ['test'], ]; } /** * @dataProvider caPathDataProvider */ public function testWithCaPath($caPath) { $context = new ServerTlsContext; $clonedContext = $context->withCaPath($caPath); $this->assertNull($context->getCaPath()); $this->assertSame($caPath, $clonedContext->getCaPath()); } public function testWithPeerCapturing() { $context = new ServerTlsContext; $clonedContext = $context->withPeerCapturing(); $this->assertFalse($context->hasPeerCapturing()); $this->assertTrue($clonedContext->hasPeerCapturing()); } public function testWithoutPeerCapturing() { $context = new ServerTlsContext; $clonedContext = $context->withoutPeerCapturing(); $this->assertFalse($context->hasPeerCapturing()); $this->assertFalse($clonedContext->hasPeerCapturing()); } public function defaultCertificateDataProvider() { return [ [null], [new Certificate('test')], ]; } /** * @dataProvider defaultCertificateDataProvider */ public function testWithDefaultCertificate($defaultCertificate) { $context = new ServerTlsContext; $clonedContext = $context->withDefaultCertificate($defaultCertificate); $this->assertNull($context->getDefaultCertificate()); $this->assertSame($defaultCertificate, $clonedContext->getDefaultCertificate()); } public function testWithCertificatesErrorWithoutStringKeys() { $this->expectException(\TypeError::class); $this->expectExceptionMessage("Expected an array mapping domain names to Certificate instances"); (new ServerTlsContext)->withCertificates([new Certificate("/foo/bar")]); } public function testWithCertificatesErrorWithoutCertificateInstances() { $this->expectException(\TypeError::class); $this->expectExceptionMessage("Expected an array of Certificate instances"); (new ServerTlsContext)->withCertificates(["example.com" => "/foo/bar"]); } public function testWithCertificatesWithDifferentPathsBeforePhp72() { if (\PHP_VERSION_ID >= 70200) { $this->markTestSkipped("Only relevant in versions lower to PHP 7.2"); } $this->expectException(\Error::class); $this->expectExceptionMessage("Different files for cert and key are not supported on this version of PHP. Please upgrade to PHP 7.2 or later."); (new ServerTlsContext)->withCertificates(["example.com" => new Certificate("/var/foo", "/foo/bar")]); } public function invalidSecurityLevelDataProvider() { return [ [-1], [6], ]; } /** * @dataProvider invalidSecurityLevelDataProvider */ public function testWithSecurityLevelInvalid($level) { $this->expectException(\Error::class); $this->expectExceptionMessage("Invalid security level ({$level}), must be between 0 and 5."); (new ServerTlsContext)->withSecurityLevel($level); } public function validSecurityLevelDataProvider() { return [ [0], [1], [2], [3], [4], [5], ]; } /** * @dataProvider validSecurityLevelDataProvider */ public function testWithSecurityLevelValid($level) { if (\OPENSSL_VERSION_NUMBER >= 0x10100000) { $value = (new ServerTlsContext) ->withSecurityLevel($level) ->getSecurityLevel(); $this->assertSame($level, $value); } else { $this->expectException(\Error::class); $this->expectExceptionMessage("Can't set a security level, as PHP is compiled with OpenSSL < 1.1.0."); (new ServerTlsContext)->withSecurityLevel($level); } } public function testWithSecurityLevelDefaultValue() { if (\OPENSSL_VERSION_NUMBER >= 0x10100000) { $this->assertSame(2, (new ServerTlsContext)->getSecurityLevel()); } else { $this->assertSame(0, (new ServerTlsContext)->getSecurityLevel()); } } } <?php namespace Amp\Socket\Test; use Amp\Dns\Record; use Amp\Socket\ClientConnectContext; use PHPUnit\Framework\TestCase; class ClientConnectContextTest extends TestCase { public function bindToDataProvider() { return [ [null], ['127.0.0.1:12345'] ]; } /** * @dataProvider bindToDataProvider */ public function testWithBindTo($bindTo) { $context = new ClientConnectContext(); $clonedContext = $context->withBindTo($bindTo); $this->assertNull($context->getBindTo()); $this->assertSame($bindTo, $clonedContext->getBindTo()); } public function testWithTcpNoDelay() { $context = new ClientConnectContext(); $clonedContext = $context->withTcpNoDelay(); $this->assertFalse($context->hasTcpNoDelay()); $this->assertTrue($clonedContext->hasTcpNoDelay()); } public function withConnectTimeoutDataProvider() { return [ [1], [12345] ]; } /** * @dataProvider withConnectTimeoutDataProvider */ public function testWithConnectTimeout($timeout) { $context = new ClientConnectContext(); $clonedContext = $context->withConnectTimeout($timeout); $this->assertSame(10000, $context->getConnectTimeout()); $this->assertSame($timeout, $clonedContext->getConnectTimeout()); } public function withConnectTimeoutInvalidTimeoutDataProvider() { return [ [0], [-1], [-123456] ]; } /** * @dataProvider withConnectTimeoutInvalidTimeoutDataProvider */ public function testWithConnectTimeoutInvalidTimeout($timeout) { $this->expectException(\Error::class); $this->expectExceptionMessage("Invalid connect timeout ({$timeout}), must be greater than 0"); $context = new ClientConnectContext(); $context->withConnectTimeout($timeout); } public function withMaxAttemptsDataProvider() { return [ [1], [12345] ]; } /** * @dataProvider withMaxAttemptsDataProvider */ public function testWithMaxAttempts($maxAttempts) { $context = new ClientConnectContext(); $clonedContext = $context->withMaxAttempts($maxAttempts); $this->assertSame(2, $context->getMaxAttempts()); $this->assertSame($maxAttempts, $clonedContext->getMaxAttempts()); } public function withMaxAttemptsInvalidTimeoutDataProvider() { return [ [0], [-1], [-123456] ]; } /** * @dataProvider withMaxAttemptsInvalidTimeoutDataProvider */ public function testWithMaxAttemptsInvalidTimeout($maxAttempts) { $this->expectException(\Error::class); $this->expectExceptionMessage("Invalid max attempts ({$maxAttempts}), must be greater than 0"); $context = new ClientConnectContext(); $context->withMaxAttempts($maxAttempts); } public function withDnsTypeRestrictionDataProvider() { return [ [null], [Record::AAAA], [Record::A] ]; } /** * @dataProvider withDnsTypeRestrictionDataProvider */ public function testWithDnsTypeRestriction($type) { $context = new ClientConnectContext(); $clonedContext = $context->withDnsTypeRestriction($type); $this->assertNull($context->getDnsTypeRestriction()); $this->assertSame($type, $clonedContext->getDnsTypeRestriction()); } public function withDnsTypeRestrictionInvalidTypeDataProvider() { return [ [Record::NS], [Record::MX], ]; } /** * @dataProvider withDnsTypeRestrictionInvalidTypeDataProvider * @expectedException \Error * @expectedExceptionMessage Invalid resolver type restriction */ public function testWithDnsTypeRestrictionInvalidType($type) { $context = new ClientConnectContext(); $context->withDnsTypeRestriction($type); } public function testToStreamContextArray() { $context = new ClientConnectContext(); $clonedContext = $context->withBindTo('127.0.0.1:12345'); $this->assertSame(['socket' => ['tcp_nodelay' => false]], $context->toStreamContextArray()); $this->assertSame(['socket' => [ 'tcp_nodelay' => false, 'bindto' => '127.0.0.1:12345', ]], $clonedContext->toStreamContextArray()); } } <?php namespace Amp\Socket\Test; use Amp\CancelledException; use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientSocket; use Amp\Socket\ClientTlsContext; use Amp\Socket\ConnectException; use Amp\TimeoutCancellationToken; use PHPUnit\Framework\TestCase; class IntegrationTest extends TestCase { /** * @dataProvider provideConnectArgs */ public function testConnect($uri) { $promise = \Amp\Socket\connect($uri); $sock = \Amp\Promise\wait($promise); $this->assertInstanceOf(ClientSocket::class, $sock); } public function provideConnectArgs() { return [ ['www.google.com:80'], ['www.yahoo.com:80'], ]; } public function testConnectFailure() { $this->expectException(ConnectException::class); $promise = \Amp\Socket\connect('8.8.8.8:80', (new ClientConnectContext)->withConnectTimeout(1000)); $sock = \Amp\Promise\wait($promise); } /** * @depends testConnectFailure */ public function testConnectCancellation() { $this->expectException(CancelledException::class); $token = new TimeoutCancellationToken(1000); $promise = \Amp\Socket\connect('8.8.8.8:80', (new ClientConnectContext)->withConnectTimeout(2000), $token); $sock = \Amp\Promise\wait($promise); } /** * @dataProvider provideCryptoConnectArgs */ public function testCryptoConnect($uri) { $promise = \Amp\Socket\cryptoConnect($uri); $sock = \Amp\Promise\wait($promise); $this->assertInstanceOf(ClientSocket::class, $sock); } public function provideCryptoConnectArgs() { return [ ['stackoverflow.com:443'], ['github.com:443'], ['raw.githubusercontent.com:443'], ]; } public function testNoRenegotiationForEqualOptions() { $promise = \Amp\socket\cryptoConnect('www.google.com:443'); /** @var ClientSocket $sock */ $socket = \Amp\Promise\wait($promise); // For this case renegotiation not needed because options is equals $promise = $socket->enableCrypto((new ClientTlsContext)->withPeerName("www.google.com")); $this->assertNull(\Amp\Promise\wait($promise)); } public function testRenegotiation() { $this->markTestSkipped("Expected failure: proper renegotiation does not work yet"); $promise = \Amp\Socket\cryptoConnect('www.google.com:443', null, (new ClientTlsContext)->withPeerName("www.google.com")); $sock = \Amp\Promise\wait($promise); // force renegotiation by different option... $promise = $sock->enableCrypto((new ClientTlsContext)->withoutPeerVerification()); \Amp\Promise\wait($promise); $this->assertInstanceOf(ClientSocket::class, $sock); } } <?php namespace Amp\Socket\Test; use Amp\PHPUnit\TestCase; use Amp\Socket\ClientSocket; use Amp\Socket\SocketPool; use Amp\Socket\StaticSocketPool; class StaticSocketPoolTest extends TestCase { public function testCheckout() { $underlyingSocketPool = $this->prophesize(SocketPool::class); $staticSocketPool = new StaticSocketPool('override-uri', $underlyingSocketPool->reveal()); $expected = new \Amp\LazyPromise(function () {}); $underlyingSocketPool->checkout('override-uri', null)->shouldBeCalled()->willReturn($expected); $returned = $staticSocketPool->checkout('test-url'); self::assertEquals($expected, $returned); } public function testCheckin() { $underlyingSocketPool = $this->prophesize(SocketPool::class); $staticSocketPool = new StaticSocketPool('override-uri', $underlyingSocketPool->reveal()); $clientSocket = new ClientSocket(fopen('php://memory', 'rw+')); $underlyingSocketPool->checkin($clientSocket)->shouldBeCalled(); $staticSocketPool->checkin($clientSocket); } public function testClear() { $underlyingSocketPool = $this->prophesize(SocketPool::class); $staticSocketPool = new StaticSocketPool('override-uri', $underlyingSocketPool->reveal()); $clientSocket = new ClientSocket(fopen('php://memory', 'rw+')); $underlyingSocketPool->clear($clientSocket)->shouldBeCalled(); $staticSocketPool->clear($clientSocket); } } <?php namespace Amp\Socket\Test; use Amp\Socket\Certificate; use Amp\Socket\ClientTlsContext; use PHPUnit\Framework\TestCase; class ClientTlsContextTest extends TestCase { public function minimumVersionDataProvider() { return [ [ClientTlsContext::TLSv1_0], [ClientTlsContext::TLSv1_1], [ClientTlsContext::TLSv1_2], ]; } /** * @dataProvider minimumVersionDataProvider */ public function testWithMinimumVersion($version) { $context = new ClientTlsContext; $clonedContext = $context->withMinimumVersion($version); $this->assertSame(ClientTlsContext::TLSv1_0, $context->getMinimumVersion()); $this->assertSame($version, $clonedContext->getMinimumVersion()); } public function minimumVersionInvalidDataProvider() { return [ [-1], ]; } /** * @dataProvider minimumVersionInvalidDataProvider * @expectedException \Error * @expectedExceptionMessage Invalid minimum version, only TLSv1.0, TLSv1.1 or TLSv1.2 allowed */ public function testWithMinimumVersionInvalid($version) { (new ClientTlsContext)->withMinimumVersion($version); } public function peerNameDataProvider() { return [ [null], ['test'], ]; } /** * @dataProvider peerNameDataProvider */ public function testWithPeerName($peerName) { $context = new ClientTlsContext; $clonedContext = $context->withPeerName($peerName); $this->assertNull($context->getPeerName()); $this->assertSame($peerName, $clonedContext->getPeerName()); } public function testWithPeerVerification() { $context = new ClientTlsContext; $clonedContext = $context->withPeerVerification(); $this->assertTrue($context->hasPeerVerification()); $this->assertTrue($clonedContext->hasPeerVerification()); } public function testWithoutPeerVerification() { $context = new ClientTlsContext; $clonedContext = $context->withoutPeerVerification(); $this->assertTrue($context->hasPeerVerification()); $this->assertFalse($clonedContext->hasPeerVerification()); } public function certificateDataProvider() { return [ [null], [new Certificate('cert.pem')], ]; } /** * @dataProvider certificateDataProvider */ public function testWithCertificate($certificate) { $context = new ClientTlsContext; $clonedContext = $context->withCertificate($certificate); $this->assertNull($context->getCertificate()); $this->assertSame($certificate, $clonedContext->getCertificate()); } public function verifyDepthDataProvider() { return [ [0], [123], ]; } /** * @dataProvider verifyDepthDataProvider */ public function testWithVerificationDepth($verifyDepth) { $context = new ClientTlsContext; $clonedContext = $context->withVerificationDepth($verifyDepth); $this->assertSame(10, $context->getVerificationDepth()); $this->assertSame($verifyDepth, $clonedContext->getVerificationDepth()); } public function verifyDepthInvalidDataProvider() { return [ [-1], [-123], ]; } /** * @dataProvider verifyDepthInvalidDataProvider * @expectedException \Error * @expectedExceptionMessageRegExp /Invalid verification depth (.*), must be greater than or equal to 0/ */ public function testWithVerificationDepthInvalid($verifyDepth) { (new ClientTlsContext)->withVerificationDepth($verifyDepth); } public function ciphersDataProvider() { return [ ['ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256'], ['DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256'], ]; } /** * @dataProvider ciphersDataProvider */ public function testWithCiphers($ciphers) { $context = new ClientTlsContext; $clonedContext = $context->withCiphers($ciphers); $this->assertSame(\OPENSSL_DEFAULT_STREAM_CIPHERS, $context->getCiphers()); $this->assertSame($ciphers, $clonedContext->getCiphers()); } public function caFileDataProvider() { return [ [null], ['test'], ]; } /** * @dataProvider caFileDataProvider */ public function testWithCaFile($caFile) { $context = new ClientTlsContext; $clonedContext = $context->withCaFile($caFile); $this->assertNull($context->getCaFile()); $this->assertSame($caFile, $clonedContext->getCaFile()); } public function caPathDataProvider() { return [ [null], ['test'], ]; } /** * @dataProvider caPathDataProvider */ public function testWithCaPath($caPath) { $context = new ClientTlsContext; $clonedContext = $context->withCaPath($caPath); $this->assertNull($context->getCaPath()); $this->assertSame($caPath, $clonedContext->getCaPath()); } public function testWithPeerCapturing() { $context = new ClientTlsContext; $clonedContext = $context->withPeerCapturing(); $this->assertFalse($context->hasPeerCapturing()); $this->assertTrue($clonedContext->hasPeerCapturing()); } public function testWithoutPeerCapturing() { $context = new ClientTlsContext; $clonedContext = $context->withoutPeerCapturing(); $this->assertFalse($context->hasPeerCapturing()); $this->assertFalse($clonedContext->hasPeerCapturing()); } public function testWithSni() { $context = new ClientTlsContext; $clonedContext = $context->withSni(); $this->assertTrue($context->hasSni()); $this->assertTrue($clonedContext->hasSni()); } public function testWithoutSni() { $context = new ClientTlsContext; $clonedContext = $context->withoutSni(); $this->assertTrue($context->hasSni()); $this->assertFalse($clonedContext->hasSni()); } public function invalidSecurityLevelDataProvider() { return [ [-1], [6], ]; } /** * @dataProvider invalidSecurityLevelDataProvider */ public function testWithSecurityLevelInvalid($level) { $this->expectException(\Error::class); $this->expectExceptionMessage("Invalid security level ({$level}), must be between 0 and 5."); (new ClientTlsContext)->withSecurityLevel($level); } public function validSecurityLevelDataProvider() { return [ [0], [1], [2], [3], [4], [5], ]; } /** * @dataProvider validSecurityLevelDataProvider */ public function testWithSecurityLevelValid($level) { if (\OPENSSL_VERSION_NUMBER >= 0x10100000) { $value = (new ClientTlsContext) ->withSecurityLevel($level) ->getSecurityLevel(); $this->assertSame($level, $value); } else { $this->expectException(\Error::class); $this->expectExceptionMessage("Can't set a security level, as PHP is compiled with OpenSSL < 1.1.0."); (new ClientTlsContext)->withSecurityLevel($level); } } public function testWithSecurityLevelDefaultValue() { if (\OPENSSL_VERSION_NUMBER >= 0x10100000) { $this->assertSame(2, (new ClientTlsContext)->getSecurityLevel()); } else { $this->assertSame(0, (new ClientTlsContext)->getSecurityLevel()); } } public function testStreamContextArray() { $context = (new ClientTlsContext) ->withCaPath("/var/foobar"); $contextArray = $context->toStreamContextArray(); unset($contextArray['ssl']['security_level']); // present depending on OpenSSL version $this->assertSame(["ssl" => [ "crypto_method" => $context->toStreamCryptoMethod(), "peer_name" => $context->getPeerName(), "verify_peer" => $context->hasPeerVerification(), "verify_peer_name" => $context->hasPeerVerification(), "verify_depth" => $context->getVerificationDepth(), "ciphers" => $context->getCiphers(), "capture_peer_cert" => $context->hasPeerCapturing(), "capture_peer_cert_chain" => $context->hasPeerCapturing(), "SNI_enabled" => $context->hasSni(), "capath" => $context->getCaPath(), ]], $contextArray); } } <?php namespace Amp\Socket\Test; use Amp\Delayed; use Amp\Loop; use Amp\Socket; use PHPUnit\Framework\TestCase; use function Amp\asyncCall; class ServerTest extends TestCase { public function testAccept() { Loop::run(function () { $server = Socket\listen("127.0.0.1:0"); asyncCall(function () use ($server) { while ($socket = yield $server->accept()) { $this->assertInstanceOf(Socket\ServerSocket::class, $socket); } }); yield Socket\connect($server->getAddress()); Loop::delay(100, [$server, 'close']); }); } public function testTls() { Loop::run(function () { $tlsContext = (new Socket\ServerTlsContext) ->withDefaultCertificate(new Socket\Certificate(__DIR__ . "/tls/amphp.org.pem")); $server = Socket\listen("127.0.0.1:0", null, $tlsContext); asyncCall(function () use ($server) { /** @var Socket\ServerSocket $socket */ while ($socket = yield $server->accept()) { asyncCall(function () use ($socket) { yield $socket->enableCrypto(); $this->assertInstanceOf(Socket\ServerSocket::class, $socket); $this->assertSame("Hello World", yield $socket->read()); $socket->write("test"); }); } }); $context = (new Socket\ClientTlsContext) ->withPeerName("amphp.org") ->withCaFile(__DIR__ . "/tls/amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($server->getAddress(), null, $context); yield $client->write("Hello World"); $this->assertSame("test", yield $client->read()); $server->close(); Loop::stop(); }); } public function testSniWorksWithCorrectHostName() { Loop::run(function () { $tlsContext = (new Socket\ServerTlsContext) ->withCertificates(["amphp.org" => new Socket\Certificate(__DIR__ . "/tls/amphp.org.pem")]); $server = Socket\listen("127.0.0.1:0", null, $tlsContext); asyncCall(function () use ($server) { /** @var Socket\ServerSocket $socket */ while ($socket = yield $server->accept()) { asyncCall(function () use ($socket) { yield $socket->enableCrypto(); $this->assertInstanceOf(Socket\ServerSocket::class, $socket); $this->assertSame("Hello World", yield $socket->read()); $socket->write("test"); }); } }); $context = (new Socket\ClientTlsContext) ->withPeerName("amphp.org") ->withCaFile(__DIR__ . "/tls/amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($server->getAddress(), null, $context); yield $client->write("Hello World"); $this->assertSame("test", yield $client->read()); $server->close(); Loop::stop(); }); } public function testSniWorksWithMultipleCertificates() { Loop::run(function () { $tlsContext = (new Socket\ServerTlsContext)->withCertificates([ "amphp.org" => new Socket\Certificate(__DIR__ . "/tls/amphp.org.pem"), "www.amphp.org" => new Socket\Certificate(__DIR__ . "/tls/www.amphp.org.pem"), ]); $server = Socket\listen("127.0.0.1:0", null, $tlsContext); asyncCall(function () use ($server) { /** @var Socket\ServerSocket $socket */ while ($socket = yield $server->accept()) { asyncCall(function () use ($socket) { yield $socket->enableCrypto(); $this->assertInstanceOf(Socket\ServerSocket::class, $socket); $this->assertSame("Hello World", yield $socket->read()); $socket->write("test"); }); } }); $context = (new Socket\ClientTlsContext) ->withPeerName("amphp.org") ->withCaFile(__DIR__ . "/tls/amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($server->getAddress(), null, $context); yield $client->write("Hello World"); $context = (new Socket\ClientTlsContext) ->withPeerName("www.amphp.org") ->withCaFile(__DIR__ . "/tls/www.amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($server->getAddress(), null, $context); yield $client->write("Hello World"); yield new Delayed(1); $server->close(); Loop::stop(); }); } public function testSniWorksWithMultipleCertificatesAndDifferentFilesForCertAndKey() { if (\PHP_VERSION_ID < 70200) { $this->markTestSkipped("This test requires PHP 7.2 or higher."); } Loop::run(function () { $tlsContext = (new Socket\ServerTlsContext)->withCertificates([ "amphp.org" => new Socket\Certificate(__DIR__ . "/tls/amphp.org.crt", __DIR__ . "/tls/amphp.org.key"), "www.amphp.org" => new Socket\Certificate(__DIR__ . "/tls/www.amphp.org.crt", __DIR__ . "/tls/www.amphp.org.key"), ]); $server = Socket\listen("127.0.0.1:0", null, $tlsContext); asyncCall(function () use ($server) { /** @var Socket\ServerSocket $socket */ while ($socket = yield $server->accept()) { asyncCall(function () use ($socket) { yield $socket->enableCrypto(); $this->assertInstanceOf(Socket\ServerSocket::class, $socket); $this->assertSame("Hello World", yield $socket->read()); $socket->write("test"); }); } }); $context = (new Socket\ClientTlsContext) ->withPeerName("amphp.org") ->withCaFile(__DIR__ . "/tls/amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($server->getAddress(), null, $context); yield $client->write("Hello World"); $context = (new Socket\ClientTlsContext) ->withPeerName("www.amphp.org") ->withCaFile(__DIR__ . "/tls/www.amphp.org.crt"); /** @var Socket\ClientSocket $client */ $client = yield Socket\cryptoConnect($server->getAddress(), null, $context); yield $client->write("Hello World"); yield new Delayed(1); $server->close(); Loop::stop(); }); } } <?php namespace Amp\Socket\Internal; use Amp\Deferred; use Amp\Failure; use Amp\Loop; use Amp\Promise; use Amp\Socket\CryptoException; use Amp\Success; use function Amp\call; /** * Parse an URI into [scheme, host, port]. * * @param string $uri * * @return array * * @throws \Error If an invalid URI has been passed. * * @internal */ function parseUri(string $uri): array { if (\stripos($uri, "unix://") === 0 || \stripos($uri, "udg://") === 0) { list($scheme, $path) = \explode("://", $uri, 2); return [$scheme, \ltrim($path, "/"), 0]; } if (!$uriParts = @\parse_url($uri)) { throw new \Error( "Invalid URI: {$uri}" ); } $scheme = $uriParts["scheme"] ?? "tcp"; $host = $uriParts["host"] ?? ""; $port = $uriParts["port"] ?? 0; if (!($scheme === "tcp" || $scheme === "udp")) { throw new \Error( "Invalid URI scheme ({$scheme}); tcp, udp, unix or udg scheme expected" ); } if ($host === "" || $port === 0) { throw new \Error( "Invalid URI ({$uri}); host and port components required" ); } if (\strpos($host, ":") !== false) { // IPv6 address $host = \sprintf("[%s]", \trim($host, "[]")); } return [$scheme, $host, $port]; } /** * Enable encryption on an existing socket stream. * * @param resource $socket * @param array $options * @param bool $force Forces enabling without prior disabling if already enabled. * * @return Promise * * @throws \Error If an invalid options array has been passed. * * @internal */ function enableCrypto($socket, array $options = [], bool $force = false): Promise { $ctx = \stream_context_get_options($socket); if (!$force && !empty($ctx['ssl']) && !empty($ctx["ssl"]["_enabled"])) { $cmp = array_merge($ctx["ssl"], $options["ssl"] ?? []); $ctx = $ctx['ssl']; // Use weak comparison so the order of the items doesn't matter if ($ctx == $cmp) { return new Success; } return call(function () use ($socket, $options) { yield disableCrypto($socket); return enableCrypto($socket, $options); }); } $options["ssl"]["_enabled"] = true; // avoid recursion \error_clear_last(); \stream_context_set_option($socket, $options); $result = @\stream_socket_enable_crypto($socket, $enable = true); // Yes, that function can return true / false / 0, don't use weak comparisons. if ($result === true) { return new Success($socket); } if ($result === false) { return new Failure(new CryptoException( "Crypto negotiation failed: " . (\error_get_last()["message"] ?? "Unknown error") )); } return call(function () use ($socket) { $deferred = new Deferred; $watcher = Loop::onReadable($socket, function (string $watcher, $socket, Deferred $deferred) { $result = @\stream_socket_enable_crypto($socket, $enable = true); // If $result is 0, just wait for the next invocation if ($result === true) { $deferred->resolve(); } elseif ($result === false) { $deferred->fail(new CryptoException("Crypto negotiation failed: " . (\feof($socket) ? "Connection reset by peer" : \error_get_last()["message"]))); } }, $deferred); try { yield $deferred->promise(); } finally { Loop::cancel($watcher); } return $socket; }); } /** * Disable encryption on an existing socket stream. * * @param resource $socket * * @return Promise * * @internal */ function disableCrypto($socket): Promise { // note that disabling crypto *ALWAYS* returns false, immediately \stream_context_set_option($socket, ["ssl" => ["_enabled" => false]]); @\stream_socket_enable_crypto($socket, false); return new Success; } /** * Normalizes "bindto" options to add a ":0" in case no port is present, otherwise PHP will silently ignore those. * * @param string|null $bindTo * * @return string|null * * @throws \Error If an invalid option has been passed. */ function normalizeBindToOption(string $bindTo = null) { if ($bindTo === null) { // all fine return null; } elseif (\preg_match("/\\[(?P<ip>[0-9a-f:]+)\\](:(?P<port>\\d+))?$/", $bindTo ?? "", $match)) { $ip = $match['ip']; $port = $match['port'] ?? 0; if (@\inet_pton($ip) === false) { throw new \Error("Invalid IPv6 address: {$ip}"); } if ($port < 0 || $port > 65535) { throw new \Error("Invalid port: {$port}"); } return "[{$ip}]:{$port}"; } if (\preg_match("/(?P<ip>\\d+\\.\\d+\\.\\d+\\.\\d+)(:(?P<port>\\d+))?$/", $bindTo ?? "", $match)) { $ip = $match['ip']; $port = $match['port'] ?? 0; if (@\inet_pton($ip) === false) { throw new \Error("Invalid IPv4 address: {$ip}"); } if ($port < 0 || $port > 65535) { throw new \Error("Invalid port: {$port}"); } return "{$ip}:{$port}"; } throw new \Error("Invalid bindTo value: {$bindTo}"); } /** * Cleans up return values of stream_socket_get_name. * * @param string|false $address * * @return string|null */ function cleanupSocketName($address) { // https://3v4l.org/5C1lo if ($address === false || $address === "\0") { return null; } // Check if this is an IPv6 address which includes multiple colons but no square brackets // @see https://github.com/reactphp/socket/blob/v0.8.10/src/TcpServer.php#L179-L184 // @license https://github.com/reactphp/socket/blob/v0.8.10/LICENSE $pos = strrpos($address, ':'); if ($pos !== false && strpos($address, ':') < $pos && substr($address, 0, 1) !== '[') { $port = substr($address, $pos + 1); $address = '[' . substr($address, 0, $pos) . ']:' . $port; } // -- End of imported code ----- // return $address; } <?php namespace Amp\Socket; use Amp\CancellationToken; use Amp\Deferred; use Amp\Dns; use Amp\Loop; use Amp\NullCancellationToken; use Amp\Promise; use Amp\TimeoutException; use function Amp\call; /** * Listen for client connections on the specified server address. * * If you want to accept TLS connections, you have to use `yield $socket->enableCrypto()` after accepting new clients. * * @param string $uri URI in scheme://host:port format. TCP is assumed if no scheme is present. * @param ServerListenContext $socketContext Context options for listening. * @param ServerTlsContext $tlsContext Context options for TLS connections. * * @return Server * * @throws SocketException If binding to the specified URI failed. * @throws \Error If an invalid scheme is given. */ function listen(string $uri, ServerListenContext $socketContext = null, ServerTlsContext $tlsContext = null): Server { $socketContext = $socketContext ?? new ServerListenContext; $scheme = \strstr($uri, "://", true); if ($scheme === false) { $scheme = "tcp"; } if (!\in_array($scheme, ["tcp", "udp", "unix", "udg"])) { throw new \Error("Only tcp, udp, unix and udg schemes allowed for server creation"); } if ($tlsContext) { $context = \array_merge( $socketContext->toStreamContextArray(), $tlsContext->toStreamContextArray() ); } else { $context = $socketContext->toStreamContextArray(); } $context = \stream_context_create($context); // Error reporting suppressed since stream_socket_server() emits an E_WARNING on failure (checked below). $server = @\stream_socket_server($uri, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context); if (!$server || $errno) { throw new SocketException(\sprintf("Could not create server %s: [Error: #%d] %s", $uri, $errno, $errstr), $errno); } return new Server($server, Socket::DEFAULT_CHUNK_SIZE); } /** * Asynchronously establish a socket connection to the specified URI. * * @param string $uri URI in scheme://host:port format. TCP is assumed if no scheme is present. * @param ClientConnectContext $socketContext Socket connect context to use when connecting. * @param CancellationToken|null $token * * @return Promise<\Amp\Socket\ClientSocket> */ function connect(string $uri, ClientConnectContext $socketContext = null, CancellationToken $token = null): Promise { return call(function () use ($uri, $socketContext, $token) { $socketContext = $socketContext ?? new ClientConnectContext; $token = $token ?? new NullCancellationToken; $attempt = 0; $uris = []; $failures = []; list($scheme, $host, $port) = Internal\parseUri($uri); if ($host[0] === '[') { $host = substr($host, 1, -1); } if ($port === 0 || @\inet_pton($host)) { // Host is already an IP address or file path. $uris = [$uri]; } else { // Host is not an IP address, so resolve the domain name. $records = yield Dns\resolve($host, $socketContext->getDnsTypeRestriction()); // Usually the faster response should be preferred, but we don't have a reliable way of determining IPv6 // support, so we always prefer IPv4 here. \usort($records, function (Dns\Record $a, Dns\Record $b) { return $a->getType() - $b->getType(); }); foreach ($records as $record) { /** @var Dns\Record $record */ if ($record->getType() === Dns\Record::AAAA) { $uris[] = \sprintf("%s://[%s]:%d", $scheme, $record->getValue(), $port); } else { $uris[] = \sprintf("%s://%s:%d", $scheme, $record->getValue(), $port); } } } $flags = \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT; $timeout = $socketContext->getConnectTimeout(); foreach ($uris as $builtUri) { try { $context = \stream_context_create($socketContext->toStreamContextArray()); if (!$socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $context)) { throw new ConnectException(\sprintf( "Connection to %s failed: [Error #%d] %s%s", $uri, $errno, $errstr, $failures ? "; previous attempts: " . \implode($failures) : "" ), $errno); } \stream_set_blocking($socket, false); $deferred = new Deferred; $watcher = Loop::onWritable($socket, [$deferred, 'resolve']); $id = $token->subscribe([$deferred, 'fail']); try { yield Promise\timeout($deferred->promise(), $timeout); } catch (TimeoutException $e) { throw new ConnectException(\sprintf( "Connecting to %s failed: timeout exceeded (%d ms)%s", $uri, $timeout, $failures ? "; previous attempts: " . \implode($failures) : "" ), 110); // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno } finally { Loop::cancel($watcher); $token->unsubscribe($id); } // The following hack looks like the only way to detect connection refused errors with PHP's stream sockets. if (\stream_socket_get_name($socket, true) === false) { \fclose($socket); throw new ConnectException(\sprintf( "Connection to %s refused%s", $uri, $failures ? "; previous attempts: " . \implode($failures) : "" ), 111); // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno } } catch (ConnectException $e) { // Includes only error codes used in this file, as error codes on other OS families might be different. // In fact, this might show a confusing error message on OS families that return 110 or 111 by itself. $knownReasons = [ 110 => "connection timeout", 111 => "connection refused", ]; $code = $e->getCode(); $reason = $knownReasons[$code] ?? ("Error #" . $code); if (++$attempt === $socketContext->getMaxAttempts()) { break; } $failures[] = "{$uri} ({$reason})"; continue; // Could not connect to host, try next host in the list. } return new ClientSocket($socket); } // This is reached if either all URIs failed or the maximum number of attempts is reached. throw $e; }); } /** * Asynchronously establish an encrypted TCP connection (non-blocking). * * Note: Once resolved the socket stream will already be set to non-blocking mode. * * @param string $uri * @param ClientConnectContext $socketContext * @param ClientTlsContext $tlsContext * @param CancellationToken $token * * @return Promise<ClientSocket> */ function cryptoConnect( string $uri, ClientConnectContext $socketContext = null, ClientTlsContext $tlsContext = null, CancellationToken $token = null ): Promise { return call(function () use ($uri, $socketContext, $tlsContext, $token) { $tlsContext = $tlsContext ?? new ClientTlsContext; if ($tlsContext->getPeerName() === null) { $tlsContext = $tlsContext->withPeerName(\parse_url($uri, PHP_URL_HOST)); } /** @var ClientSocket $socket */ $socket = yield connect($uri, $socketContext, $token); $promise = $socket->enableCrypto($tlsContext); if ($token) { $deferred = new Deferred; $id = $token->subscribe([$deferred, "fail"]); $promise->onResolve(function ($exception) use ($id, $token, $deferred) { if ($token->isRequested()) { return; } $token->unsubscribe($id); if ($exception) { $deferred->fail($exception); return; } $deferred->resolve(); }); $promise = $deferred->promise(); } try { yield $promise; } catch (\Throwable $exception) { $socket->close(); throw $exception; } return $socket; }); } /** * Returns a pair of connected stream socket resources. * * @return resource[] Pair of socket resources. * * @throws \Amp\Socket\SocketException If creating the sockets fails. */ function pair(): array { if (($sockets = @\stream_socket_pair(\stripos(PHP_OS, "win") === 0 ? STREAM_PF_INET : STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP)) === false) { $message = "Failed to create socket pair."; if ($error = \error_get_last()) { $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); } throw new SocketException($message); } return $sockets; } <?php namespace Amp\Socket; use Amp\CancellationToken; use Amp\CancelledException; use Amp\Failure; use Amp\Loop; use Amp\Promise; use Amp\Struct; use Amp\Success; use Amp\Uri\Uri; use function Amp\call; final class BasicSocketPool implements SocketPool { private $sockets = []; private $socketIdUriMap = []; private $pendingCount = []; private $idleTimeout; private $socketContext; public function __construct(int $idleTimeout = 10000, ClientConnectContext $socketContext = null) { $this->idleTimeout = $idleTimeout; $this->socketContext = $socketContext ?? new ClientConnectContext; } private function normalizeUri(string $uri): string { if (stripos($uri, 'unix://') === 0) { return $uri; } return (new Uri($uri))->normalize(); } /** @inheritdoc */ public function checkout(string $uri, CancellationToken $token = null): Promise { // A request might already be cancelled before we reach the checkout, so do not even attempt to checkout in that // case. The weird logic is required to throw the token's exception instead of creating a new one. if ($token && $token->isRequested()) { try { $token->throwIfRequested(); } catch (CancelledException $e) { return new Failure($e); } } $uri = $this->normalizeUri($uri); if (empty($this->sockets[$uri])) { return $this->checkoutNewSocket($uri, $token); } foreach ($this->sockets[$uri] as $socketId => $socket) { if (!$socket->isAvailable) { continue; } elseif (!\is_resource($socket->resource) || \feof($socket->resource)) { $this->clear(new ClientSocket($socket->resource)); continue; } $socket->isAvailable = false; if ($socket->idleWatcher !== null) { Loop::disable($socket->idleWatcher); } return new Success(new ClientSocket($socket->resource)); } return $this->checkoutNewSocket($uri, $token); } private function checkoutNewSocket(string $uri, CancellationToken $token = null): Promise { return call(function () use ($uri, $token) { $this->pendingCount[$uri] = ($this->pendingCount[$uri] ?? 0) + 1; try { /** @var ClientSocket $rawSocket */ $rawSocket = yield connect($uri, $this->socketContext, $token); } finally { if (--$this->pendingCount[$uri] === 0) { unset($this->pendingCount[$uri]); } } $socketId = (int) $rawSocket->getResource(); $socket = new class { use Struct; public $id; public $uri; public $resource; public $isAvailable; public $idleWatcher; }; $socket->id = $socketId; $socket->uri = $uri; $socket->resource = $rawSocket->getResource(); $socket->isAvailable = false; $this->sockets[$uri][$socketId] = $socket; $this->socketIdUriMap[$socketId] = $uri; return $rawSocket; }); } /** @inheritdoc */ public function clear(ClientSocket $socket) { $socketId = (int) $socket->getResource(); if (!isset($this->socketIdUriMap[$socketId])) { throw new \Error( sprintf('Unknown socket: %d', $socketId) ); } $uri = $this->socketIdUriMap[$socketId]; $socket = $this->sockets[$uri][$socketId]; if ($socket->idleWatcher) { Loop::cancel($socket->idleWatcher); } unset( $this->sockets[$uri][$socketId], $this->socketIdUriMap[$socketId] ); if (empty($this->sockets[$uri])) { unset($this->sockets[$uri]); } } /** @inheritdoc */ public function checkin(ClientSocket $socket) { $socketId = (int) $socket->getResource(); if (!isset($this->socketIdUriMap[$socketId])) { throw new \Error( \sprintf('Unknown socket: %d', $socketId) ); } $uri = $this->socketIdUriMap[$socketId]; if (!\is_resource($socket->getResource()) || \feof($socket->getResource())) { $this->clear($socket); return; } $socket = $this->sockets[$uri][$socketId]; $socket->isAvailable = true; if (isset($socket->idleWatcher)) { Loop::enable($socket->idleWatcher); } else { $socket->idleWatcher = Loop::delay($this->idleTimeout, function () use ($socket) { $this->clear(new ClientSocket($socket->resource)); }); Loop::unreference($socket->idleWatcher); } } } <?php namespace Amp\Socket; use Amp\ByteStream\ClosedException; use Amp\Failure; use Amp\Promise; class ServerSocket extends Socket { /** @inheritdoc */ public function enableCrypto(): Promise { if (($resource = $this->getResource()) === null) { return new Failure(new ClosedException("The socket has been closed")); } $ctx = \stream_context_get_options($resource); if (empty($ctx['ssl'])) { return new Failure(new CryptoException( "Can't enable TLS without configuration. " . "If you used Amp\\Socket\\listen(), be sure to pass a ServerTlsContext as third argument, " . "otherwise set the 'ssl' context option to the PHP stream resource." )); } return Internal\enableCrypto($resource, [], true); } } <?php namespace Amp\Socket; /** * Thrown in case a second read operation is attempted while another read operation is still pending. */ final class PendingAcceptError extends \Error { public function __construct( string $message = "The previous accept operation must complete before accept can be called again", int $code = 0, \Throwable $previous = null ) { parent::__construct($message, $code, $previous); } } <?php namespace Amp\Socket; use Amp\ByteStream\ClosedException; use Amp\ByteStream\InputStream; use Amp\ByteStream\OutputStream; use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\Failure; use Amp\Promise; abstract class Socket implements InputStream, OutputStream { const DEFAULT_CHUNK_SIZE = ResourceInputStream::DEFAULT_CHUNK_SIZE; /** @var \Amp\ByteStream\ResourceInputStream */ private $reader; /** @var \Amp\ByteStream\ResourceOutputStream */ private $writer; /** * @param resource $resource Stream resource. * @param int $chunkSize Read and write chunk size. * * @throws \Error If a stream resource is not given for $resource. */ public function __construct($resource, int $chunkSize = self::DEFAULT_CHUNK_SIZE) { $this->reader = new ResourceInputStream($resource, $chunkSize); $this->writer = new ResourceOutputStream($resource, $chunkSize); } /** * Raw stream socket resource. * * @return resource|null */ public function getResource() { return $this->reader->getResource(); } /** * Enables encryption on this socket. * * @return Promise */ abstract public function enableCrypto(): Promise; /** * Disables encryption on this socket. * * @return Promise */ public function disableCrypto(): Promise { if (($resource = $this->reader->getResource()) === null) { return new Failure(new ClosedException("The socket has been closed")); } return Internal\disableCrypto($resource); } /** @inheritdoc */ public function read(): Promise { return $this->reader->read(); } /** @inheritdoc */ public function write(string $data): Promise { return $this->writer->write($data); } /** @inheritdoc */ public function end(string $data = ""): Promise { $promise = $this->writer->end($data); $promise->onResolve(function () { $this->close(); }); return $promise; } /** * References the read watcher, so the loop keeps running in case there's an active read. * * @see Loop::reference() */ public function reference() { $this->reader->reference(); } /** * Unreferences the read watcher, so the loop doesn't keep running even if there are active reads. * * @see Loop::unreference() */ public function unreference() { $this->reader->unreference(); } /** * Force closes the socket, failing any pending reads or writes. */ public function close() { $this->reader->close(); $this->writer->close(); } public function getLocalAddress() { return $this->getAddress(false); } public function getRemoteAddress() { return $this->getAddress(true); } private function getAddress(bool $wantPeer) { $remoteCleaned = Internal\cleanupSocketName(@\stream_socket_get_name($this->getResource(), $wantPeer)); if ($remoteCleaned !== null) { return $remoteCleaned; } $meta = @stream_get_meta_data($this->getResource()) ?? []; if (array_key_exists('stream_type', $meta) && $meta['stream_type'] === 'unix_socket') { return Internal\cleanupSocketName(@\stream_socket_get_name($this->getResource(), !$wantPeer)); } return null; } } <?php namespace Amp\Socket; use function Amp\Socket\Internal\normalizeBindToOption; final class ServerListenContext { private $bindTo = null; private $backlog = 128; private $reusePort = false; private $broadcast = false; private $tcpNoDelay = false; public function withBindTo(string $bindTo = null): self { $bindTo = normalizeBindToOption($bindTo); $clone = clone $this; $clone->bindTo = $bindTo; return $clone; } public function getBindTo() { return $this->bindTo; } public function getBacklog() { return $this->backlog; } public function withBacklog(int $backlog): self { $clone = clone $this; $clone->backlog = $backlog; return $clone; } public function hasReusePort(): bool { return $this->reusePort; } public function withReusePort(): self { $clone = clone $this; $clone->reusePort = true; return $clone; } public function withoutReusePort(): self { $clone = clone $this; $clone->reusePort = false; return $clone; } public function hasBroadcast(): bool { return $this->broadcast; } public function withBroadcast(): self { $clone = clone $this; $clone->broadcast = true; return $clone; } public function withoutBroadcast(): self { $clone = clone $this; $clone->broadcast = false; return $clone; } public function hasTcpNoDelay(): bool { return $this->tcpNoDelay; } public function withTcpNoDelay(): self { $clone = clone $this; $clone->tcpNoDelay = true; return $clone; } public function withoutTcpNoDelay(): self { $clone = clone $this; $clone->tcpNoDelay = false; return $clone; } public function toStreamContextArray(): array { return ["socket" => [ "bindto" => $this->bindTo, "backlog" => $this->backlog, "ipv6_v6only" => true, // SO_REUSEADDR has SO_REUSEPORT semantics on Windows "so_reuseaddr" => $this->reusePort && \stripos(\PHP_OS, "WIN") === 0, "so_reuseport" => $this->reusePort, "so_broadcast" => $this->broadcast, "tcp_nodelay" => $this->tcpNoDelay, ]]; } } <?php namespace Amp\Socket; /** * @see ServerTlsContext::withDefaultCertificate() * @see ServerTlsContext::withCertificates() */ class Certificate { private $certFile; private $keyFile; /** * @param string $certFile Certificate file with the certificate + intermediaries. * @param string|null $keyFile Key file with the corresponding private key or `null` if the key is in $certFile. */ public function __construct(string $certFile, string $keyFile = null) { $this->certFile = $certFile; $this->keyFile = $keyFile ?? $certFile; } /** * @return string */ public function getCertFile(): string { return $this->certFile; } /** * @return string */ public function getKeyFile(): string { return $this->keyFile; } } <?php namespace Amp\Socket; class CryptoException extends SocketException { } <?php namespace Amp\Socket; final class ServerTlsContext { const TLSv1_0 = \STREAM_CRYPTO_METHOD_TLSv1_0_SERVER; const TLSv1_1 = \STREAM_CRYPTO_METHOD_TLSv1_1_SERVER; const TLSv1_2 = \STREAM_CRYPTO_METHOD_TLSv1_2_SERVER; /** @var int */ private $minVersion = \STREAM_CRYPTO_METHOD_TLSv1_0_SERVER; /** @var null|string */ private $peerName = null; /** @var bool */ private $verifyPeer = false; /** @var int */ private $verifyDepth = 10; /** @var null|string */ private $ciphers = null; /** @var null|string */ private $caFile = null; /** @var null|string */ private $caPath = null; /** @var bool */ private $capturePeer = false; /** @var null|Certificate */ private $defaultCertificate = null; /** @var Certificate[] */ private $certificates = []; /** @var int */ private $securityLevel = 2; /** * Minimum TLS version to negotiate. * * Defaults to TLS 1.0. * * @param int $version `ServerTlsContext::TLSv1_0`, `ServerTlsContext::TLSv1_1`, or `ServerTlsContext::TLSv1_2`. * * @return self Cloned, modified instance. * @throws \Error If an invalid minimum version is given. */ public function withMinimumVersion(int $version): self { if ($version !== self::TLSv1_0 && $version !== self::TLSv1_1 && $version !== self::TLSv1_2) { throw new \Error("Invalid minimum version, only TLSv1.0, TLSv1.1 or TLSv1.2 allowed"); } $clone = clone $this; $clone->minVersion = $version; return $clone; } /** * Returns the minimum TLS version to negotiate. * * @return int */ public function getMinimumVersion(): int { return $this->minVersion; } /** * Expected name of the peer. * * @param string|null $peerName * * @return self Cloned, modified instance. */ public function withPeerName(string $peerName = null): self { $clone = clone $this; $clone->peerName = $peerName; return $clone; } /** * @return null|string Expected name of the peer or `null` if such an expectation doesn't exist. */ public function getPeerName() { return $this->peerName; } /** * Enable peer verification. * * @return self Cloned, modified instance. */ public function withPeerVerification(): self { $clone = clone $this; $clone->verifyPeer = true; return $clone; } /** * Disable peer verification, this is the default for servers. * * @return self Cloned, modified instance. */ public function withoutPeerVerification(): self { $clone = clone $this; $clone->verifyPeer = false; return $clone; } /** * @return bool Whether peer verification is enabled. */ public function hasPeerVerification(): bool { return $this->verifyPeer; } /** * Maximum chain length the peer might present including the certificates in the local trust store. * * @param int $verifyDepth Maximum length of the certificate chain. * * @return self Cloned, modified instance. */ public function withVerificationDepth(int $verifyDepth): self { if ($verifyDepth < 0) { throw new \Error("Invalid verification depth ({$verifyDepth}), must be greater than or equal to 0"); } $clone = clone $this; $clone->verifyDepth = $verifyDepth; return $clone; } /** * @return int Maximum length of the certificate chain. */ public function getVerificationDepth(): int { return $this->verifyDepth; } /** * List of ciphers to negotiate, the server's order is always preferred. * * @param string|null $ciphers List of ciphers in OpenSSL's format (colon separated). * * @return self Cloned, modified instance. */ public function withCiphers(string $ciphers = null): self { $clone = clone $this; $clone->ciphers = $ciphers; return $clone; } /** * @return string List of ciphers in OpenSSL's format (colon separated). */ public function getCiphers(): string { return $this->ciphers ?? \OPENSSL_DEFAULT_STREAM_CIPHERS; } /** * CAFile to check for trusted certificates. * * @param string|null $cafile Path to the file or `null` to unset. * * @return self Cloned, modified instance. */ public function withCaFile(string $cafile = null): self { $clone = clone $this; $clone->caFile = $cafile; return $clone; } /** * @return null|string Path to the file if one is set, otherwise `null`. */ public function getCaFile() { return $this->caFile; } /** * CAPath to check for trusted certificates. * * @param string|null $capath Path to the file or `null` to unset. * * @return self Cloned, modified instance. */ public function withCaPath(string $capath = null): self { $clone = clone $this; $clone->caPath = $capath; return $clone; } /** * @return null|string Path to the file if one is set, otherwise `null`. */ public function getCaPath() { return $this->caPath; } /** * Capture the certificates sent by the peer. * * Note: This is the chain as sent by the peer, NOT the verified chain. * * @return self Cloned, modified instance. */ public function withPeerCapturing(): self { $clone = clone $this; $clone->capturePeer = true; return $clone; } /** * Don't capture the certificates sent by the peer. * * @return self Cloned, modified instance. */ public function withoutPeerCapturing(): self { $clone = clone $this; $clone->capturePeer = false; return $clone; } /** * @return bool Whether to capture the certificates sent by the peer. */ public function hasPeerCapturing(): bool { return $this->capturePeer; } /** * Default certificate to use in case no SNI certificate matches. * * @param Certificate|null $defaultCertificate * * @return self Cloned, modified instance. */ public function withDefaultCertificate(Certificate $defaultCertificate = null): self { $clone = clone $this; $clone->defaultCertificate = $defaultCertificate; return $clone; } /** * @return Certificate|null Default certificate to use in case no SNI certificate matches, or `null` if unset. */ public function getDefaultCertificate() { return $this->defaultCertificate; } /** * Certificates to use for the given host names. * * @param array $certificates Must be a associative array mapping hostnames to certificate instances. * * @return self Cloned, modified instance. */ public function withCertificates(array $certificates): self { foreach ($certificates as $key => $certificate) { if (!\is_string($key)) { throw new \TypeError("Expected an array mapping domain names to Certificate instances"); } if (!$certificate instanceof Certificate) { throw new \TypeError("Expected an array of Certificate instances"); } if (\PHP_VERSION_ID < 70200 && $certificate->getCertFile() !== $certificate->getKeyFile()) { throw new \Error( "Different files for cert and key are not supported on this version of PHP. " . "Please upgrade to PHP 7.2 or later." ); } } $clone = clone $this; $clone->certificates = $certificates; return $clone; } /** * @return array Associative array mapping hostnames to certificate instances. */ public function getCertificates(): array { return $this->certificates; } /** * Security level to use. * * Requires OpenSSL 1.1.0 or higher. * * @param int $level Must be between 0 and 5. * * @return self Cloned, modified instance. */ public function withSecurityLevel(int $level): self { // See https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_security_level.html // Level 2 is not recommended, because of SHA-1 by that document, // but SHA-1 should be phased out now on general internet use. // We therefore default to level 2. if ($level < 0 || $level > 5) { throw new \Error("Invalid security level ({$level}), must be between 0 and 5."); } if (\OPENSSL_VERSION_NUMBER < 0x10100000) { throw new \Error("Can't set a security level, as PHP is compiled with OpenSSL < 1.1.0."); } $clone = clone $this; $clone->securityLevel = $level; return $clone; } /** * @return int Security level between 0 and 5. Always 0 for OpenSSL < 1.1.0. */ public function getSecurityLevel(): int { // 0 is equivalent to previous versions of OpenSSL and just does nothing if (\OPENSSL_VERSION_NUMBER < 0x10100000) { return 0; } return $this->securityLevel; } /** * Converts this TLS context into PHP's equivalent stream context array. * * @return array Stream context array compatible with PHP's streams. */ public function toStreamContextArray(): array { $options = [ "crypto_method" => $this->toStreamCryptoMethod(), "peer_name" => $this->peerName, "verify_peer" => $this->verifyPeer, "verify_peer_name" => $this->verifyPeer, "verify_depth" => $this->verifyDepth, "ciphers" => $this->ciphers ?? \OPENSSL_DEFAULT_STREAM_CIPHERS, "honor_cipher_order" => true, "single_dh_use" => true, "no_ticket" => true, "capture_peer_cert" => $this->capturePeer, "capture_peer_chain" => $this->capturePeer, ]; if ($this->defaultCertificate !== null) { $options["local_cert"] = $this->defaultCertificate->getCertFile(); if ($this->defaultCertificate->getCertFile() !== $this->defaultCertificate->getKeyFile()) { $options["local_pk"] = $this->defaultCertificate->getKeyFile(); } } if ($this->certificates) { $options["SNI_server_certs"] = array_map(function (Certificate $certificate) { if ($certificate->getCertFile() === $certificate->getKeyFile()) { return $certificate->getCertFile(); } return [ "local_cert" => $certificate->getCertFile(), "local_pk" => $certificate->getKeyFile(), ]; }, $this->certificates); } if ($this->caFile !== null) { $options["cafile"] = $this->caFile; } if ($this->caPath !== null) { $options["capath"] = $this->caPath; } if (\OPENSSL_VERSION_NUMBER >= 0x10100000) { $options["security_level"] = $this->securityLevel; } return ["ssl" => $options]; } /** * @return int Crypto method compatible with PHP's streams. */ public function toStreamCryptoMethod(): int { return (~($this->minVersion - 1) & \STREAM_CRYPTO_METHOD_ANY_SERVER) & (~1); } } <?php namespace Amp\Socket; class ConnectException extends SocketException { } <?php namespace Amp\Socket; use Amp\ByteStream\StreamException; class SocketException extends StreamException { } <?php namespace Amp\Socket; use Amp\ByteStream\ClosedException; use Amp\Failure; use Amp\Promise; class ClientSocket extends Socket { /** * {@inheritdoc} * * @param ClientTlsContext|null $tlsContext */ public function enableCrypto(ClientTlsContext $tlsContext = null): Promise { if (($resource = $this->getResource()) === null) { return new Failure(new ClosedException("The socket has been closed")); } $tlsContext = $tlsContext ?? new ClientTlsContext; return Internal\enableCrypto($resource, $tlsContext->toStreamContextArray()); } } <?php namespace Amp\Socket; final class ClientTlsContext { const TLSv1_0 = \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; const TLSv1_1 = \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; const TLSv1_2 = \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; private $minVersion = \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT; private $peerName = null; private $verifyPeer = true; private $verifyDepth = 10; private $ciphers = null; private $caFile = null; private $caPath = null; private $capturePeer = false; private $sniEnabled = true; private $securityLevel = 2; private $certificate = null; /** * Minimum TLS version to negotiate. * * Defaults to TLS 1.0. * * @param int $version `ServerTlsContext::TLSv1_0`, `ServerTlsContext::TLSv1_1`, or `ServerTlsContext::TLSv1_2`. * * @return self Cloned, modified instance. * @throws \Error If an invalid minimum version is given. */ public function withMinimumVersion(int $version): self { if ($version !== self::TLSv1_0 && $version !== self::TLSv1_1 && $version !== self::TLSv1_2) { throw new \Error("Invalid minimum version, only TLSv1.0, TLSv1.1 or TLSv1.2 allowed"); } $clone = clone $this; $clone->minVersion = $version; return $clone; } /** * Returns the minimum TLS version to negotiate. * * @return int */ public function getMinimumVersion(): int { return $this->minVersion; } /** * Expected name of the peer. * * @param string|null $peerName * * @return self Cloned, modified instance. */ public function withPeerName(string $peerName = null): self { $clone = clone $this; $clone->peerName = $peerName; return $clone; } /** * @return null|string Expected name of the peer or `null` if such an expectation doesn't exist. */ public function getPeerName() { return $this->peerName; } /** * Enable peer verification. * * @return self Cloned, modified instance. */ public function withPeerVerification(): self { $clone = clone $this; $clone->verifyPeer = true; return $clone; } /** * Disable peer verification, this is the default for servers. * * @return self Cloned, modified instance. */ public function withoutPeerVerification(): self { $clone = clone $this; $clone->verifyPeer = false; return $clone; } /** * @return bool Whether peer verification is enabled. */ public function hasPeerVerification(): bool { return $this->verifyPeer; } /** * Maximum chain length the peer might present including the certificates in the local trust store. * * @param int $verifyDepth Maximum length of the certificate chain. * * @return self Cloned, modified instance. */ public function withVerificationDepth(int $verifyDepth): self { if ($verifyDepth < 0) { throw new \Error("Invalid verification depth ({$verifyDepth}), must be greater than or equal to 0"); } $clone = clone $this; $clone->verifyDepth = $verifyDepth; return $clone; } /** * @return int Maximum length of the certificate chain. */ public function getVerificationDepth(): int { return $this->verifyDepth; } /** * List of ciphers to negotiate, the server's order is always preferred. * * @param string|null $ciphers List of ciphers in OpenSSL's format (colon separated). * * @return self Cloned, modified instance. */ public function withCiphers(string $ciphers = null): self { $clone = clone $this; $clone->ciphers = $ciphers; return $clone; } /** * @return string List of ciphers in OpenSSL's format (colon separated). */ public function getCiphers(): string { return $this->ciphers ?? \OPENSSL_DEFAULT_STREAM_CIPHERS; } /** * CAFile to check for trusted certificates. * * @param string|null $cafile Path to the file or `null` to unset. * * @return self Cloned, modified instance. */ public function withCaFile(string $cafile = null): self { $clone = clone $this; $clone->caFile = $cafile; return $clone; } /** * @return null|string Path to the file if one is set, otherwise `null`. */ public function getCaFile() { return $this->caFile; } /** * CAPath to check for trusted certificates. * * @param string|null $capath Path to the file or `null` to unset. * * @return self Cloned, modified instance. */ public function withCaPath(string $capath = null): self { $clone = clone $this; $clone->caPath = $capath; return $clone; } /** * @return null|string Path to the file if one is set, otherwise `null`. */ public function getCaPath() { return $this->caPath; } /** * Capture the certificates sent by the peer. * * Note: This is the chain as sent by the peer, NOT the verified chain. * * @return self Cloned, modified instance. */ public function withPeerCapturing(): self { $clone = clone $this; $clone->capturePeer = true; return $clone; } /** * Don't capture the certificates sent by the peer. * * @return self Cloned, modified instance. */ public function withoutPeerCapturing(): self { $clone = clone $this; $clone->capturePeer = false; return $clone; } /** * @return bool Whether to capture the certificates sent by the peer. */ public function hasPeerCapturing(): bool { return $this->capturePeer; } /** * Enable SNI. * * @return self Cloned, modified instance. */ public function withSni(): self { $clone = clone $this; $clone->sniEnabled = true; return $clone; } /** * Disable SNI. * * @return self Cloned, modified instance. */ public function withoutSni(): self { $clone = clone $this; $clone->sniEnabled = false; return $clone; } /** * @return bool Whether SNI is enabled or not. */ public function hasSni(): bool { return $this->sniEnabled; } /** * Security level to use. * * Requires OpenSSL 1.1.0 or higher. * * @param int $level Must be between 0 and 5. * * @return self Cloned, modified instance. */ public function withSecurityLevel(int $level): self { // See https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_security_level.html // Level 2 is not recommended, because of SHA-1 by that document, // but SHA-1 should be phased out now on general internet use. // We therefore default to level 2. if ($level < 0 || $level > 5) { throw new \Error("Invalid security level ({$level}), must be between 0 and 5."); } if (\OPENSSL_VERSION_NUMBER < 0x10100000) { throw new \Error("Can't set a security level, as PHP is compiled with OpenSSL < 1.1.0."); } $clone = clone $this; $clone->securityLevel = $level; return $clone; } /** * @return int Security level between 0 and 5. Always 0 for OpenSSL < 1.1.0. */ public function getSecurityLevel(): int { // 0 is equivalent to previous versions of OpenSSL and just does nothing if (\OPENSSL_VERSION_NUMBER < 0x10100000) { return 0; } return $this->securityLevel; } /** * Client certificate to use, if key is no present it assumes it is present in the same file as the certificate. * * @return self Cloned, modified instance. */ public function withCertificate(Certificate $certificate = null): self { $clone = clone $this; $clone->certificate = $certificate; return $clone; } public function getCertificate() { return $this->certificate; } /** * Converts this TLS context into PHP's equivalent stream context array. * * @return array Stream context array compatible with PHP's streams. */ public function toStreamContextArray(): array { $options = [ "crypto_method" => $this->toStreamCryptoMethod(), "peer_name" => $this->peerName, "verify_peer" => $this->verifyPeer, "verify_peer_name" => $this->verifyPeer, "verify_depth" => $this->verifyDepth, "ciphers" => $this->ciphers ?? \OPENSSL_DEFAULT_STREAM_CIPHERS, "capture_peer_cert" => $this->capturePeer, "capture_peer_cert_chain" => $this->capturePeer, "SNI_enabled" => $this->sniEnabled, ]; if ($this->certificate !== null) { $options["local_cert"] = $this->certificate->getCertFile(); if ($this->certificate->getCertFile() !== $this->certificate->getKeyFile()) { $options["local_pk"] = $this->certificate->getKeyFile(); } } if ($this->caFile !== null) { $options["cafile"] = $this->caFile; } if ($this->caPath !== null) { $options["capath"] = $this->caPath; } if (\OPENSSL_VERSION_NUMBER >= 0x10100000) { $options["security_level"] = $this->securityLevel; } return ["ssl" => $options]; } /** * @return int Crypto method compatible with PHP's streams. */ public function toStreamCryptoMethod(): int { // -2 to clear client flag and then make all lower versions bits 1 return (~($this->minVersion - 2) & \STREAM_CRYPTO_METHOD_ANY_CLIENT) | 1; } } <?php namespace Amp\Socket; use Amp\CancellationToken; use Amp\Promise; final class StaticSocketPool implements SocketPool { private $uri; private $socketPool; public function __construct(string $uri, SocketPool $socketPool = null) { $this->uri = $uri; $this->socketPool = $socketPool ?? new BasicSocketPool; } /** @inheritdoc */ public function checkout(string $uri, CancellationToken $token = null): Promise { return $this->socketPool->checkout($this->uri, $token); } /** @inheritdoc */ public function checkin(ClientSocket $socket) { $this->socketPool->checkin($socket); } /** @inheritdoc */ public function clear(ClientSocket $socket) { $this->socketPool->clear($socket); } } <?php namespace Amp\Socket; use Amp\CancellationToken; use Amp\Promise; /** * Allows pooling of connections for stateless protocols. */ interface SocketPool { /** * Checkout a socket from the specified URI authority. * * The resulting socket resource should be checked back in via `SocketPool::checkin()` once the calling code is * finished with the stream (even if the socket has been closed). Failure to checkin sockets will result in memory * leaks and socket queue blockage. Instead of checking the socket in again, it can also be cleared. * * @param string $uri A string of the form tcp://example.com:80 or tcp://192.168.1.1:443. * @param CancellationToken $token Optional cancellation token to cancel the checkout request. * * @return Promise Resolves to a Socket instance once a connection is available. */ public function checkout(string $uri, CancellationToken $token = null): Promise; /** * Return a previously checked-out socket to the pool so it can be reused. * * @param ClientSocket $socket Socket instance. * * @throws \Error If the provided resource is unknown to the pool. */ public function checkin(ClientSocket $socket); /** * Remove the specified socket from the pool. * * @param ClientSocket $socket Socket instance. * * @throws \Error If the provided resource is unknown to the pool. */ public function clear(ClientSocket $socket); } <?php namespace Amp\Socket; use Amp\Deferred; use Amp\Loop; use Amp\Promise; use Amp\Success; class Server { /** @var resource Stream socket server resource. */ private $socket; /** @var string Watcher ID. */ private $watcher; /** @var string|null Stream socket name */ private $address; /** @var int */ private $chunkSize; /** @var Deferred|null */ private $acceptor; /** * @param resource $socket A bound socket server resource * @param int $chunkSize Chunk size for the input and output stream. * * @throws \Error If a stream resource is not given for $socket. */ public function __construct($socket, int $chunkSize = Socket::DEFAULT_CHUNK_SIZE) { if (!\is_resource($socket) || \get_resource_type($socket) !== 'stream') { throw new \Error('Invalid resource given to constructor!'); } $this->socket = $socket; $this->chunkSize = $chunkSize; $this->address = Internal\cleanupSocketName(@\stream_socket_get_name($this->socket, false)); \stream_set_blocking($this->socket, false); $acceptor = &$this->acceptor; $this->watcher = Loop::onReadable($this->socket, static function ($watcher, $socket) use (&$acceptor, $chunkSize) { // Error reporting suppressed since stream_socket_accept() emits E_WARNING on client accept failure. if (!$client = @\stream_socket_accept($socket, 0)) { // Timeout of 0 to be non-blocking. return; // Accepting client failed. } $deferred = $acceptor; $acceptor = null; $deferred->resolve(new ServerSocket($client, $chunkSize)); if (!$acceptor) { Loop::disable($watcher); } }); Loop::disable($this->watcher); } /** * Automatically cancels the loop watcher. */ public function __destruct() { if (!$this->socket) { return; } $this->free(); } /** * @return \Amp\Promise<ServerSocket|null> * * @throws \Amp\Socket\PendingAcceptError If another accept request is pending. */ public function accept(): Promise { if ($this->acceptor) { throw new PendingAcceptError; } if (!$this->socket) { return new Success; // Resolve with null when server is closed. } // Error reporting suppressed since stream_socket_accept() emits E_WARNING on client accept failure. if ($client = @\stream_socket_accept($this->socket, 0)) { // Timeout of 0 to be non-blocking. return new Success(new ServerSocket($client, $this->chunkSize)); } $this->acceptor = new Deferred; Loop::enable($this->watcher); return $this->acceptor->promise(); } /** * Closes the server and stops accepting connections. Any socket clients accepted will not be closed. */ public function close() { if ($this->socket) { \fclose($this->socket); } $this->free(); } /** * @return string|null */ public function getAddress() { return $this->address; } private function free() { Loop::cancel($this->watcher); $this->socket = null; if ($this->acceptor) { $this->acceptor->resolve(); $this->acceptor = null; } } /** * Raw stream socket resource. * * @return resource|null */ public function getResource() { return $this->socket; } } <?php namespace Amp\Socket; use Amp\Dns\Record; use function Amp\Socket\Internal\normalizeBindToOption; final class ClientConnectContext { private $bindTo = null; private $connectTimeout = 10000; private $maxAttempts = 2; private $typeRestriction = null; private $tcpNoDelay = false; public function withBindTo(string $bindTo = null): self { $bindTo = normalizeBindToOption($bindTo); $clone = clone $this; $clone->bindTo = $bindTo; return $clone; } public function getBindTo() { return $this->bindTo; } public function withConnectTimeout(int $timeout): self { if ($timeout <= 0) { throw new \Error("Invalid connect timeout ({$timeout}), must be greater than 0"); } $clone = clone $this; $clone->connectTimeout = $timeout; return $clone; } public function getConnectTimeout(): int { return $this->connectTimeout; } public function withMaxAttempts(int $maxAttempts): self { if ($maxAttempts <= 0) { throw new \Error("Invalid max attempts ({$maxAttempts}), must be greater than 0"); } $clone = clone $this; $clone->maxAttempts = $maxAttempts; return $clone; } public function getMaxAttempts(): int { return $this->maxAttempts; } public function withDnsTypeRestriction(int $type = null): self { if ($type !== null && $type !== Record::AAAA && $type !== Record::A) { throw new \Error("Invalid resolver type restriction"); } $clone = clone $this; $clone->typeRestriction = $type; return $clone; } public function getDnsTypeRestriction() { return $this->typeRestriction; } public function hasTcpNoDelay(): bool { return $this->tcpNoDelay; } public function withTcpNoDelay(): self { $clone = clone $this; $clone->tcpNoDelay = true; return $clone; } public function withoutTcpNoDelay(): self { $clone = clone $this; $clone->tcpNoDelay = false; return $clone; } public function toStreamContextArray(): array { $options = [ "tcp_nodelay" => $this->tcpNoDelay, ]; if ($this->bindTo !== null) { $options["bindto"] = $this->bindTo; } return ["socket" => $options]; } } { "name": "amphp/dns", "homepage": "https://github.com/amphp/dns", "description": "Async DNS resolution for Amp.", "keywords": [ "dns", "resolve", "client", "async", "amp", "amphp" ], "license": "MIT", "authors": [ { "name": "Chris Wright", "email": "addr@daverandom.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" } ], "require": { "php": ">=7.0", "amphp/amp": "^2", "amphp/byte-stream": "^1.1", "amphp/cache": "^1.2", "amphp/parser": "^1", "amphp/windows-registry": "^0.3", "daverandom/libdns": "^2.0.1", "ext-filter": "*" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "amphp/php-cs-fixer-config": "dev-master" }, "autoload": { "psr-4": { "Amp\\Dns\\": "lib" }, "files": [ "lib/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Dns\\Test\\": "test" } }, "config": { "platform": { "php": "7.0.0" } }, "scripts": { "check": [ "@cs", "@test" ], "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run", "cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff", "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text" } } <?php namespace Amp\Dns; class TimeoutException extends DnsException { } <?php namespace Amp\Dns; class DnsException extends \Exception { } <?php namespace Amp\Dns\Internal; use Amp\Dns\DnsException; use Amp\Promise; use Amp\Success; use LibDNS\Decoder\DecoderFactory; use LibDNS\Encoder\EncoderFactory; use LibDNS\Messages\Message; use function Amp\call; /** @internal */ final class UdpSocket extends Socket { /** @var \LibDNS\Encoder\Encoder */ private $encoder; /** @var \LibDNS\Decoder\Decoder */ private $decoder; public static function connect(string $uri): Promise { if (!$socket = @\stream_socket_client($uri, $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT)) { throw new DnsException(\sprintf( "Connection to %s failed: [Error #%d] %s", $uri, $errno, $errstr )); } return new Success(new self($socket)); } protected function __construct($socket) { parent::__construct($socket); $this->encoder = (new EncoderFactory)->create(); $this->decoder = (new DecoderFactory)->create(); } protected function send(Message $message): Promise { $data = $this->encoder->encode($message); return $this->write($data); } protected function receive(): Promise { return call(function () { $data = yield $this->read(); if ($data === null) { throw new DnsException("Reading from the server failed"); } return $this->decoder->decode($data); }); } public function isAlive(): bool { return true; } } <?php namespace Amp\Dns\Internal; use Amp; use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\ByteStream\StreamException; use Amp\Deferred; use Amp\Dns\DnsException; use Amp\Dns\TimeoutException; use Amp\Promise; use LibDNS\Messages\Message; use LibDNS\Messages\MessageFactory; use LibDNS\Messages\MessageTypes; use LibDNS\Records\Question; use function Amp\call; /** @internal */ abstract class Socket { const MAX_CONCURRENT_REQUESTS = 500; /** @var ResourceInputStream */ private $input; /** @var ResourceOutputStream */ private $output; /** @var array Contains already sent queries with no response yet. For UDP this is exactly zero or one item. */ private $pending = []; /** @var MessageFactory */ private $messageFactory; /** @var callable */ private $onResolve; /** @var int Used for determining whether the socket can be garbage collected, because it's inactive. */ private $lastActivity; /** @var bool */ private $receiving = false; /** @var array Queued requests if the number of concurrent requests is too large. */ private $queue = []; /** * @param string $uri * * @return Promise<self> */ abstract public static function connect(string $uri): Promise; /** * @param Message $message * * @return Promise<int> */ abstract protected function send(Message $message): Promise; /** * @return Promise<Message> */ abstract protected function receive(): Promise; /** * @return bool */ abstract public function isAlive(): bool; public function getLastActivity(): int { return $this->lastActivity; } protected function __construct($socket) { $this->input = new ResourceInputStream($socket); $this->output = new ResourceOutputStream($socket); $this->messageFactory = new MessageFactory; $this->lastActivity = \time(); $this->onResolve = function (\Throwable $exception = null, Message $message = null) { $this->lastActivity = \time(); $this->receiving = false; if ($exception) { $this->error($exception); return; } \assert($message instanceof Message); $id = $message->getId(); // Ignore duplicate and invalid responses. if (isset($this->pending[$id]) && $this->matchesQuestion($message, $this->pending[$id]->question)) { /** @var Deferred $deferred */ $deferred = $this->pending[$id]->deferred; unset($this->pending[$id]); $deferred->resolve($message); } if (empty($this->pending)) { $this->input->unreference(); } elseif (!$this->receiving) { $this->input->reference(); $this->receiving = true; $this->receive()->onResolve($this->onResolve); } }; } /** * @param \LibDNS\Records\Question $question * @param int $timeout * * @return \Amp\Promise<\LibDNS\Messages\Message> */ final public function ask(Question $question, int $timeout): Promise { return call(function () use ($question, $timeout) { $this->lastActivity = \time(); if (\count($this->pending) > self::MAX_CONCURRENT_REQUESTS) { $deferred = new Deferred; $this->queue[] = $deferred; yield $deferred->promise(); } do { $id = \random_int(0, 0xffff); } while (isset($this->pending[$id])); $deferred = new Deferred; $pending = new class { use Amp\Struct; public $deferred; public $question; }; $pending->deferred = $deferred; $pending->question = $question; $this->pending[$id] = $pending; $message = $this->createMessage($question, $id); try { yield $this->send($message); } catch (StreamException $exception) { $exception = new DnsException("Sending the request failed", 0, $exception); $this->error($exception); throw $exception; } $this->input->reference(); if (!$this->receiving) { $this->receiving = true; $this->receive()->onResolve($this->onResolve); } try { // Work around an OPCache issue that returns an empty array with "return ...", // so assign to a variable first and return after the try block. // // See https://github.com/amphp/dns/issues/58. // See https://bugs.php.net/bug.php?id=74840. $result = yield Promise\timeout($deferred->promise(), $timeout); } catch (Amp\TimeoutException $exception) { unset($this->pending[$id]); if (empty($this->pending)) { $this->input->unreference(); } throw new TimeoutException("Didn't receive a response within {$timeout} milliseconds."); } finally { if ($this->queue) { $deferred = \array_shift($this->queue); $deferred->resolve(); } } return $result; }); } final public function close() { $this->input->close(); $this->output->close(); } private function error(\Throwable $exception) { $this->close(); if (empty($this->pending)) { return; } if (!$exception instanceof DnsException) { $message = "Unexpected error during resolution: " . $exception->getMessage(); $exception = new DnsException($message, 0, $exception); } $pending = $this->pending; $this->pending = []; foreach ($pending as $pendingQuestion) { /** @var Deferred $deferred */ $deferred = $pendingQuestion->deferred; $deferred->fail($exception); } } final protected function read(): Promise { return $this->input->read(); } final protected function write(string $data): Promise { return $this->output->write($data); } final protected function createMessage(Question $question, int $id): Message { $request = $this->messageFactory->create(MessageTypes::QUERY); $request->getQuestionRecords()->add($question); $request->isRecursionDesired(true); $request->setID($id); return $request; } private function matchesQuestion(Message $message, Question $question): bool { if ($message->getType() !== MessageTypes::RESPONSE) { return false; } $questionRecords = $message->getQuestionRecords(); // We only ever ask one question at a time if (\count($questionRecords) !== 1) { return false; } $questionRecord = $questionRecords->getIterator()->current(); if ($questionRecord->getClass() !== $question->getClass()) { return false; } if ($questionRecord->getType() !== $question->getType()) { return false; } if ($questionRecord->getName()->getValue() !== $question->getName()->getValue()) { return false; } return true; } } <?php namespace Amp\Dns\Internal; use Amp; use Amp\Deferred; use Amp\Dns\DnsException; use Amp\Dns\TimeoutException; use Amp\Loop; use Amp\Parser\Parser; use Amp\Promise; use Amp\Success; use LibDNS\Decoder\DecoderFactory; use LibDNS\Encoder\EncoderFactory; use LibDNS\Messages\Message; use function Amp\call; /** @internal */ final class TcpSocket extends Socket { /** @var \LibDNS\Encoder\Encoder */ private $encoder; /** @var \SplQueue */ private $queue; /** @var Parser */ private $parser; /** @var bool */ private $isAlive = true; public static function connect(string $uri, int $timeout = 5000): Promise { if (!$socket = @\stream_socket_client($uri, $errno, $errstr, 0, STREAM_CLIENT_ASYNC_CONNECT)) { throw new DnsException(\sprintf( "Connection to %s failed: [Error #%d] %s", $uri, $errno, $errstr )); } \stream_set_blocking($socket, false); return call(function () use ($uri, $socket, $timeout) { $deferred = new Deferred; $watcher = Loop::onWritable($socket, static function () use ($socket, $deferred) { $deferred->resolve(new self($socket)); }); try { return yield Promise\timeout($deferred->promise(), $timeout); } catch (Amp\TimeoutException $e) { throw new TimeoutException("Name resolution timed out, could not connect to server at $uri"); } finally { Loop::cancel($watcher); } }); } public static function parser(callable $callback): \Generator { $decoder = (new DecoderFactory)->create(); while (true) { $length = yield 2; $length = \unpack("n", $length)[1]; $rawData = yield $length; $callback($decoder->decode($rawData)); } } protected function __construct($socket) { parent::__construct($socket); $this->encoder = (new EncoderFactory)->create(); $this->queue = new \SplQueue; $this->parser = new Parser(self::parser([$this->queue, 'push'])); } protected function send(Message $message): Promise { $data = $this->encoder->encode($message); $promise = $this->write(\pack("n", \strlen($data)) . $data); $promise->onResolve(function ($error) { if ($error) { $this->isAlive = false; } }); return $promise; } protected function receive(): Promise { if ($this->queue->isEmpty()) { return call(function () { do { $chunk = yield $this->read(); if ($chunk === null) { $this->isAlive = false; throw new DnsException("Reading from the server failed"); } $this->parser->push($chunk); } while ($this->queue->isEmpty()); return $this->queue->shift(); }); } return new Success($this->queue->shift()); } public function isAlive(): bool { return $this->isAlive; } } <?php namespace Amp\Dns; use Amp\Failure; use Amp\Promise; use Amp\Success; use function Amp\call; class UnixConfigLoader implements ConfigLoader { private $path; private $hostLoader; public function __construct(string $path = "/etc/resolv.conf", HostLoader $hostLoader = null) { $this->path = $path; $this->hostLoader = $hostLoader ?? new HostLoader; } protected function readFile(string $path): Promise { \set_error_handler(function (int $errno, string $message) use ($path) { throw new ConfigException("Could not read configuration file '{$path}' ({$errno}) $message"); }); try { // Blocking file access, but this file should be local and usually loaded only once. $fileContent = \file_get_contents($path); } catch (ConfigException $exception) { return new Failure($exception); } finally { \restore_error_handler(); } return new Success($fileContent); } final public function loadConfig(): Promise { return call(function () { $nameservers = []; $timeout = 3000; $attempts = 2; $fileContent = yield $this->readFile($this->path); $lines = \explode("\n", $fileContent); foreach ($lines as $line) { $line = \preg_split('#\s+#', $line, 2); if (\count($line) !== 2) { continue; } list($type, $value) = $line; if ($type === "nameserver") { $value = \trim($value); $ip = @\inet_pton($value); if ($ip === false) { continue; } if (isset($ip[15])) { // IPv6 $nameservers[] = "[" . $value . "]:53"; } else { // IPv4 $nameservers[] = $value . ":53"; } } elseif ($type === "options") { $optline = \preg_split('#\s+#', $value, 2); if (\count($optline) !== 2) { continue; } list($option, $value) = $optline; switch ($option) { case "timeout": $timeout = (int) $value; break; case "attempts": $attempts = (int) $value; } } } $hosts = yield $this->hostLoader->loadHosts(); return new Config($nameservers, $hosts, $timeout, $attempts); }); } } <?php namespace Amp\Dns; use Amp\Cache\ArrayCache; use Amp\Cache\Cache; use Amp\Dns\Internal\Socket; use Amp\Dns\Internal\TcpSocket; use Amp\Dns\Internal\UdpSocket; use Amp\Loop; use Amp\MultiReasonException; use Amp\Promise; use Amp\Success; use LibDNS\Messages\Message; use LibDNS\Records\Question; use LibDNS\Records\QuestionFactory; use function Amp\call; final class Rfc1035StubResolver implements Resolver { const CACHE_PREFIX = "amphp.dns."; const CONFIG_NOT_LOADED = 0; const CONFIG_LOADED = 1; const CONFIG_FAILED = 2; /** @var \Amp\Dns\ConfigLoader */ private $configLoader; /** @var \LibDNS\Records\QuestionFactory */ private $questionFactory; /** @var \Amp\Dns\Config|null */ private $config; /** @var int */ private $configStatus = self::CONFIG_NOT_LOADED; /** @var Promise|null */ private $pendingConfig; /** @var Cache */ private $cache; /** @var Socket[] */ private $sockets = []; /** @var Promise[] */ private $pendingSockets = []; /** @var Promise[] */ private $pendingQueries = []; /** @var string */ private $gcWatcher; public function __construct(Cache $cache = null, ConfigLoader $configLoader = null) { $this->cache = $cache ?? new ArrayCache(5000/* default gc interval */, 256/* size */); $this->configLoader = $configLoader ?? (\stripos(PHP_OS, "win") === 0 ? new WindowsConfigLoader : new UnixConfigLoader); $this->questionFactory = new QuestionFactory; $sockets = &$this->sockets; $this->gcWatcher = Loop::repeat(5000, static function () use (&$sockets) { if (!$sockets) { return; } $now = \time(); foreach ($sockets as $key => $server) { if ($server->getLastActivity() < $now - 60) { $server->close(); unset($sockets[$key]); } } }); Loop::unreference($this->gcWatcher); } public function __destruct() { Loop::cancel($this->gcWatcher); } /** @inheritdoc */ public function resolve(string $name, int $typeRestriction = null): Promise { if ($typeRestriction !== null && $typeRestriction !== Record::A && $typeRestriction !== Record::AAAA) { throw new \Error("Invalid value for parameter 2: null|Record::A|Record::AAAA expected"); } return call(function () use ($name, $typeRestriction) { if (!$this->configStatus) { try { yield $this->reloadConfig(); } catch (ConfigException $e) { $this->configStatus = self::CONFIG_FAILED; } } if ($this->configStatus === self::CONFIG_FAILED) { if (!\in_array($typeRestriction, [Record::A, null])) { return []; } $result = \gethostbynamel($name); if ($result === false) { return []; } foreach ($result as &$record) { $record = new Record($record, Record::A, null); } return $result; } switch ($typeRestriction) { case Record::A: if (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return [new Record($name, Record::A, null)]; } elseif (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { throw new DnsException("Got an IPv6 address, but type is restricted to IPv4"); } break; case Record::AAAA: if (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return [new Record($name, Record::AAAA, null)]; } elseif (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { throw new DnsException("Got an IPv4 address, but type is restricted to IPv6"); } break; default: if (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return [new Record($name, Record::A, null)]; } elseif (\filter_var($name, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return [new Record($name, Record::AAAA, null)]; } break; } $name = normalizeName($name); if ($records = $this->queryHosts($name, $typeRestriction)) { return $records; } // Follow RFC 6761 and never send queries for localhost to the caching DNS server // Usually, these queries are already resolved via queryHosts() if ($name === 'localhost') { return $typeRestriction === Record::AAAA ? [new Record('::1', Record::AAAA, null)] : [new Record('127.0.0.1', Record::A, null)]; } for ($redirects = 0; $redirects < 5; $redirects++) { try { if ($typeRestriction) { $records = yield $this->query($name, $typeRestriction); } else { try { list(, $records) = yield Promise\some([ $this->query($name, Record::A), $this->query($name, Record::AAAA), ]); $records = \array_merge(...$records); break; // Break redirect loop, otherwise we query the same records 5 times } catch (MultiReasonException $e) { $errors = []; foreach ($e->getReasons() as $reason) { if ($reason instanceof NoRecordException) { throw $reason; } $errors[] = $reason->getMessage(); } throw new DnsException("All query attempts failed for {$name}: ".\implode(", ", $errors), 0, $e); } } } catch (NoRecordException $e) { try { /** @var Record[] $cnameRecords */ $cnameRecords = yield $this->query($name, Record::CNAME); $name = $cnameRecords[0]->getValue(); continue; } catch (NoRecordException $e) { /** @var Record[] $dnameRecords */ $dnameRecords = yield $this->query($name, Record::DNAME); $name = $dnameRecords[0]->getValue(); continue; } } } return $records; }); } /** * Reloads the configuration in the background. * * Once it's finished, the configuration will be used for new requests. * * @return Promise */ public function reloadConfig(): Promise { if ($this->pendingConfig) { return $this->pendingConfig; } $promise = call(function () { $this->config = yield $this->configLoader->loadConfig(); $this->configStatus = self::CONFIG_LOADED; }); $this->pendingConfig = $promise; $promise->onResolve(function () { $this->pendingConfig = null; }); return $promise; } private function queryHosts(string $name, int $typeRestriction = null): array { $hosts = $this->config->getKnownHosts(); $records = []; $returnIPv4 = $typeRestriction === null || $typeRestriction === Record::A; $returnIPv6 = $typeRestriction === null || $typeRestriction === Record::AAAA; if ($returnIPv4 && isset($hosts[Record::A][$name])) { $records[] = new Record($hosts[Record::A][$name], Record::A, null); } if ($returnIPv6 && isset($hosts[Record::AAAA][$name])) { $records[] = new Record($hosts[Record::AAAA][$name], Record::AAAA, null); } return $records; } /** @inheritdoc */ public function query(string $name, int $type): Promise { $pendingQueryKey = $type." ".$name; if (isset($this->pendingQueries[$pendingQueryKey])) { return $this->pendingQueries[$pendingQueryKey]; } $promise = call(function () use ($name, $type) { if (!$this->configStatus) { try { yield $this->reloadConfig(); } catch (ConfigException $e) { $this->configStatus = self::CONFIG_FAILED; } } if ($this->configStatus === self::CONFIG_FAILED) { if ($type !== Record::A) { throw new NoRecordException("No records returned for '{$name}' (".Record::getName($type).")"); } $result = \gethostbynamel($name); if ($result === false || $result === []) { throw new NoRecordException("No records returned for '{$name}' (".Record::getName($type).")"); } foreach ($result as &$record) { $record = new Record($record, Record::A, null); } return $result; } $name = $this->normalizeName($name, $type); $question = $this->createQuestion($name, $type); if (null !== $cachedValue = yield $this->cache->get($this->getCacheKey($name, $type))) { return $this->decodeCachedResult($name, $type, $cachedValue); } $nameservers = $this->config->getNameservers(); $attempts = $this->config->getAttempts(); $protocol = "udp"; $attempt = 0; /** @var Socket $socket */ $uri = $protocol."://".$nameservers[0]; $socket = yield $this->getSocket($uri); $attemptDescription = []; while ($attempt < $attempts) { try { if (!$socket->isAlive()) { unset($this->sockets[$uri]); $socket->close(); /** @var Socket $server */ $i = $attempt % \count($nameservers); $uri = $protocol."://".$nameservers[$i]; $socket = yield $this->getSocket($uri); } $attemptDescription[] = $uri; /** @var Message $response */ $response = yield $socket->ask($question, $this->config->getTimeout()); $this->assertAcceptableResponse($response); // UDP sockets are never reused, they're not in the $this->sockets map if ($protocol === "udp") { // Defer call, because it interferes with the unreference() call in Internal\Socket otherwise Loop::defer(function () use ($socket) { $socket->close(); }); } if ($response->isTruncated()) { if ($protocol !== "tcp") { // Retry with TCP, don't count attempt $protocol = "tcp"; $i = $attempt % \count($nameservers); $uri = $protocol."://".$nameservers[$i]; $socket = yield $this->getSocket($uri); continue; } throw new DnsException("Server returned a truncated response for '{$name}' (".Record::getName($type).")"); } $answers = $response->getAnswerRecords(); $result = []; $ttls = []; /** @var \LibDNS\Records\Resource $record */ foreach ($answers as $record) { $recordType = $record->getType(); $result[$recordType][] = (string) $record->getData(); // Cache for max one day $ttls[$recordType] = \min($ttls[$recordType] ?? 86400, $record->getTTL()); } foreach ($result as $recordType => $records) { // We don't care here whether storing in the cache fails $this->cache->set($this->getCacheKey($name, $recordType), \json_encode($records), $ttls[$recordType]); } if (!isset($result[$type])) { // "it MUST NOT cache it for longer than five (5) minutes" per RFC 2308 section 7.1 $this->cache->set($this->getCacheKey($name, $type), \json_encode([]), 300); throw new NoRecordException("No records returned for '{$name}' (".Record::getName($type).")"); } return \array_map(function ($data) use ($type, $ttls) { return new Record($data, $type, $ttls[$type]); }, $result[$type]); } catch (TimeoutException $e) { // Defer call, because it might interfere with the unreference() call in Internal\Socket otherwise Loop::defer(function () use ($socket, $uri) { unset($this->sockets[$uri]); $socket->close(); }); $i = ++$attempt % \count($nameservers); $uri = $protocol."://".$nameservers[$i]; $socket = yield $this->getSocket($uri); continue; } } throw new TimeoutException(\sprintf( "No response for '%s' (%s) from any nameserver after %d attempts, tried %s", $name, Record::getName($type), $attempts, \implode(", ", $attemptDescription) )); }); $this->pendingQueries[$type." ".$name] = $promise; $promise->onResolve(function () use ($name, $type) { unset($this->pendingQueries[$type." ".$name]); }); return $promise; } private function normalizeName(string $name, int $type) { if ($type === Record::PTR) { if (($packedIp = @\inet_pton($name)) !== false) { if (isset($packedIp[4])) { // IPv6 $name = \wordwrap(\strrev(\bin2hex($packedIp)), 1, ".", true).".ip6.arpa"; } else { // IPv4 $name = \inet_ntop(\strrev($packedIp)).".in-addr.arpa"; } } } elseif (\in_array($type, [Record::A, Record::AAAA])) { $name = normalizeName($name); } return $name; } /** * @param string $name * @param int $type * * @return \LibDNS\Records\Question */ private function createQuestion(string $name, int $type): Question { if (0 > $type || 0xffff < $type) { $message = \sprintf('%d does not correspond to a valid record type (must be between 0 and 65535).', $type); throw new \Error($message); } $question = $this->questionFactory->create($type); $question->setName($name); return $question; } private function getCacheKey(string $name, int $type): string { return self::CACHE_PREFIX.$name."#".$type; } private function decodeCachedResult(string $name, int $type, string $encoded) { $decoded = \json_decode($encoded, true); if (!$decoded) { throw new NoRecordException("No records returned for {$name} (cached result)"); } $result = []; foreach ($decoded as $data) { $result[] = new Record($data, $type); } return $result; } private function getSocket($uri): Promise { // We use a new socket for each UDP request, as that increases the entropy and mitigates response forgery. if (\substr($uri, 0, 3) === "udp") { return UdpSocket::connect($uri); } // Over TCP we might reuse sockets if the server allows to keep them open. Sequence IDs in TCP are already // better than a random port. Additionally, a TCP connection is more expensive. if (isset($this->sockets[$uri])) { return new Success($this->sockets[$uri]); } if (isset($this->pendingSockets[$uri])) { return $this->pendingSockets[$uri]; } $server = TcpSocket::connect($uri); $server->onResolve(function ($error, $server) use ($uri) { unset($this->pendingSockets[$uri]); if (!$error) { $this->sockets[$uri] = $server; } }); return $server; } private function assertAcceptableResponse(Message $response) { if ($response->getResponseCode() !== 0) { throw new DnsException(\sprintf("Server returned error code: %d", $response->getResponseCode())); } } } <?php namespace Amp\Dns; use Amp\Loop; use Amp\Promise; const LOOP_STATE_IDENTIFIER = Resolver::class; /** * Retrieve the application-wide dns resolver instance. * * @param \Amp\Dns\Resolver $resolver Optionally specify a new default dns resolver instance * * @return \Amp\Dns\Resolver Returns the application-wide dns resolver instance */ function resolver(Resolver $resolver = null): Resolver { if ($resolver === null) { $resolver = Loop::getState(LOOP_STATE_IDENTIFIER); if ($resolver) { return $resolver; } $resolver = createDefaultResolver(); } Loop::setState(LOOP_STATE_IDENTIFIER, $resolver); return $resolver; } /** * Create a new dns resolver best-suited for the current environment. * * @return \Amp\Dns\Resolver */ function createDefaultResolver(): Resolver { return new Rfc1035StubResolver; } /** * @see Resolver::resolve() */ function resolve(string $name, int $typeRestriction = null): Promise { return resolver()->resolve($name, $typeRestriction); } /** * @see Resolver::query() */ function query(string $name, int $type): Promise { return resolver()->query($name, $type); } /** * Checks whether a string is a valid DNS name. * * @param string $name String to check. * * @return bool */ function isValidName(string $name) { try { normalizeName($name); return true; } catch (InvalidNameException $e) { return false; } } /** * Normalizes a DNS name and automatically checks it for validity. * * @param string $name DNS name. * * @return string Normalized DNS name. * @throws InvalidNameException If an invalid name or an IDN name without ext/intl being installed has been passed. */ function normalizeName(string $name): string { static $pattern = '/^(?<name>[a-z0-9]([a-z0-9-_]{0,61}[a-z0-9])?)(\.(?&name))*$/i'; if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) { if (false === $result = \idn_to_ascii($name, 0, \INTL_IDNA_VARIANT_UTS46)) { throw new InvalidNameException("Name '{$name}' could not be processed for IDN."); } $name = $result; } elseif (\preg_match('/[\x80-\xff]/', $name)) { throw new InvalidNameException( "Name '{$name}' contains non-ASCII characters and IDN support is not available. " . "Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6." ); } if (isset($name[253]) || !\preg_match($pattern, $name)) { throw new InvalidNameException("Name '{$name}' is not a valid hostname."); } return $name; } <?php namespace Amp\Dns; use Throwable; /** * MUST be thrown in case the config can't be read and no fallback is available. */ class ConfigException extends DnsException { public function __construct(string $message, Throwable $previous = null) { parent::__construct($message, 0, $previous); } } <?php namespace Amp\Dns; use Amp\Promise; interface ConfigLoader { public function loadConfig(): Promise; } <?php namespace Amp\Dns; use Amp\Promise; interface Resolver { /** * Resolves a hostname name to an IP address [hostname as defined by RFC 3986]. * * Upon success the returned promise resolves to an array of Record objects. * * A null $ttl value indicates the DNS name was resolved from the cache or the local hosts file. * * @param string $name The hostname to resolve. * @param int $typeRestriction Optional type restriction to `Record::A` or `Record::AAAA`, otherwise `null`. * * @return Promise */ public function resolve(string $name, int $typeRestriction = null): Promise; /** * Query specific DNS records. * * Upon success the returned promise resolves to an array of Record objects. * * @param string $name Record to question, A, AAAA and PTR queries are automatically normalized. * @param int $type Use constants of Amp\Dns\Record. * * @return Promise */ public function query(string $name, int $type): Promise; } <?php namespace Amp\Dns; class InvalidNameException extends DnsException { } <?php namespace Amp\Dns; use Amp\Failure; use Amp\Promise; use Amp\Success; use function Amp\call; class HostLoader { private $path; public function __construct(string $path = null) { $this->path = $path ?? $this->getDefaultPath(); } private function getDefaultPath(): string { return \stripos(PHP_OS, "win") === 0 ? 'C:\Windows\system32\drivers\etc\hosts' : '/etc/hosts'; } protected function readFile(string $path): Promise { \set_error_handler(function (int $errno, string $message) use ($path) { throw new ConfigException("Could not read configuration file '{$path}' ({$errno}) $message"); }); try { // Blocking file access, but this file should be local and usually loaded only once. $fileContent = \file_get_contents($path); } catch (ConfigException $exception) { return new Failure($exception); } finally { \restore_error_handler(); } return new Success($fileContent); } public function loadHosts(): Promise { return call(function () { try { $contents = yield $this->readFile($this->path); } catch (ConfigException $exception) { return []; } $data = []; $lines = \array_filter(\array_map("trim", \explode("\n", $contents))); foreach ($lines as $line) { if ($line[0] === "#") { // Skip comments continue; } $parts = \preg_split('/\s+/', $line); if (!($ip = @\inet_pton($parts[0]))) { continue; } elseif (isset($ip[4])) { $key = Record::AAAA; } else { $key = Record::A; } for ($i = 1, $l = \count($parts); $i < $l; $i++) { try { $normalizedName = normalizeName($parts[$i]); $data[$key][$normalizedName] = $parts[0]; } catch (InvalidNameException $e) { // ignore invalid entries } } } return $data; }); } } <?php namespace Amp\Dns; class NoRecordException extends DnsException { } <?php namespace Amp\Dns; use LibDNS\Records\ResourceQTypes; use LibDNS\Records\ResourceTypes; final class Record { const A = ResourceTypes::A; const AAAA = ResourceTypes::AAAA; const AFSDB = ResourceTypes::AFSDB; // const APL = ResourceTypes::APL; const CAA = ResourceTypes::CAA; const CERT = ResourceTypes::CERT; const CNAME = ResourceTypes::CNAME; const DHCID = ResourceTypes::DHCID; const DLV = ResourceTypes::DLV; const DNAME = ResourceTypes::DNAME; const DNSKEY = ResourceTypes::DNSKEY; const DS = ResourceTypes::DS; const HINFO = ResourceTypes::HINFO; // const HIP = ResourceTypes::HIP; // const IPSECKEY = ResourceTypes::IPSECKEY; const KEY = ResourceTypes::KEY; const KX = ResourceTypes::KX; const ISDN = ResourceTypes::ISDN; const LOC = ResourceTypes::LOC; const MB = ResourceTypes::MB; const MD = ResourceTypes::MD; const MF = ResourceTypes::MF; const MG = ResourceTypes::MG; const MINFO = ResourceTypes::MINFO; const MR = ResourceTypes::MR; const MX = ResourceTypes::MX; const NAPTR = ResourceTypes::NAPTR; const NS = ResourceTypes::NS; // const NSEC = ResourceTypes::NSEC; // const NSEC3 = ResourceTypes::NSEC3; // const NSEC3PARAM = ResourceTypes::NSEC3PARAM; const NULL = ResourceTypes::NULL; const PTR = ResourceTypes::PTR; const RP = ResourceTypes::RP; // const RRSIG = ResourceTypes::RRSIG; const RT = ResourceTypes::RT; const SIG = ResourceTypes::SIG; const SOA = ResourceTypes::SOA; const SPF = ResourceTypes::SPF; const SRV = ResourceTypes::SRV; const TXT = ResourceTypes::TXT; const WKS = ResourceTypes::WKS; const X25 = ResourceTypes::X25; const AXFR = ResourceQTypes::AXFR; const MAILB = ResourceQTypes::MAILB; const MAILA = ResourceQTypes::MAILA; const ALL = ResourceQTypes::ALL; private $value; private $type; private $ttl; public function __construct(string $value, int $type, int $ttl = null) { $this->value = $value; $this->type = $type; $this->ttl = $ttl; } public function getValue(): string { return $this->value; } public function getType(): int { return $this->type; } public function getTtl() { return $this->ttl; } /** * Converts an record type integer back into its name as defined in this class. * * Returns "unknown (<type>)" in case a name for this record is not known. * * @param int $type Record type as integer. * * @return string Name of the constant for this record in this class. */ public static function getName(int $type): string { static $types; if (0 > $type || 0xffff < $type) { $message = \sprintf('%d does not correspond to a valid record type (must be between 0 and 65535).', $type); throw new \Error($message); } if ($types === null) { $types = \array_flip( (new \ReflectionClass(self::class)) ->getConstants() ); } return $types[$type] ?? "unknown ({$type})"; } } <?php namespace Amp\Dns; final class Config { private $nameservers; private $knownHosts; private $timeout; private $attempts; public function __construct(array $nameservers, array $knownHosts = [], int $timeout = 3000, int $attempts = 2) { if (\count($nameservers) < 1) { throw new ConfigException("At least one nameserver is required for a valid config"); } foreach ($nameservers as $nameserver) { $this->validateNameserver($nameserver); } if ($timeout < 0) { throw new ConfigException("Invalid timeout ({$timeout}), must be 0 or greater"); } if ($attempts < 1) { throw new ConfigException("Invalid attempt count ({$attempts}), must be 1 or greater"); } // Windows does not include localhost in its host file. Fetch it from the system instead if (!isset($knownHosts[Record::A]["localhost"]) && !isset($knownHosts[Record::AAAA]["localhost"])) { // PHP currently provides no way to **resolve** IPv6 hostnames (not even with fallback) $local = \gethostbyname("localhost"); if ($local !== "localhost") { $knownHosts[Record::A]["localhost"] = $local; } else { $knownHosts[Record::AAAA]["localhost"] = '::1'; } } $this->nameservers = $nameservers; $this->knownHosts = $knownHosts; $this->timeout = $timeout; $this->attempts = $attempts; } private function validateNameserver($nameserver) { if (!$nameserver || !\is_string($nameserver)) { throw new ConfigException("Invalid nameserver: {$nameserver}"); } if ($nameserver[0] === "[") { // IPv6 $addr = \strstr(\substr($nameserver, 1), "]", true); $port = \substr($nameserver, \strrpos($nameserver, "]") + 1); if ($port !== "" && !\preg_match("(^:(\\d+)$)", $port, $match)) { throw new ConfigException("Invalid nameserver: {$nameserver}"); } $port = $port === "" ? 53 : \substr($port, 1); } else { // IPv4 $arr = \explode(":", $nameserver, 2); if (\count($arr) === 2) { list($addr, $port) = $arr; } else { $addr = $arr[0]; $port = 53; } } $addr = \trim($addr, "[]"); $port = (int) $port; if (!$inAddr = @\inet_pton($addr)) { throw new ConfigException("Invalid server IP: {$addr}"); } if ($port < 1 || $port > 65535) { throw new ConfigException("Invalid server port: {$port}"); } } public function getNameservers(): array { return $this->nameservers; } public function getKnownHosts(): array { return $this->knownHosts; } public function getTimeout(): int { return $this->timeout; } public function getAttempts(): int { return $this->attempts; } } <?php namespace Amp\Dns; use Amp\Promise; use Amp\WindowsRegistry\KeyNotFoundException; use Amp\WindowsRegistry\WindowsRegistry; use function Amp\call; final class WindowsConfigLoader implements ConfigLoader { private $hostLoader; public function __construct(HostLoader $hostLoader = null) { $this->hostLoader = $hostLoader ?? new HostLoader; } public function loadConfig(): Promise { return call(function () { $keys = [ "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\NameServer", "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\DhcpNameServer", ]; $reader = new WindowsRegistry; $nameserver = ""; while ($nameserver === "" && ($key = \array_shift($keys))) { try { $nameserver = yield $reader->read($key); } catch (KeyNotFoundException $e) { // retry other possible locations } } if ($nameserver === "") { $interfaces = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; $subKeys = yield $reader->listKeys($interfaces); foreach ($subKeys as $key) { foreach (["NameServer", "DhcpNameServer"] as $property) { try { $nameserver = yield $reader->read("{$key}\\{$property}"); if ($nameserver !== "") { break 2; } } catch (KeyNotFoundException $e) { // retry other possible locations } } } } if ($nameserver === "") { throw new ConfigException("Could not find a nameserver in the Windows Registry"); } $nameservers = []; // Microsoft documents space as delimiter, AppVeyor uses comma, we just accept both foreach (\explode(" ", \strtr($nameserver, ",", " ")) as $nameserver) { $nameserver = \trim($nameserver); $ip = @\inet_pton($nameserver); if ($ip === false) { continue; } if (isset($ip[15])) { // IPv6 $nameservers[] = "[" . $nameserver . "]:53"; } else { // IPv4 $nameservers[] = $nameserver . ":53"; } } $hosts = yield $this->hostLoader->loadHosts(); return new Config($nameservers, $hosts); }); } } { "name": "amphp/uri", "homepage": "https://github.com/amphp/uri", "description": "Uri Parser and Resolver.", "license": "MIT", "authors": [ { "name": "Daniel Lowrey" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "support": { "issues": "https://github.com/amphp/uri/issues" }, "require-dev": { "phpunit/phpunit": "^6", "friendsofphp/php-cs-fixer": "^2.3" }, "autoload": { "psr-4": { "Amp\\Uri\\": "src" }, "files": [ "src/functions.php" ] } } <?php namespace Amp\Uri; class InvalidDnsNameException extends \Exception { } <?php namespace Amp\Uri; /** * Checks whether a string is a valid DNS name. * * @param string $name String to check. * * @return bool */ function isValidDnsName(string $name) { try { normalizeDnsName($name); return true; } catch (InvalidDnsNameException $e) { return false; } } /** * Normalizes a DNS name and automatically checks it for validity. * * @param string $name DNS name. * * @return string Normalized DNS name. * * @throws InvalidDnsNameException If an invalid name or an IDN name without ext/intl being installed has been passed. */ function normalizeDnsName(string $name): string { static $pattern = '/^(?<name>[a-z0-9]([a-z0-9-_]{0,61}[a-z0-9])?)(\.(?&name))*\.?$/i'; if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) { if (false === $result = \idn_to_ascii($name, 0, \INTL_IDNA_VARIANT_UTS46)) { throw new InvalidDnsNameException("Name '{$name}' could not be processed for IDN."); } $name = $result; } else { if (\preg_match('/[\x80-\xff]/', $name)) { throw new InvalidDnsNameException( "Name '{$name}' contains non-ASCII characters and IDN support is not available. " . "Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6." ); } } if (isset($name[253]) || !\preg_match($pattern, $name)) { throw new InvalidDnsNameException("Name '{$name}' is not a valid hostname."); } if ($name[strlen($name)-1] === '.') { $name = substr($name, 0, -1); } return $name; } <?php namespace Amp\Uri; /** * Provides URI parsing and can resolve URIs. */ final class Uri { private $defaultPortMap = [ "http" => 80, "https" => 443, "ftp" => 21, "ftps" => 990, "smtp" => 25, ]; private $uri; private $scheme = ''; private $user = ''; private $pass = ''; private $host = ''; private $port = 0; private $path = ''; private $query = ''; private $fragment = ''; private $queryParameters = []; private $isIpV4 = false; private $isIpV6 = false; public function __construct(string $uri) { /** @var false|array $parts */ if (!$parts = parse_url($uri)) { throw new InvalidUriException( 'Invalid URI specified at ' . self::class . '::__construct Argument 1: ' . $uri ); } $this->uri = $uri; foreach ($parts as $key => $value) { $this->{$key} = $value; } // http://www.apps.ietf.org/rfc/rfc3986.html#sec-3.1 // "schemes are case-insensitive" $this->scheme = \strtolower($this->scheme); // http://www.apps.ietf.org/rfc/rfc3986.html#sec-3.2.2 // "Although host is case-insensitive, producers and normalizers should use lowercase for // registered names and hexadecimal addresses for the sake of uniformity" if ($inAddr = @\inet_pton(\trim($this->host, "[]"))) { $this->host = \strtolower($this->host); if (isset($inAddr[4])) { $this->isIpV6 = true; } else { $this->isIpV4 = true; } } elseif ($this->host) { try { $this->host = normalizeDnsName($this->host); } catch (InvalidDnsNameException $e) { throw new InvalidUriException("Invalid URI: Invalid host: {$this->host}", 0, $e); } } if ($this->port === 0) { if (isset($this->defaultPortMap[$this->scheme])) { $this->port = $this->defaultPortMap[$this->scheme]; } } $this->parseQueryParameters(); if ($this->fragment) { $this->fragment = rawurldecode($this->fragment); $this->fragment = rawurlencode($this->fragment); } } public function __toString() { return $this->reconstitute( $this->scheme, $this->getAuthority(), $this->path, $this->query, $this->fragment ); } /** * @see http://tools.ietf.org/html/rfc3986#section-5.3 */ private function reconstitute($scheme, $authority, $path, $query, $fragment): string { $result = ''; if ($scheme) { $result .= $scheme . ':'; } if ($authority) { $result .= '//'; $result .= $authority; } $result .= $path; if ($query) { $result .= '?'; $result .= $query; } if ($fragment) { $result .= '#'; $result .= $fragment; } return $result; } /** * Normalizes the URI for maximal comparison success. * * @return string */ public function normalize(): string { if (!$this->uri) { return ''; } $path = $this->path ?: '/'; $path = $this->removeDotSegments($path); $path = $this->decodeUnreservedCharacters($path); $path = $this->decodeReservedSubDelimiters($path); return $this->reconstitute( $this->scheme, $this->getAuthority(), $path, $this->query, $this->fragment ); } /** * "URI producers and normalizers should omit the port component and its ":" delimiter if port * is empty or if its value would be the same as that of the scheme's default". * * @see http://www.apps.ietf.org/rfc/rfc3986.html#sec-3.2.3 */ private function getNormalizedDefaultPort(): string { if ($this->port === 0) { return ""; } if (isset($this->defaultPortMap[$this->scheme])) { $defaultPort = $this->defaultPortMap[$this->scheme]; if ($defaultPort === $this->port) { return ""; } } return ":" . $this->port; } /** * @param string $input * * @return string * * @link http://www.apps.ietf.org/rfc/rfc3986.html#sec-5.2.4 */ private function removeDotSegments(string $input): string { $output = ''; $patternA = ',^(\.\.?/),'; $patternB1 = ',^(/\./),'; $patternB2 = ',^(/\.)$,'; $patternC = ',^(/\.\./|/\.\.),'; // $patternD = ',^(\.\.?)$,'; $patternE = ',(/*[^/]*),'; while ($input !== '') { if (\preg_match($patternA, $input)) { $input = \preg_replace($patternA, '', $input); } elseif (\preg_match($patternB1, $input, $match) || \preg_match($patternB2, $input, $match)) { $input = preg_replace(",^" . $match[1] . ",", '/', $input); } elseif (\preg_match($patternC, $input, $match)) { $input = \preg_replace(',^' . \preg_quote($match[1], ',') . ',', '/', $input); $output = \preg_replace(',/([^/]+)$,', '', $output); } elseif ($input === '.' || $input === '..') { // pattern D $input = ''; } elseif (\preg_match($patternE, $input, $match)) { $initialSegment = $match[1]; $input = \preg_replace(',^' . \preg_quote($initialSegment, ',') . ',', '', $input, 1); $output .= $initialSegment; } } return $output; } /** * @see http://www.apps.ietf.org/rfc/rfc3986.html#sec-2.3 */ private function decodeUnreservedCharacters($str) { $str = \rawurldecode($str); $str = \rawurlencode($str); $encoded = ['%2F', '%3A', '%40']; $decoded = ['/', ':', '@']; return \str_replace($encoded, $decoded, $str); } /** * @see http://www.apps.ietf.org/rfc/rfc3986.html#sec-2.2 */ private function decodeReservedSubDelimiters($str) { $encoded = ['%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D']; $decoded = ['!', '$', '&', "'", '(', ')', '*', '+', ',', ';', '=']; return \str_replace($encoded, $decoded, $str); } /** * @param string $toResolve * * @return Uri * * @see http://tools.ietf.org/html/rfc3986#section-5.2.2 */ public function resolve(string $toResolve) { $r = new Uri($toResolve); if ((string) $r === '') { return clone $this; } $base = $this; $t = new \stdClass; $t->scheme = ''; $t->authority = ''; $t->path = ''; $t->query = ''; $t->fragment = ''; if ('' !== $r->getScheme()) { $t->scheme = $r->getScheme(); $t->authority = $r->getAuthority(); $t->path = $this->removeDotSegments($r->getPath()); $t->query = $r->getQuery(); } else { if ('' !== $r->getAuthority()) { $t->authority = $r->getAuthority(); $t->path = $this->removeDotSegments($r->getPath()); $t->query = $r->getQuery(); } else { if ('' === $r->getPath()) { $t->path = $base->getPath(); if ($r->getQuery()) { $t->query = $r->getQuery(); } else { $t->query = $base->getQuery(); }; } else { if ($r->getPath() && substr($r->getPath(), 0, 1) === "/") { $t->path = $this->removeDotSegments($r->getPath()); } else { $t->path = $this->mergePaths($base->getPath(), $r->getPath()); }; $t->query = $r->getQuery(); }; $t->authority = $base->getAuthority(); }; $t->scheme = $base->getScheme(); }; $t->fragment = $r->getFragment(); $result = $this->reconstitute($t->scheme, $t->authority, $t->path, $t->query, $t->fragment); return new Uri($result); } /** * @link http://tools.ietf.org/html/rfc3986#section-5.2.3 */ private function mergePaths($basePath, $pathToMerge) { if ($basePath === '') { $merged = '/' . $pathToMerge; } else { $parts = \explode('/', $basePath); \array_pop($parts); $parts[] = $pathToMerge; $merged = \implode('/', $parts); } return $this->removeDotSegments($merged); } /** * @return string */ public function getScheme(): string { return $this->scheme; } /** * @return string */ public function getUser(): string { return $this->user; } /** * @return string */ public function getPass(): string { return $this->pass; } /** * @return string */ public function getHost(): string { return $this->host; } /** * @return int */ public function getPort(): int { return $this->port; } /** * @return string */ public function getPath(): string { return $this->path; } /** * @return string */ public function getQuery(): string { return $this->query; } /** * @return string */ public function getFragment(): string { return $this->fragment; } /** * Retrieve the URI without the fragment component. */ public function getAbsoluteUri() { return $this->reconstitute( $this->scheme, $this->getAuthority(), $this->path, $this->query, $fragment = '' ); } /** * @return bool */ public function isIpV4(): bool { return $this->isIpV4; } /** * @return bool */ public function isIpV6(): bool { return $this->isIpV6; } /** * @param bool $hiddenPass Whether to hide the password. * * @return string * * @see http://www.apps.ietf.org/rfc/rfc3986.html#sec-3.2 */ public function getAuthority(bool $hiddenPass = true): string { $authority = $this->user; $authority .= $this->pass !== '' ? (':' . ($hiddenPass ? '********' : $this->pass)) : ''; $authority .= $authority ? '@' : ''; $authority .= $this->isIpV6 ? "[{$this->host}]" : $this->host; $authority .= $this->getNormalizedDefaultPort(); return $authority; } private function parseQueryParameters() { if ($this->query) { $parameters = []; foreach (\explode("&", $this->query) as $pair) { $pair = explode("=", $pair, 2); $parameters[\urldecode($pair[0])][] = \urldecode($pair[1] ?? ""); } $this->queryParameters = $parameters; } } /** * Check whether the specified query parameter exists. * * @param string $parameter * * @return bool */ public function hasQueryParameter(string $parameter): bool { return isset($this->queryParameters[$parameter]); } /** * Get the first occurrence of the specified query parameter. * * @param string $parameter * * @return string|null */ public function getQueryParameter(string $parameter) { return $this->queryParameters[$parameter][0] ?? null; } /** * Get all occurrences of the specified query parameter. * * @param string $parameter * * @return string[] */ public function getQueryParameterArray(string $parameter): array { return $this->queryParameters[$parameter] ?? []; } /** * @return array */ public function getAllQueryParameters(): array { return $this->queryParameters; } /** * @return string */ public function getOriginalUri(): string { return $this->uri; } /** * Test whether the specified string is a valid URI. * * @param string $uri * * @return bool */ public static function isValid(string $uri): bool { try { new self($uri); } catch (InvalidUriException $e) { return false; } return true; } } <?php namespace Amp\Uri; class InvalidUriException extends \Exception { } { "name": "amphp/sync", "description": "Mutex, Semaphore, and other synchronization tools for Amp.", "keywords": [ "asynchronous", "async", "mutex", "semaphore", "synchronization" ], "homepage": "https://github.com/amphp/sync", "license": "MIT", "authors": [ { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Stephen Coakley", "email": "me@stephencoakley.com" } ], "require": { "amphp/amp": "^2" }, "require-dev": { "phpunit/phpunit": "^6", "amphp/phpunit-util": "^1", "friendsofphp/php-cs-fixer": "^2.3" }, "autoload": { "psr-4": { "Amp\\Sync\\": "lib" }, "files": [ "lib/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Sync\\Test\\": "test" } } } <?php namespace Amp\Sync\Internal; use Amp\Delayed; use Amp\Promise; use Amp\Sync\Lock; use function Amp\call; class MutexStorage extends \Threaded { const LATENCY_TIMEOUT = 10; /** @var bool */ private $locked = false; /** * @return \Amp\Promise */ public function acquire(): Promise { return call(function () { $tsl = function () { if ($this->locked) { return true; } $this->locked = true; return false; }; while ($this->locked || $this->synchronized($tsl)) { yield new Delayed(self::LATENCY_TIMEOUT); } return new Lock(0, function () { $this->locked = false; }); }); } } <?php namespace Amp\Sync\Internal; use Amp\Delayed; use Amp\Promise; use Amp\Sync\Lock; use function Amp\call; class SemaphoreStorage extends \Threaded { const LATENCY_TIMEOUT = 10; /** * Creates a new semaphore with a given number of locks. * * @param int $locks The maximum number of locks that can be acquired from the semaphore. */ public function __construct(int $locks) { foreach (\range(0, $locks - 1) as $lock) { $this[] = $lock; } } /** * @return \Amp\Promise */ public function acquire(): Promise { /** * Uses a double locking mechanism to acquire a lock without blocking. A * synchronous mutex is used to make sure that the semaphore is queried one * at a time to preserve the integrity of the semaphore itself. Then a lock * count is used to check if a lock is available without blocking. * * If a lock is not available, we add the request to a queue and set a timer * to check again in the future. */ return call(function () { $tsl = function () { // If there are no locks available or the wait queue is not empty, // we need to wait our turn to acquire a lock. if (!$this->count()) { return null; } return $this->shift(); }; while (!$this->count() || ($id = $this->synchronized($tsl)) === null) { yield new Delayed(self::LATENCY_TIMEOUT); } return new Lock($id, function (Lock $lock) { $id = $lock->getId(); $this->synchronized(function () use ($id) { $this[] = $id; }); }); }); } } <?php namespace Amp\Sync; use Amp\Promise; use function Amp\call; /** * Invokes the given callback while maintaining a lock from the provided mutex. The lock is automatically released after * invoking the callback or once the promise returned by the callback is resolved. If the callback returns a Generator, * it will be run as a coroutine. See Amp\call(). * * @param \Amp\Sync\Mutex $mutex * @param callable $callback * @param ...$args * * @return \Amp\Promise Resolves with the return value of the callback. */ function synchronized(Mutex $mutex, callable $callback,...$args): Promise { return call(function () use ($mutex, $callback, $args) { /** @var \Amp\Sync\Lock $lock */ $lock = yield $mutex->acquire(); try { return yield call($callback,...$args); } finally { $lock->release(); } }); } <?php namespace Amp\Sync; use Amp\Promise; /** * A non-blocking counting semaphore. * * Objects that implement this interface should guarantee that all operations * are atomic. Implementations do not have to guarantee that acquiring a lock * is first-come, first serve. */ interface Semaphore { /** * Acquires a lock on the semaphore. * * @return \Amp\Promise<\Amp\Sync\Lock> Resolves with an integer keyed lock object. Identifiers returned by the * locks should be 0-indexed. Releasing an identifier MUST make that same identifier available. May fail with * a SyncException if an error occurs when attempting to obtain the lock (e.g. a shared memory segment closed). */ public function acquire(): Promise; } <?php namespace Amp\Sync; use Amp\Coroutine; use Amp\Delayed; use Amp\Promise; /** * A non-blocking, interprocess POSIX semaphore. * * Uses a POSIX message queue to store a queue of permits in a lock-free data structure. This semaphore implementation * is preferred over other implementations when available, as it provides the best performance. * * Not compatible with Windows. */ class PosixSemaphore implements Semaphore { const LATENCY_TIMEOUT = 10; /** @var string */ private $id; /** @var int The semaphore key. */ private $key; /** @var int PID of the process that created the semaphore. */ private $initializer = 0; /** @var resource A message queue of available locks. */ private $queue; /** * Creates a new semaphore with a given ID and number of locks. * * @param string $id The unique name for the new semaphore. * @param int $maxLocks The maximum number of locks that can be acquired from the semaphore. * @param int $permissions Permissions to access the semaphore. Use file permission format specified as 0xxx. * * @throws SyncException If the semaphore could not be created due to an internal error. */ public static function create(string $id, int $maxLocks, int $permissions = 0600): self { if ($maxLocks < 1) { throw new \Error("Number of locks must be greater than 0"); } $semaphore = new self($id); $semaphore->init($maxLocks, $permissions); return $semaphore; } /** * @param string $id The unique name of the semaphore to use. * * @return \Amp\Sync\PosixSemaphore */ public static function use(string $id): self { $semaphore = new self($id); $semaphore->open(); return $semaphore; } /** * @param string $id * * @throws \Error If the sysvmsg extension is not loaded. */ private function __construct(string $id) { if (!\extension_loaded("sysvmsg")) { throw new \Error(__CLASS__ . " requires the sysvmsg extension."); } $this->id = $id; $this->key = self::makeKey($this->id); } /** * Private method to prevent cloning. */ private function __clone() { } /** * Private to prevent serialization. */ private function __sleep() { } public function getId(): string { return $this->id; } private function open() { if (!\msg_queue_exists($this->key)) { throw new SyncException('No semaphore with that ID found'); } $this->queue = \msg_get_queue($this->key); if (!$this->queue) { throw new SyncException('Failed to open the semaphore.'); } } /** * @param int $maxLocks The maximum number of locks that can be acquired from the semaphore. * @param int $permissions Permissions to access the semaphore. * * @throws SyncException If the semaphore could not be created due to an internal error. */ private function init(int $maxLocks, int $permissions) { if (\msg_queue_exists($this->key)) { throw new SyncException('A semaphore with that ID already exists'); } $this->queue = \msg_get_queue($this->key, $permissions); if (!$this->queue) { throw new SyncException('Failed to create the semaphore.'); } $this->initializer = \getmypid(); // Fill the semaphore with locks. while (--$maxLocks >= 0) { $this->release($maxLocks); } } /** * Gets the access permissions of the semaphore. * * @return int A permissions mode. */ public function getPermissions(): int { $stat = \msg_stat_queue($this->queue); return $stat['msg_perm.mode']; } /** * Sets the access permissions of the semaphore. * * The current user must have access to the semaphore in order to change the permissions. * * @param int $mode A permissions mode to set. * * @throws SyncException If the operation failed. */ public function setPermissions(int $mode) { if (!\msg_set_queue($this->queue, [ 'msg_perm.mode' => $mode ])) { throw new SyncException('Failed to change the semaphore permissions.'); } } public function acquire(): Promise { return new Coroutine($this->doAcquire()); } /** * {@inheritdoc} */ private function doAcquire(): \Generator { do { // Attempt to acquire a lock from the semaphore. if (@\msg_receive($this->queue, 0, $type, 1, $id, false, \MSG_IPC_NOWAIT, $errno)) { // A free lock was found, so resolve with a lock object that can // be used to release the lock. return new Lock(\unpack("C", $id)[1], function (Lock $lock) { $this->release($lock->getId()); }); } // Check for unusual errors. if ($errno !== \MSG_ENOMSG) { throw new SyncException(\sprintf('Failed to acquire a lock; errno: %d', $errno)); } } while (yield new Delayed(self::LATENCY_TIMEOUT, true)); } /** * Removes the semaphore if it still exists. * * @throws SyncException If the operation failed. */ public function __destruct() { if ($this->initializer === 0 || $this->initializer !== \getmypid()) { return; } if (!\is_resource($this->queue) || !\msg_queue_exists($this->key)) { return; } \msg_remove_queue($this->queue); } /** * Releases a lock from the semaphore. * * @param int $id Lock identifier. * * @throws SyncException If the operation failed. */ protected function release(int $id) { if (!$this->queue) { return; // Queue already destroyed. } // Call send in non-blocking mode. If the call fails because the queue // is full, then the number of locks configured is too large. if (!@\msg_send($this->queue, 1, \pack("C", $id), false, false, $errno)) { if ($errno === \MSG_EAGAIN) { throw new SyncException('The semaphore size is larger than the system allows.'); } throw new SyncException('Failed to release the lock.'); } } private static function makeKey(string $id): int { return \abs(\unpack("l", \md5($id, true))[1]); } } <?php namespace Amp\Sync; use Amp\Coroutine; use Amp\Delayed; use Amp\Promise; /** * A cross-platform mutex that uses exclusive files as the lock mechanism. * * This mutex implementation is not always atomic and depends on the operating * system's implementation of file creation operations. Use this implementation * only if no other mutex types are available. * * This implementation avoids using [flock()](http://php.net/flock) * because flock() is known to have some atomicity issues on some systems. In * addition, flock() does not work as expected when trying to lock a file * multiple times in the same process on Linux. Instead, exclusive file creation * is used to create a lock file, which is atomic on most systems. * * @see http://php.net/fopen */ class FileMutex implements Mutex { const LATENCY_TIMEOUT = 10; /** @var string The full path to the lock file. */ private $fileName; /** * Creates a new mutex. * * @param string|null */ public function __construct(string $fileName) { $this->fileName = $fileName; } /** * {@inheritdoc} */ public function acquire(): Promise { return new Coroutine($this->doAcquire()); } /** * @coroutine * * @return \Generator */ private function doAcquire(): \Generator { // Try to create the lock file. If the file already exists, someone else // has the lock, so set an asynchronous timer and try again. while (($handle = @\fopen($this->fileName, 'x')) === false) { yield new Delayed(self::LATENCY_TIMEOUT); } // Return a lock object that can be used to release the lock on the mutex. $lock = new Lock(0, function () { $this->release(); }); \fclose($handle); return $lock; } /** * Releases the lock on the mutex. * * @throws SyncException If the unlock operation failed. */ protected function release() { $success = @\unlink($this->fileName); if (!$success) { throw new SyncException('Failed to unlock the mutex file.'); } } } <?php namespace Amp\Sync; use Amp\CallableMaker; use Amp\Deferred; use Amp\Promise; use Amp\Success; class LocalMutex implements Mutex { use CallableMaker; /** @var bool */ private $locked = false; /** @var \Amp\Deferred[] */ private $queue = []; /** @var callable */ private $release; public function __construct() { $this->release = $this->callableFromInstanceMethod("release"); } /** {@inheritdoc} */ public function acquire(): Promise { if (!$this->locked) { $this->locked = true; return new Success(new Lock(0, $this->release)); } $this->queue[] = $deferred = new Deferred; return $deferred->promise(); } private function release() { if (!empty($this->queue)) { $deferred = \array_shift($this->queue); $deferred->resolve(new Lock(0, $this->release)); return; } $this->locked = false; } } <?php namespace Amp\Sync; use Amp\Promise; /** * An asynchronous semaphore based on pthreads' synchronization methods. * * This is an implementation of a thread-safe semaphore that has non-blocking * acquire methods. There is a small tradeoff for asynchronous semaphores; you * may not acquire a lock immediately when one is available and there may be a * small delay. However, the small delay will not block the thread. */ class ThreadedSemaphore implements Semaphore { /** @var \Threaded */ private $semaphore; /** * Creates a new semaphore with a given number of locks. * * @param int $locks The maximum number of locks that can be acquired from the semaphore. */ public function __construct(int $locks) { if ($locks < 1) { throw new \Error("The number of locks should be a positive integer"); } $this->semaphore = new Internal\SemaphoreStorage($locks); } /** * {@inheritdoc} */ public function acquire(): Promise { return $this->semaphore->acquire(); } } <?php namespace Amp\Sync; class SyncException extends \Exception { } <?php namespace Amp\Sync; /** * A handle on an acquired lock from a synchronization object. * * This object is not thread-safe; after acquiring a lock from a mutex or * semaphore, the lock should reside in the same thread or process until it is * released. */ class Lock { /** @var callable|null The function to be called on release or null if the lock has been released. */ private $releaser; /** @var int */ private $id; /** * Creates a new lock permit object. * * @param int $id The lock identifier. * @param callable $releaser A function to be called upon release. The function will be passed this object as the * first parameter. */ public function __construct(int $id, callable $releaser) { $this->id = $id; $this->releaser = $releaser; } /** * Checks if the lock has already been released. * * @return bool True if the lock has already been released, otherwise false. */ public function isReleased(): bool { return !$this->releaser; } /** * @return int Lock identifier. */ public function getId(): int { return $this->id; } /** * Releases the lock. No-op if the lock has already been released. */ public function release() { if (!$this->releaser) { return; } // Invoke the releaser function given to us by the synchronization source // to release the lock. $releaser = $this->releaser; $this->releaser = null; ($releaser)($this); } /** * Releases the lock when there are no more references to it. */ public function __destruct() { if ($this->releaser) { $this->release(); } } } <?php namespace Amp\Sync; use Amp\Promise; /** * A non-blocking synchronization primitive that can be used for mutual exclusion across contexts. * * Objects that implement this interface should guarantee that all operations * are atomic. Implementations do not have to guarantee that acquiring a lock * is first-come, first serve. */ interface Mutex { /** * Acquires a lock on the mutex. * * @return \Amp\Promise<\Amp\Sync\Lock> Resolves with a lock object with an ID of 0. May fail with a SyncException * if an error occurs when attempting to obtain the lock (e.g. a shared memory segment closed). */ public function acquire(): Promise; } <?php namespace Amp\Sync; use Amp\CallableMaker; use Amp\Deferred; use Amp\Promise; use Amp\Success; class LocalSemaphore implements Semaphore { use CallableMaker; /** @var int[] */ private $locks; /** @var \Amp\Deferred[] */ private $queue = []; /** @var callable */ private $release; public function __construct(int $maxLocks) { if ($maxLocks < 1) { throw new \Error("The number of locks must be greater than 0"); } $this->release = $this->callableFromInstanceMethod("release"); $this->locks = \range(0, $maxLocks - 1); } /** {@inheritdoc} */ public function acquire(): Promise { if (!empty($this->locks)) { return new Success(new Lock(\array_shift($this->locks), $this->release)); } $this->queue[] = $deferred = new Deferred; return $deferred->promise(); } private function release(Lock $lock) { $id = $lock->getId(); if (!empty($this->queue)) { $deferred = \array_shift($this->queue); $deferred->resolve(new Lock($id, $this->release)); return; } $this->locks[] = $id; } } <?php namespace Amp\Sync; use Amp\Promise; /** * A thread-safe, asynchronous mutex using the pthreads locking mechanism. * * Compatible with POSIX systems and Microsoft Windows. */ class ThreadedMutex implements Mutex { /** @var Internal\MutexStorage */ private $mutex; /** * Creates a new threaded mutex. */ public function __construct() { $this->mutex = new Internal\MutexStorage; } /** * {@inheritdoc} */ public function acquire(): Promise { return $this->mutex->acquire(); } } <?php namespace Amp\Sync; use Amp\Promise; use function Amp\call; class SemaphoreMutex implements Mutex { /** @var \Amp\Sync\Semaphore */ private $semaphore; /** * @param \Amp\Sync\Semaphore $semaphore A semaphore with a single lock. */ public function __construct(Semaphore $semaphore) { $this->semaphore = $semaphore; } /** {@inheritdoc} */ public function acquire(): Promise { return call(function () { /** @var \Amp\Sync\Lock $lock */ $lock = yield $this->semaphore->acquire(); if ($lock->getId() !== 0) { $lock->release(); throw new \Error("Cannot use a semaphore with more than a single lock"); } return $lock; }); } } { "name": "amphp/parser", "homepage": "https://github.com/amphp/parser", "description": "A generator parser to make streaming parsers simple.", "support": { "issues": "https://github.com/amphp/parser/issues" }, "keywords": [ "stream", "async", "non-blocking", "parser" ], "license": "MIT", "authors": [ { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "require": { "php": ">=7" }, "require-dev": { "phpunit/phpunit": "^6", "friendsofphp/php-cs-fixer": "^2.3" }, "autoload": { "psr-4": { "Amp\\Parser\\": "lib" } }, "autoload-dev": { "psr-4": { "Amp\\Parser\\Test\\": "test" } } } <?php namespace Amp\Parser; class InvalidDelimiterError extends \Error { /** * @param \Generator $generator * @param string $prefix * @param \Throwable|null $previous */ public function __construct(\Generator $generator, string $prefix, \Throwable $previous = null) { $yielded = $generator->current(); $prefix .= \sprintf( "; %s yielded at key %s", \is_object($yielded) ? \get_class($yielded) : \gettype($yielded), \var_export($generator->key(), true) ); if (!$generator->valid()) { parent::__construct($prefix, 0, $previous); return; } $reflGen = new \ReflectionGenerator($generator); $exeGen = $reflGen->getExecutingGenerator(); if ($isSubgenerator = ($exeGen !== $generator)) { $reflGen = new \ReflectionGenerator($exeGen); } parent::__construct(\sprintf( "%s on line %s in %s", $prefix, $reflGen->getExecutingLine(), $reflGen->getExecutingFile() ), 0, $previous); } } <?php namespace Amp\Parser; class Parser { /** @var \Generator */ private $generator; /** @var string */ private $buffer = ''; /** @var int|string|null */ private $delimiter; /** * @param \Generator $generator * * @throws InvalidDelimiterError If the generator yields an invalid delimiter. * @throws \Throwable If the generator throws. */ public function __construct(\Generator $generator) { $this->generator = $generator; $this->delimiter = $this->generator->current(); if (!$this->generator->valid()) { $this->generator = null; return; } if ($this->delimiter !== null && (!\is_int($this->delimiter) || $this->delimiter <= 0) && (!\is_string($this->delimiter) || !\strlen($this->delimiter)) ) { throw new InvalidDelimiterError( $generator, \sprintf( "Invalid value yielded: Expected NULL, an int greater than 0, or a non-empty string; %s given", \is_object($this->delimiter) ? \sprintf("instance of %s", \get_class($this->delimiter)) : \gettype($this->delimiter) ) ); } } /** * Cancels the generator parser and returns any remaining data in the internal buffer. Writing data after calling * this method will result in an error. * * @return string */ final public function cancel(): string { $this->generator = null; return $this->buffer; } /** * @return bool True if the parser can still receive more data to parse, false if it has ended and calling push * will throw an exception. */ final public function isValid(): bool { return $this->generator !== null; } /** * Adds data to the internal buffer and tries to continue parsing. * * @param string $data Data to append to the internal buffer. * * @throws InvalidDelimiterError If the generator yields an invalid delimiter. * @throws \Error If parsing has already been cancelled. * @throws \Throwable If the generator throws. */ final public function push(string $data) { if ($this->generator === null) { throw new \Error("The parser is no longer writable"); } $this->buffer .= $data; $end = false; try { while ($this->buffer !== "") { if (\is_int($this->delimiter)) { if (\strlen($this->buffer) < $this->delimiter) { break; // Too few bytes in buffer. } $send = \substr($this->buffer, 0, $this->delimiter); $this->buffer = \substr($this->buffer, $this->delimiter); } elseif (\is_string($this->delimiter)) { if (($position = \strpos($this->buffer, $this->delimiter)) === false) { break; } $send = \substr($this->buffer, 0, $position); $this->buffer = \substr($this->buffer, $position + \strlen($this->delimiter)); } else { $send = $this->buffer; $this->buffer = ""; } $this->delimiter = $this->generator->send($send); if (!$this->generator->valid()) { $end = true; break; } if ($this->delimiter !== null && (!\is_int($this->delimiter) || $this->delimiter <= 0) && (!\is_string($this->delimiter) || !\strlen($this->delimiter)) ) { throw new InvalidDelimiterError( $this->generator, \sprintf( "Invalid value yielded: Expected NULL, an int greater than 0, or a non-empty string; %s given", \is_object($this->delimiter) ? \sprintf("instance of %s", \get_class($this->delimiter)) : \gettype($this->delimiter) ) ); } } } catch (\Throwable $exception) { $end = true; throw $exception; } finally { if ($end) { $this->generator = null; } } } } { "name": "amphp/parallel", "description": "Parallel processing component for Amp.", "keywords": [ "asynchronous", "async", "concurrent", "multi-threading", "multi-processing" ], "homepage": "https://github.com/amphp/parallel", "license": "MIT", "authors": [ { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Stephen Coakley", "email": "me@stephencoakley.com" } ], "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.5", "amphp/parser": "^1", "amphp/process": "^1", "amphp/sync": "^1.0.1" }, "require-dev": { "phpunit/phpunit": "^6", "amphp/phpunit-util": "^1", "amphp/php-cs-fixer-config": "dev-master" }, "suggest": { "ext-pthreads": "Required for thread contexts" }, "autoload": { "psr-4": { "Amp\\Parallel\\": "lib" }, "files": [ "lib/Worker/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Parallel\\Example\\": "examples", "Amp\\Parallel\\Test\\": "test" } }, "config": { "platform": { "php": "7.0.0" } }, "scripts": { "check": [ "@cs", "@test" ], "cs": "php-cs-fixer fix -v --diff --dry-run", "cs-fix": "php-cs-fixer fix -v --diff", "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text" } } <?php namespace Amp\Parallel\Worker; /** * A worker process that executes task objects. */ final class WorkerProcess extends TaskWorker { const SCRIPT_PATH = __DIR__ . "/Internal/worker-process.php"; /** * @param string $envClassName Name of class implementing \Amp\Parallel\Worker\Environment to instigate. * Defaults to \Amp\Parallel\Worker\BasicEnvironment. * @param mixed[] $env Array of environment variables to pass to the worker. Empty array inherits from the current * PHP process. See the $env parameter of \Amp\Process\Process::__construct(). * @param string|null $binary Path to PHP binary. Null will attempt to automatically locate the binary. * * @throws \Error If the PHP binary path given cannot be found or is not executable. */ public function __construct(string $envClassName = BasicEnvironment::class, array $env = [], string $binary = null) { $script = [ self::SCRIPT_PATH, $envClassName, ]; parent::__construct(new Internal\WorkerProcess($script, $env, $binary)); } } <?php namespace Amp\Parallel\Worker; use Amp\Parallel\Context\Thread; /** * The built-in worker factory type. */ final class DefaultWorkerFactory implements WorkerFactory { /** @var string */ private $className; /** * @param string $envClassName Name of class implementing \Amp\Parallel\Worker\Environment to instigate in each * worker. Defaults to \Amp\Parallel\Worker\BasicEnvironment. * * @throws \Error If the given class name does not exist or does not implement \Amp\Parallel\Worker\Environment. */ public function __construct(string $envClassName = BasicEnvironment::class) { if (!\class_exists($envClassName)) { throw new \Error(\sprintf("Invalid environment class name '%s'", $envClassName)); } if (!\is_subclass_of($envClassName, Environment::class)) { throw new \Error(\sprintf( "The class '%s' does not implement '%s'", $envClassName, Environment::class )); } $this->className = $envClassName; } /** * {@inheritdoc} * * The type of worker created depends on the extensions available. If multi-threading is enabled, a WorkerThread * will be created. If threads are not available a WorkerProcess will be created. */ public function create(): Worker { if (Thread::isSupported()) { return new WorkerThread($this->className); } return new WorkerProcess( $this->className, [], \getenv("AMP_PHP_BINARY") ?: (\defined("AMP_PHP_BINARY") ? \AMP_PHP_BINARY : null) ); } } <?php namespace Amp\Parallel\Worker; /** * A runnable unit of execution. */ interface Task { /** * Runs the task inside the caller's context. * * Does not have to be a coroutine, can also be a regular function returning a value. * * @param \Amp\Parallel\Worker\Environment * * @return mixed|\Amp\Promise|\Generator */ public function run(Environment $environment); } <?php namespace Amp\Parallel\Worker; use Amp\Failure; use Amp\Parallel\Context\Context; use Amp\Parallel\Context\StatusError; use Amp\Parallel\Sync\ChannelException; use Amp\Promise; use Amp\Success; use function Amp\call; /** * Base class for most common types of task workers. */ abstract class TaskWorker implements Worker { const SHUTDOWN_TIMEOUT = 1000; /** @var \Amp\Parallel\Context\Context */ private $context; /** @var \Amp\Promise|null */ private $pending; /** @var \Amp\Promise|null */ private $exitStatus; /** * @param \Amp\Parallel\Context\Context $context A context running an instance of TaskRunner. */ public function __construct(Context $context) { if ($context->isRunning()) { throw new \Error("The context was already running"); } $this->context = $context; $context = &$this->context; $pending = &$this->pending; \register_shutdown_function(static function () use (&$context, &$pending) { if ($context === null || !$context->isRunning()) { return; } try { Promise\wait(Promise\timeout(call(function () use ($context, $pending) { if ($pending) { yield $pending; } yield $context->send(0); return yield $context->join(); }), self::SHUTDOWN_TIMEOUT)); } catch (\Throwable $exception) { if ($context !== null) { $context->kill(); } } }); } /** * {@inheritdoc} */ public function isRunning(): bool { return !$this->exitStatus; } /** * {@inheritdoc} */ public function isIdle(): bool { return $this->pending === null; } /** * {@inheritdoc} */ public function enqueue(Task $task): Promise { if ($this->exitStatus) { throw new StatusError("The worker has been shut down"); } $promise = $this->pending = call(function () use ($task) { if ($this->pending) { try { yield $this->pending; } catch (\Throwable $exception) { // Ignore error from prior job. } } if ($this->exitStatus) { throw new WorkerException("The worker was shutdown"); } if (!$this->context->isRunning()) { yield $this->context->start(); } $job = new Internal\Job($task); try { yield $this->context->send($job); $result = yield $this->context->receive(); } catch (ChannelException $exception) { $this->kill(); throw new WorkerException("Communicating with the worker failed", 0, $exception); } if (!$result instanceof Internal\TaskResult) { $this->kill(); throw new WorkerException("Context did not return a task result"); } if ($result->getId() !== $job->getId()) { $this->kill(); throw new WorkerException("Task results returned out of order"); } return $result->promise(); }); $promise->onResolve(function () use ($promise) { if ($this->pending === $promise) { $this->pending = null; } }); return $promise; } /** * {@inheritdoc} */ public function shutdown(): Promise { if ($this->exitStatus) { return $this->exitStatus; } if ($this->context === null || !$this->context->isRunning()) { return $this->exitStatus = new Success(0); } return $this->exitStatus = call(function () { if ($this->pending) { // If a task is currently running, wait for it to finish. yield Promise\any([$this->pending]); } yield $this->context->send(0); try { return yield Promise\timeout($this->context->join(), self::SHUTDOWN_TIMEOUT); } catch (\Throwable $exception) { $this->context->kill(); throw new WorkerException("Failed to gracefully shutdown worker", 0, $exception); } finally { // Null properties to free memory because the shutdown function has references to these. $this->context = null; $this->pending = null; } }); } /** * {@inheritdoc} */ public function kill() { if ($this->exitStatus || $this->context === null) { return; } if ($this->context->isRunning()) { $this->context->kill(); $this->exitStatus = new Failure(new WorkerException("The worker was killed")); return; } $this->exitStatus = new Success(0); // Null properties to free memory because the shutdown function has references to these. $this->context = null; $this->pending = null; } } <?php namespace Amp\Parallel\Worker; use Amp\Loop; use Amp\Struct; final class BasicEnvironment implements Environment { /** @var array */ private $data = []; /** @var \SplPriorityQueue */ private $queue; /** @var string */ private $timer; public function __construct() { $this->queue = $queue = new \SplPriorityQueue; $data = &$this->data; $this->timer = Loop::repeat(1000, static function ($watcherId) use ($queue, &$data) { $time = \time(); while (!$queue->isEmpty()) { list($key, $expiration) = $queue->top(); if (!isset($data[$key])) { // Item removed. $queue->extract(); continue; } $struct = $data[$key]; if ($struct->expire === 0) { // Item was set again without a TTL. $queue->extract(); continue; } if ($struct->expire !== $expiration) { // Expiration changed or TTL updated. $queue->extract(); continue; } if ($time < $struct->expire) { // Item at top has not expired, break out of loop. break; } unset($data[$key]); $queue->extract(); } if ($queue->isEmpty()) { Loop::disable($watcherId); } }); Loop::disable($this->timer); Loop::unreference($this->timer); } /** * @param string $key * * @return bool */ public function exists(string $key): bool { return isset($this->data[$key]); } /** * @param string $key * * @return mixed|null Returns null if the key does not exist. */ public function get(string $key) { if (!isset($this->data[$key])) { return null; } $struct = $this->data[$key]; if ($struct->ttl !== null) { $expire = \time() + $struct->ttl; if ($struct->expire < $expire) { $struct->expire = $expire; $this->queue->insert([$key, $struct->expire], -$struct->expire); } } return $struct->data; } /** * @param string $key * @param mixed $value Using null for the value deletes the key. * @param int $ttl Number of seconds until data is automatically deleted. Use null for unlimited TTL. * * @throws \Error If the time-to-live is not a positive integer. */ public function set(string $key, $value, int $ttl = null) { if ($value === null) { $this->delete($key); return; } if ($ttl !== null && $ttl <= 0) { throw new \Error("The time-to-live must be a positive integer or null"); } $struct = new class { use Struct; public $data; public $expire = 0; public $ttl; }; $struct->data = $value; if ($ttl !== null) { $struct->ttl = $ttl; $struct->expire = \time() + $ttl; $this->queue->insert([$key, $struct->expire], -$struct->expire); Loop::enable($this->timer); } $this->data[$key] = $struct; } /** * @param string $key */ public function delete(string $key) { unset($this->data[$key]); } /** * Alias of exists(). * * @param $key * * @return bool */ public function offsetExists($key) { return $this->exists($key); } /** * Alias of get(). * * @param string $key * * @return mixed */ public function offsetGet($key) { return $this->get($key); } /** * Alias of set() with $ttl = null. * * @param string $key * @param mixed $value */ public function offsetSet($key, $value) { $this->set($key, $value); } /** * Alias of delete(). * * @param string $key */ public function offsetUnset($key) { $this->delete($key); } /** * Removes all values. */ public function clear() { $this->data = []; Loop::disable($this->timer); $this->queue = new \SplPriorityQueue; } } <?php namespace Amp\Parallel\Worker\Internal; use Amp\ByteStream; use Amp\Parallel\Context\Context; use Amp\Parallel\Context\Process; use Amp\Promise; use function Amp\call; class WorkerProcess implements Context { /** @var Process */ private $process; public function __construct($script, array $env = [], string $binary = null) { $this->process = new Process($script, null, $env, $binary); } public function receive(): Promise { return $this->process->receive(); } public function send($data): Promise { return $this->process->send($data); } public function isRunning(): bool { return $this->process->isRunning(); } public function start(): Promise { return call(function () { $result = yield $this->process->start(); $stdout = $this->process->getStdout(); $stdout->unreference(); $stderr = $this->process->getStderr(); $stderr->unreference(); ByteStream\pipe($stdout, ByteStream\getStdout()); ByteStream\pipe($stderr, ByteStream\getStderr()); return $result; }); } public function kill() { if ($this->process->isRunning()) { $this->process->kill(); } } public function join(): Promise { return $this->process->join(); } } <?php namespace Amp\Parallel\Worker\Internal; use Amp\Parallel\Worker\Task; use Amp\Parallel\Worker\Worker; use Amp\Promise; /** @internal */ final class PooledWorker implements Worker { /** @var callable */ private $push; /** @var \Amp\Parallel\Worker\Worker */ private $worker; /** * @param \Amp\Parallel\Worker\Worker $worker * @param callable $push Callable to push the worker back into the queue. */ public function __construct(Worker $worker, callable $push) { $this->worker = $worker; $this->push = $push; } /** * Automatically pushes the worker back into the queue. */ public function __destruct() { ($this->push)($this->worker); } /** * {@inheritdoc} */ public function isRunning(): bool { return $this->worker->isRunning(); } /** * {@inheritdoc} */ public function isIdle(): bool { return $this->worker->isIdle(); } /** * {@inheritdoc} */ public function enqueue(Task $task): Promise { return $this->worker->enqueue($task); } /** * {@inheritdoc} */ public function shutdown(): Promise { return $this->worker->shutdown(); } /** * {@inheritdoc} */ public function kill() { $this->worker->kill(); } } <?php namespace Amp\Parallel\Worker\Internal; use Amp\Parallel\Sync; use Amp\Parallel\Worker; use Amp\Promise; return function (Sync\Channel $channel) use ($argv): Promise { if (!\defined("AMP_WORKER")) { \define("AMP_WORKER", "amp-worker"); } if (!isset($argv[1])) { throw new \Error("No environment class name provided"); } $className = $argv[1]; if (!\class_exists($className)) { throw new \Error(\sprintf("Invalid environment class name '%s'", $className)); } if (!\is_subclass_of($className, Worker\Environment::class)) { throw new \Error(\sprintf( "The class '%s' does not implement '%s'", $className, Worker\Environment::class )); } $environment = new $className; $runner = new Worker\TaskRunner($channel, $environment); return $runner->run(); }; <?php namespace Amp\Parallel\Worker\Internal; use Amp\Failure; use Amp\Parallel\Worker\Task; use Amp\Promise; use Amp\Success; /** @internal */ final class TaskSuccess extends TaskResult { /** @var mixed Result of task. */ private $result; public function __construct(string $id, $result) { parent::__construct($id); $this->result = $result; } public function promise(): Promise { if ($this->result instanceof \__PHP_Incomplete_Class) { return new Failure(new \Error(\sprintf( "Class instances returned from %s::run() must be autoloadable by the Composer autoloader", Task::class ))); } return new Success($this->result); } } <?php namespace Amp\Parallel\Worker\Internal; use Amp\Promise; /** @internal */ abstract class TaskResult { /** @var string Task identifier. */ private $id; /** * @param string $id Task identifier. */ public function __construct(string $id) { $this->id = $id; } /** * @return string Task identifier. */ public function getId(): string { return $this->id; } /** * @return \Amp\Promise<mixed> Resolved with the task result or failure reason. */ abstract public function promise(): Promise; } <?php namespace Amp\Parallel\Worker\Internal; use Amp\Parallel\Worker\Task; /** @internal */ final class Job { /** @var string */ private $id; /** @var \Amp\Parallel\Worker\Task */ private $task; public function __construct(Task $task) { static $id = 'a'; $this->task = $task; $this->id = $id++; } public function getId(): string { return $this->id; } public function getTask(): Task { // Classes that cannot be autoloaded will be unserialized as an instance of __PHP_Incomplete_Class. if ($this->task instanceof \__PHP_Incomplete_Class) { throw new \Error(\sprintf("Classes implementing %s must be autoloadable by the Composer autoloader", Task::class)); } return $this->task; } } <?php namespace Amp\Parallel\Worker\Internal; use Amp\Failure; use Amp\Parallel\Worker\TaskError; use Amp\Parallel\Worker\TaskException; use Amp\Promise; /** @internal */ final class TaskFailure extends TaskResult { const PARENT_EXCEPTION = 0; const PARENT_ERROR = 1; /** @var string */ private $type; /** @var int */ private $parent; /** @var string */ private $message; /** @var int|string */ private $code; /** @var array */ private $trace; public function __construct(string $id, \Throwable $exception) { parent::__construct($id); $this->type = \get_class($exception); $this->parent = $exception instanceof \Error ? self::PARENT_ERROR : self::PARENT_EXCEPTION; $this->message = $exception->getMessage(); $this->code = $exception->getCode(); $this->trace = $exception->getTraceAsString(); } public function promise(): Promise { switch ($this->parent) { case self::PARENT_ERROR: $exception = new TaskError( $this->type, \sprintf( 'Uncaught %s in worker with message "%s" and code "%s"', $this->type, $this->message, $this->code ), $this->trace ); break; default: $exception = new TaskException( $this->type, \sprintf( 'Uncaught %s in worker with message "%s" and code "%s"', $this->type, $this->message, $this->code ), $this->trace ); } return new Failure($exception); } } <?php namespace Amp\Parallel\Worker; /** * An interface for worker pools. */ interface Pool extends Worker { /** @var int The default maximum pool size. */ const DEFAULT_MAX_SIZE = 32; /** * Gets a worker from the pool. The worker is marked as busy and will only be reused if the pool runs out of * idle workers. The worker will be automatically marked as idle once no references to the returned worker remain. * * @return \Amp\Parallel\Worker\Worker * * @throws \Amp\Parallel\Context\StatusError If the queue is not running. */ public function getWorker(): Worker; /** * Gets the number of workers currently running in the pool. * * @return int The number of workers. */ public function getWorkerCount(): int; /** * Gets the number of workers that are currently idle. * * @return int The number of idle workers. */ public function getIdleWorkerCount(): int; /** * Gets the maximum number of workers the pool may spawn to handle concurrent tasks. * * @return int The maximum number of workers. */ public function getMaxSize(): int; } <?php namespace Amp\Parallel\Worker; use Amp\Loop; use Amp\Promise; const LOOP_POOL_IDENTIFIER = Pool::class; const LOOP_FACTORY_IDENTIFIER = WorkerFactory::class; /** * Gets or sets the global worker pool. * * @param \Amp\Parallel\Worker\Pool|null $pool A worker pool instance. * * @return \Amp\Parallel\Worker\Pool The global worker pool instance. */ function pool(Pool $pool = null): Pool { if ($pool === null) { $pool = Loop::getState(LOOP_POOL_IDENTIFIER); if ($pool) { return $pool; } $pool = new DefaultPool; } Loop::setState(LOOP_POOL_IDENTIFIER, $pool); return $pool; } /** * Enqueues a task to be executed by the global worker pool. * * @param Task $task The task to enqueue. * * @return Promise<mixed> */ function enqueue(Task $task): Promise { return pool()->enqueue($task); } /** * Enqueues a callable to be executed by the global worker pool. * * @param callable $callable Callable needs to be serializable. * @param mixed ...$args Arguments have to be serializable. * * @return Promise<mixed> */ function enqueueCallable(callable $callable,...$args) { return enqueue(new CallableTask($callable, $args)); } /** * Gets a worker from the global worker pool. * * @return \Amp\Parallel\Worker\Worker */ function worker(): Worker { return pool()->getWorker(); } /** * Creates a worker using the global worker factory. * * @return \Amp\Parallel\Worker\Worker */ function create(): Worker { return factory()->create(); } /** * Gets or sets the global worker factory. * * @param \Amp\Parallel\Worker\WorkerFactory|null $factory * * @return \Amp\Parallel\Worker\WorkerFactory */ function factory(WorkerFactory $factory = null): WorkerFactory { if ($factory === null) { $factory = Loop::getState(LOOP_FACTORY_IDENTIFIER); if ($factory) { return $factory; } $factory = new DefaultWorkerFactory; } Loop::setState(LOOP_FACTORY_IDENTIFIER, $factory); return $factory; } <?php namespace Amp\Parallel\Worker; class WorkerException extends \Exception { } <?php namespace Amp\Parallel\Worker; final class TaskException extends \Exception { /** @var string Class name of exception thrown from task. */ private $name; /** @var string Stack trace of the exception thrown from task. */ private $trace; /** * @param string $name The exception class name. * @param string $message The panic message. * @param string $trace The panic stack trace. */ public function __construct(string $name, string $message = '', string $trace = '') { parent::__construct($message); $this->name = $name; $this->trace = $trace; } /** * Returns the class name of the exception thrown from the task. * * @return string */ public function getName(): string { return $this->name; } /** * Gets the stack trace at the point the exception was thrown in the task. * * @return string */ public function getWorkerTrace(): string { return $this->trace; } } <?php namespace Amp\Parallel\Worker; interface Environment extends \ArrayAccess { /** * @param string $key * * @return bool */ public function exists(string $key): bool; /** * @param string $key * * @return mixed|null Returns null if the key does not exist. */ public function get(string $key); /** * @param string $key * @param mixed $value Using null for the value deletes the key. * @param int $ttl Number of seconds until data is automatically deleted. Use 0 for unlimited TTL. */ public function set(string $key, $value, int $ttl = null); /** * @param string $key */ public function delete(string $key); /** * Removes all values. */ public function clear(); } <?php namespace Amp\Parallel\Worker; /** * Interface for factories used to create new workers. */ interface WorkerFactory { /** * Creates a new worker instance. * * @return Worker The newly created worker. */ public function create(): Worker; } <?php namespace Amp\Parallel\Worker; final class TaskError extends \Error { /** @var string Class name of error thrown from task. */ private $name; /** @var string Stack trace of the error thrown from task. */ private $trace; /** * @param string $name The exception class name. * @param string $message The panic message. * @param string $trace The panic stack trace. */ public function __construct(string $name, string $message = '', string $trace = '') { parent::__construct($message); $this->name = $name; $this->trace = $trace; } /** * Returns the class name of the error thrown from the task. * * @return string */ public function getName(): string { return $this->name; } /** * Gets the stack trace at the point the error was thrown in the task. * * @return string */ public function getWorkerTrace(): string { return $this->trace; } } <?php namespace Amp\Parallel\Worker; use Amp\Parallel\Context\Thread; use Amp\Parallel\Sync\Channel; use Amp\Promise; /** * A worker thread that executes task objects. */ final class WorkerThread extends TaskWorker { /** * @param string $envClassName Name of class implementing \Amp\Parallel\Worker\Environment to instigate. * Defaults to \Amp\Parallel\Worker\BasicEnvironment. */ public function __construct(string $envClassName = BasicEnvironment::class) { parent::__construct(new Thread(function (Channel $channel, string $className): Promise { if (!\class_exists($className)) { throw new \Error(\sprintf("Invalid environment class name '%s'", $className)); } if (!\is_subclass_of($className, Environment::class)) { throw new \Error(\sprintf("The class '%s' does not implement '%s'", $className, Environment::class)); } $environment = new $className; if (!\defined("AMP_WORKER")) { \define("AMP_WORKER", "amp-worker"); } $runner = new TaskRunner($channel, $environment); return $runner->run(); }, $envClassName)); } } <?php namespace Amp\Parallel\Worker; /** * Task implementation dispatching a simple callable. */ final class CallableTask implements Task { /** @var string */ private $callable; /** @var mixed[] */ private $args; /** * @param callable $callable Callable will be serialized. * @param mixed $args Arguments to pass to the function. Must be serializable. */ public function __construct(callable $callable, array $args) { $this->callable = $callable; $this->args = $args; } public function run(Environment $environment) { if ($this->callable instanceof \__PHP_Incomplete_Class) { throw new \Error('When using a class instance as a callable, the class must be autoloadable'); } if (\is_array($this->callable) && ($this->callable[0] ?? null) instanceof \__PHP_Incomplete_Class) { throw new \Error('When using a class instance method as a callable, the class must be autoloadable'); } return ($this->callable)(...$this->args); } } <?php namespace Amp\Parallel\Worker; use Amp\Coroutine; use Amp\Parallel\Sync\Channel; use Amp\Parallel\Sync\SerializationException; use Amp\Promise; use function Amp\call; final class TaskRunner { /** @var \Amp\Parallel\Sync\Channel */ private $channel; /** @var \Amp\Parallel\Worker\Environment */ private $environment; public function __construct(Channel $channel, Environment $environment) { $this->channel = $channel; $this->environment = $environment; } /** * Runs the task runner, receiving tasks from the parent and sending the result of those tasks. * * @return \Amp\Promise */ public function run(): Promise { return new Coroutine($this->execute()); } /** * @coroutine * * @return \Generator */ private function execute(): \Generator { $job = yield $this->channel->receive(); while ($job instanceof Internal\Job) { try { $result = yield call([$job->getTask(), "run"], $this->environment); $result = new Internal\TaskSuccess($job->getId(), $result); } catch (\Throwable $exception) { $result = new Internal\TaskFailure($job->getId(), $exception); } $job = null; // Free memory from last job. try { yield $this->channel->send($result); } catch (SerializationException $exception) { // Could not serialize task result. yield $this->channel->send(new Internal\TaskFailure($result->getId(), $exception)); } $result = null; // Free memory from last result. $job = yield $this->channel->receive(); } return $job; } } <?php namespace Amp\Parallel\Worker; use Amp\Parallel\Context\StatusError; use Amp\Promise; /** * Provides a pool of workers that can be used to execute multiple tasks asynchronously. * * A worker pool is a collection of worker threads that can perform multiple * tasks simultaneously. The load on each worker is balanced such that tasks * are completed as soon as possible and workers are used efficiently. */ final class DefaultPool implements Pool { /** @var bool Indicates if the pool is currently running. */ private $running = true; /** @var int The maximum number of workers the pool should spawn. */ private $maxSize; /** @var WorkerFactory A worker factory to be used to create new workers. */ private $factory; /** @var \SplObjectStorage A collection of all workers in the pool. */ private $workers; /** @var \SplQueue A collection of idle workers. */ private $idleWorkers; /** @var \SplQueue A queue of workers that have been assigned to tasks. */ private $busyQueue; /** @var \Closure */ private $push; /** @var \Amp\Promise|null */ private $exitStatus; /** * Creates a new worker pool. * * @param int $maxSize The maximum number of workers the pool should spawn. * Defaults to `Pool::DEFAULT_MAX_SIZE`. * @param \Amp\Parallel\Worker\WorkerFactory|null $factory A worker factory to be used to create * new workers. * * @throws \Error */ public function __construct(int $maxSize = self::DEFAULT_MAX_SIZE, WorkerFactory $factory = null) { if ($maxSize < 0) { throw new \Error("Maximum size must be a non-negative integer"); } $this->maxSize = $maxSize; // Use the global factory if none is given. $this->factory = $factory ?: factory(); $this->workers = new \SplObjectStorage; $this->idleWorkers = new \SplQueue; $this->busyQueue = new \SplQueue; $workers = $this->workers; $idleWorkers = $this->idleWorkers; $busyQueue = $this->busyQueue; $this->push = static function (Worker $worker) use ($workers, $idleWorkers, $busyQueue) { if (!$workers->contains($worker) || ($workers[$worker] -= 1) > 0) { return; } // Worker is completely idle, remove from busy queue and add to idle queue. foreach ($busyQueue as $key => $busy) { if ($busy === $worker) { unset($busyQueue[$key]); break; } } $idleWorkers->push($worker); }; } public function __destruct() { if ($this->isRunning()) { $this->kill(); } } /** * Checks if the pool is running. * * @return bool True if the pool is running, otherwise false. */ public function isRunning(): bool { return $this->running; } /** * Checks if the pool has any idle workers. * * @return bool True if the pool has at least one idle worker, otherwise false. */ public function isIdle(): bool { return $this->idleWorkers->count() > 0 || $this->workers->count() === 0; } /** * {@inheritdoc} */ public function getMaxSize(): int { return $this->maxSize; } /** * {@inheritdoc} */ public function getWorkerCount(): int { return $this->workers->count(); } /** * {@inheritdoc} */ public function getIdleWorkerCount(): int { return $this->idleWorkers->count(); } /** * Enqueues a task to be executed by the worker pool. * * @param Task $task The task to enqueue. * * @return \Amp\Promise<mixed> The return value of Task::run(). * * @throws \Amp\Parallel\Context\StatusError If the pool has been shutdown. * @throws \Amp\Parallel\Worker\TaskException If the task throws an exception. */ public function enqueue(Task $task): Promise { $worker = $this->pull(); $promise = $worker->enqueue($task); $promise->onResolve(function () use ($worker) { ($this->push)($worker); }); return $promise; } /** * Shuts down the pool and all workers in it. * * @return \Amp\Promise<int[]> Array of exit status from all workers. * * @throws \Amp\Parallel\Context\StatusError If the pool has not been started. */ public function shutdown(): Promise { if ($this->exitStatus) { return $this->exitStatus; } $this->running = false; $shutdowns = []; foreach ($this->workers as $worker) { if ($worker->isRunning()) { $shutdowns[] = $worker->shutdown(); } } return $this->exitStatus = Promise\all($shutdowns); } /** * Kills all workers in the pool and halts the worker pool. */ public function kill() { $this->running = false; foreach ($this->workers as $worker) { \assert($worker instanceof Worker); if ($worker->isRunning()) { $worker->kill(); } } } /** * {@inheritdoc} */ public function getWorker(): Worker { return new Internal\PooledWorker($this->pull(), $this->push); } /** * Pulls a worker from the pool. * * @return \Amp\Parallel\Worker\Worker * @throws \Amp\Parallel\Context\StatusError */ private function pull(): Worker { if (!$this->isRunning()) { throw new StatusError("The pool was shutdown"); } do { if ($this->idleWorkers->isEmpty()) { if ($this->getWorkerCount() >= $this->maxSize) { // All possible workers busy, so shift from head (will be pushed back onto tail below). $worker = $this->busyQueue->shift(); } else { // Max worker count has not been reached, so create another worker. $worker = $this->factory->create(); $this->workers->attach($worker, 0); break; } } else { // Shift a worker off the idle queue. $worker = $this->idleWorkers->shift(); } if ($worker->isRunning()) { break; } $this->workers->detach($worker); } while (true); $this->busyQueue->push($worker); $this->workers[$worker] += 1; return $worker; } } <?php namespace Amp\Parallel\Worker; use Amp\Promise; /** * An interface for a parallel worker thread that runs a queue of tasks. */ interface Worker { /** * Checks if the worker is running. * * @return bool True if the worker is running, otherwise false. */ public function isRunning(): bool; /** * Checks if the worker is currently idle. * * @return bool */ public function isIdle(): bool; /** * Enqueues a task to be executed by the worker. * * @param Task $task The task to enqueue. * * @return \Amp\Promise<mixed> Resolves with the return value of Task::run(). */ public function enqueue(Task $task): Promise; /** * @return \Amp\Promise<int> Exit code. */ public function shutdown(): Promise; /** * Immediately kills the context. */ public function kill(); } <?php namespace Amp\Parallel\Context\Internal; use Amp\Deferred; use Amp\Loop; use Amp\Parallel\Context\ContextException; use Amp\Parallel\Sync\ChannelledSocket; use Amp\Promise; use Amp\TimeoutException; use function Amp\call; final class ProcessHub { const PROCESS_START_TIMEOUT = 5000; const KEY_RECEIVE_TIMEOUT = 1000; /** @var resource|null */ private $server; /** @var string|null */ private $uri; /** @var int[] */ private $keys; /** @var string|null */ private $watcher; /** @var Deferred[] */ private $acceptor = []; public function __construct() { $isWindows = \strncasecmp(\PHP_OS, "WIN", 3) === 0; if ($isWindows) { $this->uri = "tcp://127.0.0.1:0"; } else { $this->uri = "unix://" . \tempnam(\sys_get_temp_dir(), "amp-parallel-ipc-") . ".sock"; } $this->server = \stream_socket_server($this->uri, $errno, $errstr, \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN); if (!$this->server) { throw new \RuntimeException(\sprintf("Could not create IPC server: (Errno: %d) %s", $errno, $errstr)); } if ($isWindows) { $name = \stream_socket_get_name($this->server, false); $port = \substr($name, \strrpos($name, ":") + 1); $this->uri = "tcp://127.0.0.1:" . $port; } $keys = &$this->keys; $acceptor = &$this->acceptor; $this->watcher = Loop::onReadable($this->server, static function (string $watcher, $server) use (&$keys, &$acceptor) { // Error reporting suppressed since stream_socket_accept() emits E_WARNING on client accept failure. if (!$client = @\stream_socket_accept($server, 0)) { // Timeout of 0 to be non-blocking. return; // Accepting client failed. } $channel = new ChannelledSocket($client, $client); try { $received = yield Promise\timeout($channel->receive(), self::KEY_RECEIVE_TIMEOUT); } catch (TimeoutException $exception) { $channel->close(); return; // Ignore possible foreign connection attempt. } if (!\is_string($received) || !isset($keys[$received])) { $channel->close(); return; // Ignore possible foreign connection attempt. } $pid = $keys[$received]; $deferred = $acceptor[$pid]; unset($acceptor[$pid], $keys[$received]); $deferred->resolve($channel); }); Loop::disable($this->watcher); } public function __destruct() { Loop::cancel($this->watcher); \fclose($this->server); } public function getUri(): string { return $this->uri; } public function generateKey(int $pid, int $length): string { $key = \random_bytes($length); $this->keys[$key] = $pid; return $key; } public function accept(int $pid): Promise { return call(function () use ($pid) { $this->acceptor[$pid] = new Deferred; Loop::enable($this->watcher); try { $channel = yield Promise\timeout($this->acceptor[$pid]->promise(), self::PROCESS_START_TIMEOUT); } catch (TimeoutException $exception) { $key = \array_search($pid, $this->keys, true); \assert(\is_string($key), "Key for {$pid} not found"); unset($this->acceptor[$pid], $this->keys[$key]); throw new ContextException("Starting the process timed out", 0, $exception); } finally { if (empty($this->acceptor)) { Loop::disable($this->watcher); } } return $channel; }); } } <?php namespace Amp\Parallel\Context\Internal; use Amp\Parallel\Context\Process; use Amp\Parallel\Sync; use Amp\Promise; use function Amp\call; // Doesn't exist in phpdbg... if (\function_exists("cli_set_process_title")) { @\cli_set_process_title("amp-process"); } (function () { $paths = [ \dirname(__DIR__, 5) . "/autoload.php", \dirname(__DIR__, 3) . "/vendor/autoload.php", ]; foreach ($paths as $path) { if (\file_exists($path)) { $autoloadPath = $path; break; } } if (!isset($autoloadPath)) { \trigger_error("Could not locate autoload.php in any of the following files: " . \implode(", ", $paths), E_USER_ERROR); exit(1); } require $autoloadPath; })(); (function () use ($argc, $argv) { // Remove this scripts path from process arguments. --$argc; \array_shift($argv); if (!isset($argv[0])) { throw new \Error("No socket path provided"); } // Remove socket path from process arguments. --$argc; $uri = \array_shift($argv); $key = ""; // Read random key from STDIN and send back to parent over IPC socket to authenticate. do { if (($chunk = \fread(\STDIN, Process::KEY_LENGTH)) === false || \feof(\STDIN)) { \trigger_error("Could not read key from parent", E_USER_ERROR); exit(1); } $key .= $chunk; } while (\strlen($key) < Process::KEY_LENGTH); if (!$socket = \stream_socket_client($uri, $errno, $errstr, 5, \STREAM_CLIENT_CONNECT)) { \trigger_error("Could not connect to IPC socket", E_USER_ERROR); exit(1); } $channel = new Sync\ChannelledSocket($socket, $socket); try { Promise\wait($channel->send($key)); } catch (\Throwable $exception) { \trigger_error("Could not send key to parent", E_USER_ERROR); exit(1); } try { if (!isset($argv[0])) { throw new \Error("No script path given"); } if (!\is_file($argv[0])) { throw new \Error(\sprintf("No script found at '%s' (be sure to provide the full path to the script)", $argv[0])); } // Protect current scope by requiring script within another function. $callable = (function () use ($argc, $argv) { // Using $argc so it is available to the required script. return require $argv[0]; })(); if (!\is_callable($callable)) { throw new \Error(\sprintf("Script '%s' did not return a callable function", $argv[0])); } $result = new Sync\ExitSuccess(Promise\wait(call($callable, $channel))); } catch (\Throwable $exception) { $result = new Sync\ExitFailure($exception); } try { Promise\wait(call(function () use ($channel, $result) { try { yield $channel->send($result); } catch (Sync\SerializationException $exception) { // Serializing the result failed. Send the reason why. yield $channel->send(new Sync\ExitFailure($exception)); } })); } catch (\Throwable $exception) { \trigger_error("Could not send result to parent; be sure to shutdown the child before ending the parent", E_USER_ERROR); exit(1); } })(); <?php namespace Amp\Parallel\Context\Internal; use Amp\Loop; use Amp\Parallel\Sync\Channel; use Amp\Parallel\Sync\ChannelException; use Amp\Parallel\Sync\ChannelledSocket; use Amp\Parallel\Sync\ExitFailure; use Amp\Parallel\Sync\ExitSuccess; use Amp\Parallel\Sync\SerializationException; use function Amp\call; /** * An internal thread that executes a given function concurrently. * * @internal */ final class Thread extends \Thread { const KILL_CHECK_FREQUENCY = 250; /** @var callable The function to execute in the thread. */ private $function; /** @var mixed[] Arguments to pass to the function. */ private $args; /** @var resource */ private $socket; /** @var bool */ private $killed = false; /** * Creates a new thread object. * * @param resource $socket IPC communication socket. * @param callable $function The function to execute in the thread. * @param mixed[] $args Arguments to pass to the function. */ public function __construct($socket, callable $function, array $args = []) { $this->function = $function; $this->args = $args; $this->socket = $socket; } /** * Runs the thread code and the initialized function. * * @codeCoverageIgnore Only executed in thread. */ public function run() { /* First thing we need to do is re-initialize the class autoloader. If * we don't do this first, any object of a class that was loaded after * the thread started will just be garbage data and unserializable * values (like resources) will be lost. This happens even with * thread-safe objects. */ // Protect scope by using an unbound closure (protects static access as well). (static function () { $paths = [ \dirname(__DIR__, 3) . \DIRECTORY_SEPARATOR . "vendor" . \DIRECTORY_SEPARATOR . "autoload.php", \dirname(__DIR__, 5) . \DIRECTORY_SEPARATOR . "autoload.php", ]; foreach ($paths as $path) { if (\file_exists($path)) { $autoloadPath = $path; break; } } if (!isset($autoloadPath)) { throw new \Error("Could not locate autoload.php"); } require $autoloadPath; })->bindTo(null, null)(); // At this point, the thread environment has been prepared so begin using the thread. if ($this->killed) { return; // Thread killed while requiring autoloader, simply exit. } Loop::run(function () { $watcher = Loop::repeat(self::KILL_CHECK_FREQUENCY, function () { if ($this->killed) { Loop::stop(); } }); Loop::unreference($watcher); try { $channel = new ChannelledSocket($this->socket, $this->socket); yield from $this->execute($channel); } catch (\Throwable $exception) { return; // Parent context exited or destroyed thread, no need to continue. } finally { Loop::cancel($watcher); } }); } /** * Sets a local variable to true so the running event loop can check for a kill signal. */ public function kill() { return $this->killed = true; } /** * @param \Amp\Parallel\Sync\Channel $channel * * @return \Generator * * @codeCoverageIgnore Only executed in thread. */ private function execute(Channel $channel): \Generator { try { $result = new ExitSuccess(yield call($this->function, $channel,...$this->args)); } catch (\Throwable $exception) { $result = new ExitFailure($exception); } if ($this->killed) { return; // Parent is not listening for a result. } // Attempt to return the result. try { try { yield $channel->send($result); } catch (SerializationException $exception) { // Serializing the result failed. Send the reason why. yield $channel->send(new ExitFailure($exception)); } } catch (ChannelException $exception) { // The result was not sendable! The parent context must have died or killed the context. } } } <?php namespace Amp\Parallel\Context; class ContextException extends \Exception { } <?php namespace Amp\Parallel\Context; use Amp\Failure; use Amp\Loop; use Amp\Parallel\Sync\ChannelException; use Amp\Parallel\Sync\ChannelledSocket; use Amp\Parallel\Sync\ExitResult; use Amp\Parallel\Sync\SynchronizationError; use Amp\Promise; use Amp\Success; use function Amp\call; /** * Implements an execution context using native multi-threading. * * The thread context is not itself threaded. A local instance of the context is * maintained both in the context that creates the thread and in the thread * itself. */ final class Thread implements Context { const EXIT_CHECK_FREQUENCY = 250; /** @var Internal\Thread An internal thread instance. */ private $thread; /** @var \Amp\Parallel\Sync\ChannelledSocket A channel for communicating with the thread. */ private $channel; /** @var resource */ private $socket; /** @var callable */ private $function; /** @var mixed[] */ private $args; /** @var int */ private $oid = 0; /** @var string */ private $watcher; /** * Checks if threading is enabled. * * @return bool True if threading is enabled, otherwise false. */ public static function isSupported(): bool { return \extension_loaded('pthreads'); } /** * Creates and starts a new thread. * * @param callable $function The callable to invoke in the thread. First argument is an instance of * \Amp\Parallel\Sync\Channel. * @param ...$args Additional arguments to pass to the given callable. * * @return Promise<Thread> The thread object that was spawned. */ public static function run(callable $function,...$args): Promise { $thread = new self($function,...$args); return call(function () use ($thread) { yield $thread->start(); return $thread; }); } /** * Creates a new thread. * * @param callable $function The callable to invoke in the thread. First argument is an instance of * \Amp\Parallel\Sync\Channel. * @param ...$args Additional arguments to pass to the given callable. * * @throws \Error Thrown if the pthreads extension is not available. */ public function __construct(callable $function,...$args) { if (!self::isSupported()) { throw new \Error("The pthreads extension is required to create threads."); } $this->function = $function; $this->args = $args; } /** * Returns the thread to the condition before starting. The new thread can be started and run independently of the * first thread. */ public function __clone() { $this->thread = null; $this->socket = null; $this->channel = null; $this->oid = 0; } /** * Kills the thread if it is still running. * * @throws \Amp\Parallel\Context\ContextException */ public function __destruct() { if (\getmypid() === $this->oid) { $this->kill(); } } /** * Checks if the context is running. * * @return bool True if the context is running, otherwise false. */ public function isRunning(): bool { return $this->channel !== null; } /** * Spawns the thread and begins the thread's execution. * * @return Promise<null> Resolved once the thread has started. * * @throws \Amp\Parallel\Context\StatusError If the thread has already been started. * @throws \Amp\Parallel\Context\ContextException If starting the thread was unsuccessful. */ public function start(): Promise { if ($this->oid !== 0) { throw new StatusError('The thread has already been started.'); } $this->oid = \getmypid(); $sockets = @\stream_socket_pair( \stripos(\PHP_OS, "win") === 0 ? STREAM_PF_INET : STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP ); if ($sockets === false) { $message = "Failed to create socket pair"; if ($error = \error_get_last()) { $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); } return new Failure(new ContextException($message)); } list($channel, $this->socket) = $sockets; $thread = $this->thread = new Internal\Thread($this->socket, $this->function, $this->args); if (!$this->thread->start(\PTHREADS_INHERIT_INI)) { return new Failure(new ContextException('Failed to start the thread.')); } $channel = $this->channel = new ChannelledSocket($channel, $channel); $this->watcher = Loop::repeat(self::EXIT_CHECK_FREQUENCY, static function ($watcher) use ($thread, $channel) { if (!$thread->isRunning()) { // Delay closing to avoid race condition between thread exiting and data becoming available. Loop::delay(self::EXIT_CHECK_FREQUENCY, [$channel, "close"]); Loop::cancel($watcher); } }); Loop::disable($this->watcher); return new Success; } /** * Immediately kills the context. * * @throws ContextException If killing the thread was unsuccessful. */ public function kill() { if ($this->thread !== null) { try { if ($this->thread->isRunning() && !$this->thread->kill()) { throw new ContextException('Could not kill thread.'); } } finally { $this->close(); } } } /** * Closes channel and socket if still open. */ private function close() { if ($this->channel !== null) { $this->channel->close(); } $this->channel = null; Loop::cancel($this->watcher); } /** * Gets a promise that resolves when the context ends and joins with the * parent context. * * @return \Amp\Promise<mixed> * * @throws StatusError Thrown if the context has not been started. * @throws SynchronizationError Thrown if an exit status object is not received. * @throws ContextException If the context stops responding. */ public function join(): Promise { if ($this->channel == null || $this->thread === null) { throw new StatusError('The thread has not been started or has already finished.'); } return call(function () { Loop::enable($this->watcher); try { $response = yield $this->channel->receive(); if (!$response instanceof ExitResult) { throw new SynchronizationError('Did not receive an exit result from thread.'); } } catch (ChannelException $exception) { $this->kill(); throw new ContextException( "The context stopped responding, potentially due to a fatal error or calling exit", 0, $exception ); } catch (\Throwable $exception) { $this->kill(); throw $exception; } finally { Loop::disable($this->watcher); $this->close(); } return $response->getResult(); }); } /** * {@inheritdoc} */ public function receive(): Promise { if ($this->channel === null) { throw new StatusError('The process has not been started.'); } return call(function () { Loop::enable($this->watcher); try { $data = yield $this->channel->receive(); } finally { Loop::disable($this->watcher); } if ($data instanceof ExitResult) { $data = $data->getResult(); throw new SynchronizationError(\sprintf( 'Thread process unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data) )); } return $data; }); } /** * {@inheritdoc} */ public function send($data): Promise { if ($this->channel === null) { throw new StatusError('The thread has not been started or has already finished.'); } if ($data instanceof ExitResult) { throw new \Error('Cannot send exit result objects.'); } return call(function () use ($data) { Loop::enable($this->watcher); try { $result = yield $this->channel->send($data); } finally { Loop::disable($this->watcher); } return $result; }); } } <?php namespace Amp\Parallel\Context; use Amp\Parallel\Sync\Channel; use Amp\Promise; interface Context extends Channel { /** * @return bool */ public function isRunning(): bool; /** * Starts the execution context. * * @return Promise<null> Resolved once the context has started. */ public function start(): Promise; /** * Immediately kills the context. */ public function kill(); /** * @return \Amp\Promise<mixed> Resolves with the returned from the context. * * @throws \Amp\Parallel\Context\ContextException If the context dies unexpectedly. * @throws \Amp\Parallel\Sync\PanicError If the context throws an uncaught exception. */ public function join(): Promise; } <?php namespace Amp\Parallel\Context; use Amp\Loop; use Amp\Parallel\Sync\ChannelException; use Amp\Parallel\Sync\ExitResult; use Amp\Parallel\Sync\SynchronizationError; use Amp\Process\Process as BaseProcess; use Amp\Process\ProcessInputStream; use Amp\Process\ProcessOutputStream; use Amp\Promise; use function Amp\call; final class Process implements Context { const SCRIPT_PATH = __DIR__ . "/Internal/process-runner.php"; const KEY_LENGTH = 32; /** @var string|null External version of SCRIPT_PATH if inside a PHAR. */ private static $pharScriptPath; /** @var string|null PHAR path with a '.phar' extension. */ private static $pharCopy; /** @var string|null Cached path to located PHP binary. */ private static $binaryPath; /** @var Internal\ProcessHub */ private $hub; /** @var \Amp\Process\Process */ private $process; /** @var \Amp\Parallel\Sync\ChannelledSocket */ private $channel; /** * Creates and starts the process at the given path using the optional PHP binary path. * * @param string|array $script Path to PHP script or array with first element as path and following elements options * to the PHP script (e.g.: ['bin/worker', 'Option1Value', 'Option2Value']. * @param string|null $cwd Working directory. * @param mixed[] $env Array of environment variables. * @param string $binary Path to PHP binary. Null will attempt to automatically locate the binary. * * @return Promise<Process> */ public static function run($script, string $cwd = null, array $env = [], string $binary = null): Promise { $process = new self($script, $cwd, $env, $binary); return call(function () use ($process) { yield $process->start(); return $process; }); } /** * @param string|array $script Path to PHP script or array with first element as path and following elements options * to the PHP script (e.g.: ['bin/worker', 'Option1Value', 'Option2Value']. * @param string|null $cwd Working directory. * @param mixed[] $env Array of environment variables. * @param string $binary Path to PHP binary. Null will attempt to automatically locate the binary. * * @throws \Error If the PHP binary path given cannot be found or is not executable. */ public function __construct($script, string $cwd = null, array $env = [], string $binary = null) { $this->hub = Loop::getState(self::class); if (!$this->hub instanceof Internal\ProcessHub) { $this->hub = new Internal\ProcessHub; Loop::setState(self::class, $this->hub); } $options = [ "html_errors" => "0", "display_errors" => "0", "log_errors" => "1", ]; if ($binary === null) { if (\PHP_SAPI === "cli") { $binary = \PHP_BINARY; } else { $binary = self::$binaryPath ?? self::locateBinary(); } } elseif (!\is_executable($binary)) { throw new \Error(\sprintf("The PHP binary path '%s' was not found or is not executable", $binary)); } // Write process runner to external file if inside a PHAR, // because PHP can't open files inside a PHAR directly except for the stub. if (\strpos(self::SCRIPT_PATH, "phar://") === 0) { if (self::$pharScriptPath) { $scriptPath = self::$pharScriptPath; } else { $path = \dirname(self::SCRIPT_PATH); if (\substr(\Phar::running(false), -5) !== ".phar") { self::$pharCopy = \sys_get_temp_dir() . "/phar-" . \bin2hex(\random_bytes(10)) . ".phar"; \copy(\Phar::running(false), self::$pharCopy); \register_shutdown_function(static function () { @\unlink(self::$pharCopy); }); $path = "phar://" . self::$pharCopy . "/" . \substr($path, \strlen(\Phar::running(true))); } $contents = \file_get_contents(self::SCRIPT_PATH); $contents = \str_replace("__DIR__", \var_export($path, true), $contents); self::$pharScriptPath = $scriptPath = \tempnam(\sys_get_temp_dir(), "amp-process-runner-"); \file_put_contents($scriptPath, $contents); \register_shutdown_function(static function () { @\unlink(self::$pharScriptPath); }); } // Monkey-patch the script path in the same way, only supported if the command is given as array. if (isset(self::$pharCopy) && \is_array($script) && isset($script[0])) { $script[0] = "phar://" . self::$pharCopy . \substr($script[0], \strlen(\Phar::running(true))); } } else { $scriptPath = self::SCRIPT_PATH; } if (\is_array($script)) { $script = \implode(" ", \array_map("escapeshellarg", $script)); } else { $script = \escapeshellarg($script); } $command = \implode(" ", [ \escapeshellarg($binary), $this->formatOptions($options), \escapeshellarg($scriptPath), $this->hub->getUri(), $script, ]); $this->process = new BaseProcess($command, $cwd, $env); } private static function locateBinary(): string { $executable = \strncasecmp(\PHP_OS, "WIN", 3) === 0 ? "php.exe" : "php"; $paths = \array_filter(\explode(\PATH_SEPARATOR, \getenv("PATH"))); $paths[] = \PHP_BINDIR; $paths = \array_unique($paths); foreach ($paths as $path) { $path .= \DIRECTORY_SEPARATOR . $executable; if (\is_executable($path)) { return self::$binaryPath = $path; } } throw new \Error("Could not locate PHP executable binary"); } private function formatOptions(array $options) { $result = []; foreach ($options as $option => $value) { $result[] = \sprintf("-d%s=%s", $option, $value); } return \implode(" ", $result); } /** * Private method to prevent cloning. */ private function __clone() { } /** * {@inheritdoc} */ public function start(): Promise { return call(function () { try { $pid = yield $this->process->start(); yield $this->process->getStdin()->write($this->hub->generateKey($pid, self::KEY_LENGTH)); $this->channel = yield $this->hub->accept($pid); return $pid; } catch (\Throwable $exception) { $this->process->kill(); throw new ContextException("Starting the process failed", 0, $exception); } }); } /** * {@inheritdoc} */ public function isRunning(): bool { return $this->process->isRunning(); } /** * {@inheritdoc} */ public function receive(): Promise { if ($this->channel === null) { throw new StatusError("The process has not been started"); } return call(function () { try { $data = yield $this->channel->receive(); } catch (ChannelException $e) { throw new ContextException("The context stopped responding, potentially due to a fatal error or calling exit", 0, $e); } if ($data instanceof ExitResult) { $data = $data->getResult(); throw new SynchronizationError(\sprintf( 'Process unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data) )); } return $data; }); } /** * {@inheritdoc} */ public function send($data): Promise { if ($this->channel === null) { throw new StatusError("The process has not been started"); } if ($data instanceof ExitResult) { throw new \Error("Cannot send exit result objects"); } return $this->channel->send($data); } /** * {@inheritdoc} */ public function join(): Promise { if ($this->channel === null) { throw new StatusError("The process has not been started"); } return call(function () { try { $data = yield $this->channel->receive(); if (!$data instanceof ExitResult) { throw new SynchronizationError("Did not receive an exit result from process"); } } catch (\Throwable $exception) { if ($this->isRunning()) { $this->kill(); } throw new ContextException("Failed to receive result from process", 0, $exception); } $this->channel->close(); $code = yield $this->process->join(); if ($code !== 0) { throw new ContextException(\sprintf("Process exited with code %d", $code)); } return $data->getResult(); }); } /** * Send a signal to the process. * * @see \Amp\Process\Process::signal() * * @param int $signo * * @throws \Amp\Process\ProcessException * @throws \Amp\Process\StatusError */ public function signal(int $signo) { $this->process->signal($signo); } /** * Returns the PID of the process. * * @see \Amp\Process\Process::getPid() * * @return int * * @throws \Amp\Process\StatusError */ public function getPid(): int { return $this->process->getPid(); } /** * Returns the STDIN stream of the process. * * @see \Amp\Process\Process::getStdin() * * @return ProcessOutputStream * * @throws \Amp\Process\StatusError */ public function getStdin(): ProcessOutputStream { return $this->process->getStdin(); } /** * Returns the STDOUT stream of the process. * * @see \Amp\Process\Process::getStdout() * * @return ProcessInputStream * * @throws \Amp\Process\StatusError */ public function getStdout(): ProcessInputStream { return $this->process->getStdout(); } /** * Returns the STDOUT stream of the process. * * @see \Amp\Process\Process::getStderr() * * @return ProcessInputStream * * @throws \Amp\Process\StatusError */ public function getStderr(): ProcessInputStream { return $this->process->getStderr(); } /** * {@inheritdoc} */ public function kill() { $this->process->kill(); if ($this->channel !== null) { $this->channel->close(); } } } <?php namespace Amp\Parallel\Context; class StatusError extends \Error { } <?php namespace Amp\Parallel\Sync; class SerializationException extends \Exception { } <?php namespace Amp\Parallel\Sync; class SynchronizationError extends \Error { } <?php namespace Amp\Parallel\Sync\Internal; final class ParcelStorage extends \Threaded { /** @var mixed */ private $value; /** * @param mixed $value */ public function __construct($value) { $this->value = $value; } /** * @return mixed */ public function get() { return $this->value; } /** * @param mixed $value */ public function set($value) { $this->value = $value; } } <?php namespace Amp\Parallel\Sync; use Amp\CallableMaker; use Amp\Parser\Parser; final class ChannelParser extends Parser { use CallableMaker; const HEADER_LENGTH = 5; /** * @param callable(mixed $data) Callback invoked when data is parsed. */ public function __construct(callable $callback) { parent::__construct(self::parser($callback, self::callableFromStaticMethod("errorHandler"))); } /** * @param mixed $data Data to encode to send over a channel. * * @return string Encoded data that can be parsed by this class. * * @throws \Amp\Parallel\Sync\SerializationException */ public function encode($data): string { try { $data = \serialize($data); } catch (\Throwable $exception) { throw new SerializationException( "The given data cannot be sent because it is not serializable.", 0, $exception ); } return \pack("CL", 0, \strlen($data)) . $data; } /** * @param callable $push * @param callable $errorHandler * * @return \Generator * * @throws \Amp\Parallel\Sync\ChannelException * @throws \Amp\Parallel\Sync\SerializationException */ private static function parser(callable $push, callable $errorHandler): \Generator { while (true) { $header = yield self::HEADER_LENGTH; $data = \unpack("Cprefix/Llength", $header); if ($data["prefix"] !== 0) { $data = $header . yield; $data = \preg_replace_callback("/[^\x20-\x7e]/", function (array $matches) { return "\\x" . \dechex(\ord($matches[0])); }, $data); throw new ChannelException("Invalid packet received: " . $data); } $data = yield $data["length"]; \set_error_handler($errorHandler); // Attempt to unserialize the received data. try { $data = \unserialize($data); } catch (\Throwable $exception) { throw new SerializationException("Exception thrown when unserializing data", 0, $exception); } finally { \restore_error_handler(); } $push($data); } } private static function errorHandler($errno, $errstr, $errfile, $errline) { if ($errno & \error_reporting()) { throw new ChannelException(\sprintf( 'Received corrupted data. Errno: %d; %s in file %s on line %d', $errno, $errstr, $errfile, $errline )); } } } <?php namespace Amp\Parallel\Sync; use Amp\Promise; /** * Interface for sending messages between execution contexts. */ interface Channel { /** * @return \Amp\Promise<mixed> * * @throws \Amp\Parallel\Context\StatusError Thrown if the context has not been started. * @throws \Amp\Parallel\Sync\SynchronizationError If the context has not been started or the context * unexpectedly ends. * @throws \Amp\Parallel\Sync\ChannelException If receiving from the channel fails. * @throws \Amp\Parallel\Sync\SerializationException If unserializing the data fails. */ public function receive(): Promise; /** * @param mixed $data * * @return \Amp\Promise<int> Resolves with the number of bytes sent on the channel. * * @throws \Amp\Parallel\Context\StatusError Thrown if the context has not been started. * @throws \Amp\Parallel\Sync\SynchronizationError If the context has not been started or the context * unexpectedly ends. * @throws \Amp\Parallel\Sync\ChannelException If sending on the channel fails. * @throws \Error If an ExitResult object is given. * @throws \Amp\Parallel\Sync\SerializationException If serializing the data fails. */ public function send($data): Promise; } <?php namespace Amp\Parallel\Sync; interface ExitResult { /** * @return mixed Return value of the callable given to the execution context. * * @throws \Amp\Parallel\Sync\PanicError If the context exited with an uncaught exception. */ public function getResult(); } <?php namespace Amp\Parallel\Sync; class SharedMemoryException extends \Exception { } <?php namespace Amp\Parallel\Sync; use Amp\Promise; /** * A parcel object for sharing data across execution contexts. * * A parcel is an object that stores a value in a safe way that can be shared * between different threads or processes. Different handles to the same parcel * will access the same data, and a parcel handle itself is serializable and * can be transported to other execution contexts. * * Wrapping and unwrapping values in the parcel are not atomic. To prevent race * conditions and guarantee safety, you should use the provided synchronization * methods to acquire a lock for exclusive access to the parcel first before * accessing the contained value. */ interface Parcel { /** * Asynchronously invokes a callback while maintaining an exclusive lock on the parcel. The current value of the * parcel is provided as the first argument to the callback function. * * @param callable $callback The synchronized callback to invoke. The parcel value is given as the single argument * to the callback function. The callback may be a regular function or a coroutine. * * @return \Amp\Promise<mixed> Resolves with the return value of $callback or fails if $callback * throws an exception. */ public function synchronized(callable $callback): Promise; /** * @return \Amp\Promise<mixed> A promise for the value inside the parcel. */ public function unwrap(): Promise; } <?php namespace Amp\Parallel\Sync; use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\Promise; final class ChannelledSocket implements Channel { /** @var ChannelledStream */ private $channel; /** @var ResourceInputStream */ private $read; /** @var ResourceOutputStream */ private $write; /** * @param resource $read Readable stream resource. * @param resource $write Writable stream resource. * * @throws \Error If a stream resource is not given for $resource. */ public function __construct($read, $write) { $this->channel = new ChannelledStream( $this->read = new ResourceInputStream($read), $this->write = new ResourceOutputStream($write) ); } /** * {@inheritdoc} */ public function receive(): Promise { return $this->channel->receive(); } /** * {@inheritdoc} */ public function send($data): Promise { return $this->channel->send($data); } /** * Closes the read and write resource streams. */ public function close() { $this->read->close(); $this->write->close(); } } <?php namespace Amp\Parallel\Sync; use Amp\Failure; use Amp\Promise; use Amp\Success; use Amp\Sync\PosixSemaphore; use function Amp\call; /** * A container object for sharing a value across contexts. * * A shared object is a container that stores an object inside shared memory. * The object can be accessed and mutated by any thread or process. The shared * object handle itself is serializable and can be sent to any thread or process * to give access to the value that is shared in the container. * * Because each shared object uses its own shared memory segment, it is much * more efficient to store a larger object containing many values inside a * single shared container than to use many small shared containers. * * Note that accessing a shared object is not atomic. Access to a shared object * should be protected with a mutex to preserve data integrity. * * When used with forking, the object must be created prior to forking for both * processes to access the synchronized object. * * @see http://php.net/manual/en/book.shmop.php The shared memory extension. * @see http://man7.org/linux/man-pages/man2/shmctl.2.html How shared memory works on Linux. * @see https://msdn.microsoft.com/en-us/library/ms810613.aspx How shared memory works on Windows. */ final class SharedMemoryParcel implements Parcel { /** @var int The byte offset to the start of the object data in memory. */ const MEM_DATA_OFFSET = 7; // A list of valid states the object can be in. const STATE_UNALLOCATED = 0; const STATE_ALLOCATED = 1; const STATE_MOVED = 2; const STATE_FREED = 3; /** @var string */ private $id; /** @var int The shared memory segment key. */ private $key; /** @var PosixSemaphore A semaphore for synchronizing on the parcel. */ private $semaphore; /** @var int An open handle to the shared memory segment. */ private $handle; /** @var int */ private $initializer = 0; /** * @param string $id * @param mixed $value * @param int $size The initial size in bytes of the shared memory segment. It will automatically be expanded as * necessary. * @param int $permissions Permissions to access the semaphore. Use file permission format specified as 0xxx. * * @return \Amp\Parallel\Sync\SharedMemoryParcel */ public static function create(string $id, $value, int $size = 8192, int $permissions = 0600): self { $parcel = new self($id); $parcel->init($value, $size, $permissions); return $parcel; } /** * @param string $id * * @return \Amp\Parallel\Sync\SharedMemoryParcel */ public static function use(string $id): self { $parcel = new self($id); $parcel->open(); return $parcel; } /** * Creates a new local object container. * * The object given will be assigned a new object ID and will have a * reference to it stored in memory local to the thread. * * @param mixed $value The value to store in the container. * @param int $size The number of bytes to allocate for the object. * If not specified defaults to 16384 bytes. * @param int $permissions The access permissions to set for the object. * If not specified defaults to 0600. */ private function __construct(string $id) { if (!\extension_loaded("shmop")) { throw new \Error(__CLASS__ . " requires the shmop extension."); } $this->id = $id; $this->key = self::makeKey($this->id); } /** * @param mixed $value * @param int $size * @param int $permissions */ private function init($value, int $size = 8192, int $permissions = 0600) { $this->semaphore = PosixSemaphore::create($this->id, 1); $this->initializer = \getmypid(); $this->memOpen($this->key, 'n', $permissions, $size + self::MEM_DATA_OFFSET); $this->setHeader(self::STATE_ALLOCATED, 0, $permissions); $this->wrap($value); } private function open() { $this->semaphore = PosixSemaphore::use($this->id); $this->memOpen($this->key, 'w', 0, 0); } /** * Checks if the object has been freed. * * Note that this does not check if the object has been destroyed; it only * checks if this handle has freed its reference to the object. * * @return bool True if the object is freed, otherwise false. */ private function isFreed(): bool { // If we are no longer connected to the memory segment, check if it has // been invalidated. if ($this->handle !== null) { $this->handleMovedMemory(); $header = $this->getHeader(); return $header['state'] === static::STATE_FREED; } return true; } /** * {@inheritdoc} */ public function unwrap(): Promise { if ($this->isFreed()) { return new Failure(new SharedMemoryException('The object has already been freed.')); } $header = $this->getHeader(); // Make sure the header is in a valid state and format. if ($header['state'] !== self::STATE_ALLOCATED || $header['size'] <= 0) { new Failure(new SharedMemoryException('Shared object memory is corrupt.')); } // Read the actual value data from memory and unserialize it. $data = $this->memGet(self::MEM_DATA_OFFSET, $header['size']); return new Success(\unserialize($data)); } /** * If the value requires more memory to store than currently allocated, a * new shared memory segment will be allocated with a larger size to store * the value in. The previous memory segment will be cleaned up and marked * for deletion. Other processes and threads will be notified of the new * memory segment on the next read attempt. Once all running processes and * threads disconnect from the old segment, it will be freed by the OS. */ protected function wrap($value) { if ($this->isFreed()) { throw new SharedMemoryException('The object has already been freed.'); } $serialized = \serialize($value); $size = \strlen($serialized); $header = $this->getHeader(); /* If we run out of space, we need to allocate a new shared memory segment that is larger than the current one. To coordinate with other processes, we will leave a message in the old segment that the segment has moved and along with the new key. The old segment will be discarded automatically after all other processes notice the change and close the old handle. */ if (\shmop_size($this->handle) < $size + self::MEM_DATA_OFFSET) { $this->key = $this->key < 0xffffffff ? $this->key + 1 : \mt_rand(0x10, 0xfffffffe); $this->setHeader(self::STATE_MOVED, $this->key, 0); $this->memDelete(); \shmop_close($this->handle); $this->memOpen($this->key, 'n', $header['permissions'], $size * 2); } // Rewrite the header and the serialized value to memory. $this->setHeader(self::STATE_ALLOCATED, $size, $header['permissions']); $this->memSet(self::MEM_DATA_OFFSET, $serialized); } /** * {@inheritdoc} */ public function synchronized(callable $callback): Promise { return call(function () use ($callback) { /** @var \Amp\Sync\Lock $lock */ $lock = yield $this->semaphore->acquire(); try { $result = yield call($callback, yield $this->unwrap()); if ($result !== null) { $this->wrap($result); } } finally { $lock->release(); } return $result; }); } /** * Frees the shared object from memory. * * The memory containing the shared value will be invalidated. When all * process disconnect from the object, the shared memory block will be * destroyed by the OS. */ public function __destruct() { if ($this->initializer === 0 || $this->initializer !== \getmypid()) { return; } if ($this->isFreed()) { return; } // Invalidate the memory block by setting its state to FREED. $this->setHeader(static::STATE_FREED, 0, 0); // Request the block to be deleted, then close our local handle. $this->memDelete(); \shmop_close($this->handle); $this->handle = null; $this->semaphore = null; } /** * Private method to prevent cloning. */ private function __clone() { } /** * Private method to prevent serialization. */ private function __sleep() { } /** * Updates the current memory segment handle, handling any moves made on the * data. */ private function handleMovedMemory() { // Read from the memory block and handle moved blocks until we find the // correct block. while (true) { $header = $this->getHeader(); // If the state is STATE_MOVED, the memory is stale and has been moved // to a new location. Move handle and try to read again. if ($header['state'] !== self::STATE_MOVED) { break; } \shmop_close($this->handle); $this->key = $header['size']; $this->memOpen($this->key, 'w', 0, 0); } } /** * Reads and returns the data header at the current memory segment. * * @return array An associative array of header data. */ private function getHeader(): array { $data = $this->memGet(0, self::MEM_DATA_OFFSET); return \unpack('Cstate/Lsize/Spermissions', $data); } /** * Sets the header data for the current memory segment. * * @param int $state An object state. * @param int $size The size of the stored data, or other value. * @param int $permissions The permissions mask on the memory segment. */ private function setHeader(int $state, int $size, int $permissions) { $header = \pack('CLS', $state, $size, $permissions); $this->memSet(0, $header); } /** * Opens a shared memory handle. * * @param int $key The shared memory key. * @param string $mode The mode to open the shared memory in. * @param int $permissions Process permissions on the shared memory. * @param int $size The size to crate the shared memory in bytes. */ private function memOpen(int $key, string $mode, int $permissions, int $size) { $this->handle = @\shmop_open($key, $mode, $permissions, $size); if ($this->handle === false) { throw new SharedMemoryException('Failed to create shared memory block.'); } } /** * Reads binary data from shared memory. * * @param int $offset The offset to read from. * @param int $size The number of bytes to read. * * @return string The binary data at the given offset. */ private function memGet(int $offset, int $size): string { $data = \shmop_read($this->handle, $offset, $size); if ($data === false) { throw new SharedMemoryException('Failed to read from shared memory block.'); } return $data; } /** * Writes binary data to shared memory. * * @param int $offset The offset to write to. * @param string $data The binary data to write. */ private function memSet(int $offset, string $data) { if (!\shmop_write($this->handle, $data, $offset)) { throw new SharedMemoryException('Failed to write to shared memory block.'); } } /** * Requests the shared memory segment to be deleted. */ private function memDelete() { if (!\shmop_delete($this->handle)) { throw new SharedMemoryException('Failed to discard shared memory block.'); } } private static function makeKey(string $id): int { return \abs(\unpack("l", \md5($id, true))[1]); } } <?php namespace Amp\Parallel\Sync; final class ExitSuccess implements ExitResult { /** @var mixed */ private $result; public function __construct($result) { $this->result = $result; } /** * {@inheritdoc} */ public function getResult() { return $this->result; } } <?php namespace Amp\Parallel\Sync; final class ExitFailure implements ExitResult { /** @var string */ private $type; /** @var string */ private $message; /** @var int|string */ private $code; /** @var array */ private $trace; public function __construct(\Throwable $exception) { $this->type = \get_class($exception); $this->message = $exception->getMessage(); $this->code = $exception->getCode(); $this->trace = $exception->getTraceAsString(); } /** * {@inheritdoc} */ public function getResult() { throw new PanicError( $this->type, \sprintf( 'Uncaught %s in execution context with message "%s" and code "%s"', $this->type, $this->message, $this->code ), $this->trace ); } } <?php namespace Amp\Parallel\Sync; final class PanicError extends \Error { /** @var string Class name of uncaught exception. */ private $name; /** @var string Stack trace of the panic. */ private $trace; /** * Creates a new panic error. * * @param string $name The uncaught exception class. * @param string $message The panic message. * @param string $trace The panic stack trace. */ public function __construct(string $name, string $message = '', string $trace = '') { parent::__construct($message); $this->name = $name; $this->trace = $trace; } /** * Returns the class name of the uncaught exception. * * @return string */ public function getName(): string { return $this->name; } /** * Gets the stack trace at the point the panic occurred. * * @return string */ public function getPanicTrace(): string { return $this->trace; } } <?php namespace Amp\Parallel\Sync; class ChannelException extends \Exception { } <?php namespace Amp\Parallel\Sync; use Amp\Promise; use Amp\Success; use Amp\Sync\ThreadedMutex; use function Amp\call; /** * A thread-safe container that shares a value between multiple threads. */ final class ThreadedParcel implements Parcel { /** @var \Amp\Sync\ThreadedMutex */ private $mutex; /** @var \Threaded */ private $storage; /** * Creates a new shared object container. * * @param mixed $value The value to store in the container. */ public function __construct($value) { $this->mutex = new ThreadedMutex; $this->storage = new Internal\ParcelStorage($value); } /** * {@inheritdoc} */ public function unwrap(): Promise { return new Success($this->storage->get()); } /** * @return \Amp\Promise */ public function synchronized(callable $callback): Promise { return call(function () use ($callback) { /** @var \Amp\Sync\Lock $lock */ $lock = yield $this->mutex->acquire(); try { $result = yield call($callback, $this->storage->get()); if ($result !== null) { $this->storage->set($result); } } finally { $lock->release(); } return $result; }); } } <?php namespace Amp\Parallel\Sync; use Amp\ByteStream\InputStream; use Amp\ByteStream\OutputStream; use Amp\ByteStream\StreamException; use Amp\Promise; use function Amp\call; /** * An asynchronous channel for sending data between threads and processes. * * Supports full duplex read and write. */ final class ChannelledStream implements Channel { /** @var \Amp\ByteStream\InputStream */ private $read; /** @var \Amp\ByteStream\OutputStream */ private $write; /** @var \SplQueue */ private $received; /** @var \Amp\Parser\Parser */ private $parser; /** * Creates a new channel from the given stream objects. Note that $read and $write can be the same object. * * @param \Amp\ByteStream\InputStream $read * @param \Amp\ByteStream\OutputStream $write */ public function __construct(InputStream $read, OutputStream $write) { $this->read = $read; $this->write = $write; $this->received = new \SplQueue; $this->parser = new ChannelParser([$this->received, 'push']); } /** * {@inheritdoc} */ public function send($data): Promise { return call(function () use ($data) { try { return yield $this->write->write($this->parser->encode($data)); } catch (StreamException $exception) { throw new ChannelException("Sending on the channel failed. Did the context die?", 0, $exception); } }); } /** * {@inheritdoc} */ public function receive(): Promise { return call(function () { while ($this->received->isEmpty()) { try { $chunk = yield $this->read->read(); } catch (StreamException $exception) { throw new ChannelException("Reading from the channel failed. Did the context die?", 0, $exception); } if ($chunk === null) { throw new ChannelException("The channel closed unexpectedly. Did the context die?"); } $this->parser->push($chunk); } return $this->received->shift(); }); } } <?php require \dirname(__DIR__) . '/vendor/autoload.php'; use Amp\Delayed; use Amp\Websocket\Client\Connection; use Amp\Websocket\Message; use function Amp\Websocket\Client\connect; Amp\Loop::run(function () { /** @var Connection $connection */ $connection = yield connect('wss://demos.kaazing.com/echo'); yield $connection->send('Hello!'); $i = 0; /** @var Message $message */ while ($message = yield $connection->receive()) { $payload = yield $message->buffer(); \printf("Received: %s\n", $payload); if ($payload === 'Goodbye!') { yield $connection->close(); break; } yield new Delayed(1000); if ($i < 3) { yield $connection->send('Ping: ' . ++$i); } else { yield $connection->send('Goodbye!'); } } }); <?php require \dirname(__DIR__) . '/vendor/autoload.php'; use Amp\Delayed; use Amp\Websocket\Client\Connection; use Amp\Websocket\Client\Handshake; use Amp\Websocket\Message; use function Amp\Websocket\Client\connect; // Connects to the websocket endpoint in examples/broadcast-server/server.php provided in // amphp/websocket-server (https://github.com/amphp/websocket-server). Amp\Loop::run(function () { $handshake = (new Handshake('ws://localhost:1337/broadcast')) ->withHeader('Origin', 'http://localhost:1337'); /** @var Connection $connection */ $connection = yield connect($handshake); yield $connection->send('Hello!'); $i = 0; /** @var Message $message */ while ($message = yield $connection->receive()) { $payload = yield $message->buffer(); \printf("Received: %s\n", $payload); if (\strpos($payload, 'Goodbye!') !== false) { yield $connection->close(); break; } yield new Delayed(1000); if ($i < 3) { yield $connection->send('Ping: ' . ++$i); } else { yield $connection->send('Goodbye!'); } } }); <?php use Amp\ByteStream\StreamException; use Amp\Loop; use Amp\Websocket\Client; use Amp\Websocket\Client\Connection; use Amp\Websocket\Client\Handshake; use Amp\Websocket\ClosedException; use Amp\Websocket\Message; use Amp\Websocket\Options; require __DIR__ . '/../vendor/autoload.php'; const AGENT = 'amphp/websocket'; Loop::run(function () { $errors = 0; $options = Options::createClientDefault() ->withBytesPerSecondLimit(\PHP_INT_MAX) ->withFrameSizeLimit(\PHP_INT_MAX) ->withFramesPerSecondLimit(\PHP_INT_MAX) ->withMessageSizeLimit(\PHP_INT_MAX) ->withValidateUtf8(true); /** @var Connection $connection */ $connection = yield Client\connect('ws://127.0.0.1:9001/getCaseCount'); /** @var Message $message */ $message = yield $connection->receive(); $cases = (int) yield $message->buffer(); echo "Going to run {$cases} test cases." . PHP_EOL; for ($i = 1; $i < $cases; $i++) { $connection = yield Client\connect('ws://127.0.0.1:9001/getCaseInfo?case=' . $i . '&agent=' . AGENT); $message = yield $connection->receive(); $info = \json_decode(yield $message->buffer(), true); print $info['id'] . ' ' . \str_repeat('-', 80 - \strlen($info['id']) - 1) . PHP_EOL; print \wordwrap($info['description'], 80, PHP_EOL) . ' '; $handshake = new Handshake('ws://127.0.0.1:9001/runCase?case=' . $i . '&agent=' . AGENT, $options); $connection = yield Client\connect($handshake); try { while ($message = yield $connection->receive()) { $content = yield $message->buffer(); if ($message->isBinary()) { yield $connection->sendBinary($content); } else { yield $connection->send($content); } } } catch (ClosedException $e) { // ignore } catch (AssertionError $e) { print 'Assertion error: ' . $e->getMessage() . PHP_EOL; $connection->close(); } catch (Error $e) { print 'Error: ' . $e->getMessage() . PHP_EOL; $connection->close(); } catch (StreamException $e) { print 'Stream exception: ' . $e->getMessage() . PHP_EOL; $connection->close(); } $connection = yield Client\connect('ws://127.0.0.1:9001/getCaseStatus?case=' . $i . '&agent=' . AGENT); $message = yield $connection->receive(); print($result = \json_decode(yield $message->buffer(), true)['behavior']); if ($result === 'FAILED') { $errors++; } print PHP_EOL . PHP_EOL; } $connection = yield Client\connect('ws://127.0.0.1:9001/updateReports?agent=' . AGENT); $connection->close(); Loop::stop(); if ($errors) { exit(1); } }); { "url": "ws://127.0.0.1:9001", "outdir": "./reports/clients", "cases": [ "*" ], "exclude-cases": [ "12.2*", "12.3*", "12.4*", "12.5*" ] } { "name": "amphp/websocket-client", "description": "Async WebSocket client for PHP based on Amp.", "license": "MIT", "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "support": { "issues": "https://github.com/amphp/websocket-client/issues" }, "keywords": [ "async", "non-blocking", "websocket", "client", "http", "amp", "amphp" ], "require": { "php": ">=7.1", "amphp/amp": "^2", "amphp/http": "^1.1", "amphp/socket": "^0.10", "amphp/websocket": "dev-master as 1.0", "league/uri-schemes": "^1.2" }, "require-dev": { "amphp/http-server": "^1", "amphp/websocket-server": "dev-master as 2.0", "amphp/phpunit-util": "^1", "amphp/php-cs-fixer-config": "dev-master", "phpunit/phpunit": "^6" }, "autoload": { "psr-4": { "Amp\\Websocket\\Client\\": "src" }, "files": [ "src/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Websocket\\Client\\Test\\": "test" } }, "config": { "platform": { "php": "7.1" } } } <?php namespace Amp\Websocket\Client\Test\Helper; use Amp\Http\Server\Request; use Amp\Http\Server\Response; use Amp\Promise; use Amp\Success; use Amp\Websocket\Client; use Amp\Websocket\Server\Websocket; class WebsocketAdapter extends Websocket { public function onHandshake(Request $request, Response $response): Promise { return new Success($response); } public function onConnect(Client $client, Request $request, Response $response): ?Promise { return null; } } <?php namespace Amp\Websocket\Client\Test; use Amp\Http\Server\Request; use Amp\Http\Server\Response; use Amp\Http\Server\Server; use Amp\PHPUnit\TestCase; use Amp\Promise; use Amp\Socket; use Amp\Websocket\Client; use Amp\Websocket\ClosedException; use Amp\Websocket\Message; use Amp\Websocket\Options; use Amp\Websocket\Server\Websocket; use Psr\Log\NullLogger; use function Amp\call; use function Amp\Websocket\Client\connect; class WebSocketTest extends TestCase { /** @var Server[] */ private $servers = []; protected function tearDown() { $promises = []; foreach ($this->servers as $server) { $promises[] = $server->stop(); } Promise\wait(Promise\all($promises)); parent::tearDown(); } /** * This method creates a new server that listens on a randomly assigned port and returns the used port. * * The server will automatically shut down after a test case ends. * * @param Websocket $websocket * * @return Promise<int> Resolves to the used port number. */ public function createServer(Websocket $websocket): Promise { $socket = Socket\listen('tcp://127.0.0.1:0'); $port = (int) \explode(':', $socket->getAddress())[1]; $server = new Server([$socket], $websocket, new NullLogger); $this->servers[] = $server; return call(function () use ($server, $port) { yield $server->start(); return $port; }); } public function testSimpleBinaryEcho() { Promise\wait(call(function () { $port = yield $this->createServer(new class extends Helper\WebsocketAdapter { public function onConnect(Client $client, Request $request, Response $response): Promise { return call(function () use ($client) { while ($message = yield $client->receive()) { \assert($message instanceof Message); if ($message->isBinary()) { yield $client->sendBinary(yield $message->buffer()); } yield $client->send(yield $message->buffer()); } }); } }); /** @var Client $client */ $client = yield connect('ws://127.0.0.1:' . $port . '/'); $client->sendBinary('Hey!'); /** @var Message $message */ $message = yield $client->receive(); $this->assertInstanceOf(Message::class, $message); $this->assertTrue($message->isBinary()); $this->assertSame('Hey!', yield $message->buffer()); $promise = $client->receive(); $client->close(); $this->assertNull(yield $promise); })); } public function testSimpleTextEcho() { Promise\wait(call(function () { $port = yield $this->createServer(new class extends Helper\WebsocketAdapter { public function onConnect(Client $client, Request $request, Response $response): Promise { return call(function () use ($client) { while ($message = yield $client->receive()) { \assert($message instanceof Message); if ($message->isBinary()) { yield $client->sendBinary(yield $message->buffer()); } yield $client->send(yield $message->buffer()); } }); } }); /** @var Client $client */ $client = yield connect('ws://localhost:' . $port . '/'); $client->send('Hey!'); /** @var Message $message */ $message = yield $client->receive(); $this->assertInstanceOf(Message::class, $message); $this->assertFalse($message->isBinary()); $this->assertSame('Hey!', yield $message->buffer()); $promise = $client->receive(); $client->close(); $this->assertNull(yield $promise); })); } public function testUnconsumedMessage() { Promise\wait(call(function () { $port = yield $this->createServer(new class extends Helper\WebsocketAdapter { public function onConnect(Client $client, Request $request, Response $response): Promise { return call(function () use ($client) { yield $client->send(\str_repeat('.', 1024 * 1024 * 1)); yield $client->send('Message'); }); } }); /** @var Client $client */ $client = yield connect('ws://localhost:' . $port . '/'); /** @var Message $message */ $message = yield $client->receive(); $this->assertInstanceOf(Message::class, $message); // Do not consume the bytes from the first message. $message = yield $client->receive(); $this->assertFalse($message->isBinary()); $this->assertSame('Message', yield $message->buffer()); $this->assertInstanceOf(Message::class, $message); $promise = $client->receive(); $client->close(); $this->assertNull(yield $promise); })); } public function testVeryLongMessage() { Promise\wait(call(function () { $options = Options::createClientDefault() ->withBytesPerSecondLimit(\PHP_INT_MAX) ->withFramesPerSecondLimit(\PHP_INT_MAX) ->withMessageSizeLimit(1024 * 1024 * 10) ->withoutCompression(); $port = yield $this->createServer(new class($options) extends Helper\WebsocketAdapter { public function onConnect(Client $client, Request $request, Response $response): Promise { $payload = \str_repeat('.', 1024 * 1024 * 10); // 10 MiB return $client->sendBinary($payload); } }); /** @var Client $client */ $client = yield connect(new Client\Handshake('ws://localhost:' . $port . '/', $options)); /** @var Message $message */ $message = yield $client->receive(); $this->assertSame(\str_repeat('.', 1024 * 1024 * 10), yield $message->buffer()); })); } public function testTooLongMessage() { Promise\wait(call(function () { $options = Options::createClientDefault() ->withBytesPerSecondLimit(\PHP_INT_MAX) ->withFramesPerSecondLimit(\PHP_INT_MAX) ->withMessageSizeLimit(1024 * 1024 * 10) ->withoutCompression(); $port = yield $this->createServer(new class($options) extends Helper\WebsocketAdapter { public function onConnect(Client $client, Request $request, Response $response): Promise { $payload = \str_repeat('.', 1024 * 1024 * 10 + 1); // 10 MiB + 1 byte return $client->sendBinary($payload); } }); /** @var Client $client */ $client = yield connect(new Client\Handshake('ws://localhost:' . $port . '/', $options)); try { /** @var Message $message */ $message = yield $client->receive(); yield $message->buffer(); } catch (ClosedException $exception) { $this->assertSame('Received payload exceeds maximum allowable size', $exception->getReason()); } })); } } <?php namespace Amp\Websocket\Client; final class ConnectionException extends \Exception { } <?php namespace Amp\Websocket\Client; use Amp\Http\Message; use Amp\Websocket\Options; use League\Uri\UriException; use League\Uri\Ws; final class Handshake extends Message { /** @var Ws */ private $uri; /** @var Options */ private $options; /** * @param string|Ws $uri target address of websocket (e.g. ws://foo.bar/bar or * wss://crypto.example/?secureConnection) or a \League\Uri\Ws instance. * @param Options|null $options * @param string[]|string[][] $headers * * @throws \TypeError If $uri is not a string or an instance of \League\Uri\Ws. * @throws \Error If compression is enabled in the options but the zlib extension is not installed. */ public function __construct($uri, ?Options $options = null, array $headers = []) { $this->uri = $this->makeUri($uri); $this->options = $this->checkOptions($options); if (!empty($headers)) { $this->setHeaders($headers); } } /** * @return Ws Websocket URI (scheme will be either ws or wss). */ public function getUri(): Ws { return $this->uri; } /** * @param $uri string|Ws * * @return self Cloned object */ public function withUri($uri): self { $clone = clone $this; $clone->uri = $clone->makeUri($uri); return $clone; } private function makeUri($uri): Ws { if (\is_string($uri)) { try { return Ws::createFromString($uri); } catch (UriException $exception) { throw new \Error('Invalid Websocket URI provided', 0, $exception); } } if (!$uri instanceof Ws) { throw new \TypeError(\sprintf('Must provide an instance of %s or a URL as a string', Ws::class)); } return $uri; } /** * @return Options */ public function getOptions(): Options { return $this->options; } /** * @param Options $options * * @return self Cloned object. */ public function withOptions(Options $options): self { $clone = clone $this; $clone->options = $clone->checkOptions($options); return $clone; } private function checkOptions(?Options $options): Options { if ($options === null) { return Options::createClientDefault(); } if ($options->isCompressionEnabled() && !\extension_loaded('zlib')) { throw new \Error('Compression is enabled in options, but the zlib extension is not loaded'); } return $options; } /** * Replaces all headers in the returned instance. * * @param string[]|string[][] $headers * * @return self Cloned object. */ public function withHeaders(array $headers): self { $clone = clone $this; $clone->setHeaders($headers); return $clone; } /** * Replaces the given header in the returned instance. * * @param string $name * @param string|string[] $value * * @return self Cloned object. */ public function withHeader(string $name, $value): self { $clone = clone $this; $clone->setHeader($name, $value); return $clone; } /** * Adds the given header in the returned instance. * * @param string $name * @param string|string[] $value * * @return self Cloned object. */ public function withAddedHeader(string $name, $value): self { $clone = clone $this; $clone->addHeader($name, $value); return $clone; } /** * Removes the given header in the returned instance. * * @param string $name * * @return self Cloned object. */ public function withoutHeader(string $name): self { $clone = clone $this; $clone->removeHeader($name); return $clone; } } <?php namespace Amp\Websocket\Client\Internal; use Amp\Promise; use Amp\Success; class ClientSocket extends \Amp\Socket\ClientSocket { /** @var string|null */ private $buffer; public function __construct($resource, string $buffer, int $chunkSize = self::DEFAULT_CHUNK_SIZE) { parent::__construct($resource, $chunkSize); $this->buffer = $buffer !== '' ? $buffer : null; } public function read(): Promise { if ($this->buffer !== null) { $buffer = $this->buffer; $this->buffer = null; return new Success($buffer); } return parent::read(); } } <?php namespace Amp\Websocket\Client; use Amp\CancellationToken; use Amp\Loop; use Amp\Promise; use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientTlsContext; const LOOP_CONNECTOR_IDENTIFIER = Connector::class; /** * Set or access the global websocket Connector instance. * * @param Connector|null $connector * * @return Connector */ function connector(?Connector $connector = null): Connector { if ($connector === null) { $connector = Loop::getState(LOOP_CONNECTOR_IDENTIFIER); if ($connector) { return $connector; } $connector = new Rfc6455Connector; } Loop::setState(LOOP_CONNECTOR_IDENTIFIER, $connector); return $connector; } /** * @param string|Handshake $handshake * @param ClientConnectContext|null $connectContext * @param ClientTlsContext|null $tlsContext * @param CancellationToken|null $cancellationToken * * @return Promise<Connection> * * @throws \TypeError If $handshake is not a string or instance of \Amp\WebSocket\Handshake. * @throws ConnectionException If the connection could not be established. */ function connect( $handshake, ?ClientConnectContext $connectContext = null, ?ClientTlsContext $tlsContext = null, ?CancellationToken $cancellationToken = null ): Promise { if (\is_string($handshake)) { $handshake = new Handshake($handshake); } elseif (!$handshake instanceof Handshake) { throw new \TypeError(\sprintf('Must provide an instance of %s or a URL as a string', Handshake::class)); } return connector()->connect($handshake, $connectContext, $tlsContext, $cancellationToken); } <?php namespace Amp\Websocket\Client; use Amp\CancellationToken; use Amp\Promise; use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientTlsContext; interface Connector { /** * @param Handshake $handshake * @param ClientConnectContext|null $connectContext * @param ClientTlsContext|null $tlsContext * @param CancellationToken|null $cancellationToken * * @return Promise<Connection> * * @throws ConnectionException If connecting to the Websocket fails. */ public function connect( Handshake $handshake, ?ClientConnectContext $connectContext = null, ?ClientTlsContext $tlsContext = null, ?CancellationToken $cancellationToken = null ): Promise; } <?php namespace Amp\Websocket\Client; use Amp\Websocket\Client; interface Connection extends Client { /** * Returns the headers as a string-indexed array of arrays of strings or an empty array if no headers * have been set. * * @return string[][] */ public function getHeaders(): array; /** * Returns the array of values for the given header or an empty array if the header does not exist. * * @param string $name * * @return string[] */ public function getHeaderArray(string $name): array; /** * Returns the value of the given header. If multiple headers are present for the named header, only the first * header value will be returned. Use getHeaderArray() to return an array of all values for the particular header. * Returns null if the header does not exist. * * @param string $name * * @return string|null */ public function getHeader(string $name): ?string; /** * Checks if given header exists. * * @param string $name * * @return bool */ public function hasHeader(string $name): bool; } <?php namespace Amp\Websocket\Client; use Amp\ByteStream\InputStream; use Amp\Http\Message; use Amp\Promise; use Amp\Websocket\ClientMetadata; use Amp\Websocket\Code; use Amp\Websocket\Options; use Amp\Websocket\Rfc6455Client; final class Rfc6455Connection implements Connection { /** @var Rfc6455Client */ private $client; /** @var Message */ private $headers; public function __construct(Rfc6455Client $client, array $headers) { $this->client = $client; $this->headers = new class($headers) extends Message { public function __construct(array $headers) { $this->setHeaders($headers); } }; } public function getHeaders(): array { return $this->headers->getHeaders(); } public function getHeaderArray(string $name): array { return $this->headers->getHeaderArray($name); } public function getHeader(string $name): ?string { return $this->headers->getHeader($name); } public function hasHeader(string $name): bool { return $this->headers->hasHeader($name); } public function receive(): Promise { return $this->client->receive(); } public function getId(): string { return $this->client->getId(); } public function getOptions(): Options { return $this->client->getOptions(); } public function isConnected(): bool { return $this->client->isConnected(); } public function getLocalAddress(): string { return $this->client->getLocalAddress(); } public function getLocalPort(): ?int { return $this->client->getLocalPort(); } public function getRemoteAddress(): string { return $this->client->getRemoteAddress(); } public function getRemotePort(): ?int { return $this->client->getRemotePort(); } public function isEncrypted(): bool { return $this->client->isEncrypted(); } public function getCryptoContext(): array { return $this->client->getCryptoContext(); } public function didPeerInitiateClose(): bool { return $this->client->didPeerInitiateClose(); } public function getUnansweredPingCount(): int { return $this->client->getUnansweredPingCount(); } public function getCloseCode(): int { return $this->client->getCloseCode(); } public function getCloseReason(): string { return $this->client->getCloseReason(); } public function send(string $data): Promise { return $this->client->send($data); } public function sendBinary(string $data): Promise { return $this->client->sendBinary($data); } public function stream(InputStream $stream): Promise { return $this->client->stream($stream); } public function streamBinary(InputStream $stream): Promise { return $this->client->streamBinary($stream); } public function ping(): Promise { return $this->client->ping(); } public function getInfo(): ClientMetadata { return $this->client->getInfo(); } public function close(int $code = Code::NORMAL_CLOSE, string $reason = ''): Promise { return $this->client->close($code, $reason); } public function onClose(callable $onClose): void { $this->client->onClose($onClose); } } <?php namespace Amp\Websocket\Client; use Amp\CancellationToken; use Amp\CancelledException; use Amp\Deferred; use Amp\Http\Rfc7230; use Amp\Http\Status; use Amp\NullCancellationToken; use Amp\Promise; use Amp\Socket; use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientSocket; use Amp\Socket\ClientTlsContext; use Amp\Websocket; use Amp\Websocket\CompressionContextFactory; use Amp\Websocket\Rfc6455Client; use Amp\Websocket\Rfc7692CompressionFactory; use function Amp\asyncCall; use function Amp\call; class Rfc6455Connector implements Connector { /** @var CompressionContextFactory */ private $compressionFactory; /** * @param CompressionContextFactory|null $compressionFactory Automatically uses Rfc7692CompressionFactory if null. */ public function __construct(?CompressionContextFactory $compressionFactory = null) { $this->compressionFactory = $compressionFactory ?? new Rfc7692CompressionFactory; } public function connect( Handshake $handshake, ?ClientConnectContext $connectContext = null, ?ClientTlsContext $tlsContext = null, ?CancellationToken $cancellationToken = null ): Promise { $cancellationToken = $cancellationToken ?? new NullCancellationToken; return call(function () use ($handshake, $connectContext, $tlsContext, $cancellationToken) { try { $uri = $handshake->getUri(); $isEncrypted = $uri->getScheme() === 'wss'; $defaultPort = $isEncrypted ? 443 : 80; $authority = $uri->getHost() . ':' . ($uri->getPort() ?? $defaultPort); if ($isEncrypted) { $socket = yield Socket\cryptoConnect($authority, $connectContext, $tlsContext, $cancellationToken); } else { $socket = yield Socket\connect($authority, $connectContext, $cancellationToken); } } catch (CancelledException $exception) { throw $exception; } catch (\Throwable $exception) { throw new ConnectionException('Connecting to the websocket failed', 0, $exception); } \assert($socket instanceof ClientSocket); $deferred = new Deferred; $id = $cancellationToken->subscribe([$deferred, 'fail']); asyncCall(function () use ($socket, $handshake, $deferred) { try { $key = Websocket\generateKey(); yield $socket->write($this->generateRequest($handshake, $key)); $buffer = ''; while (($chunk = yield $socket->read()) !== null) { $buffer .= $chunk; if ($position = \strpos($buffer, "\r\n\r\n")) { $headerBuffer = \substr($buffer, 0, $position + 4); $buffer = \substr($buffer, $position + 4); $headers = $this->handleResponse($headerBuffer, $key); $socket = new Internal\ClientSocket($socket->getResource(), $buffer); $deferred->resolve($this->createConnection($socket, $handshake->getOptions(), $headers)); return; } } } catch (ConnectionException $exception) { $deferred->fail($exception); } catch (\Throwable $exception) { $deferred->fail(new ConnectionException('Performing the websocket handshake failed', 0, $exception)); } }); try { $connection = yield $deferred->promise(); } catch (\Throwable $exception) { $socket->close(); // Close socket in case operation did not fail but was cancelled. throw $exception; } finally { $cancellationToken->unsubscribe($id); } return $connection; }); } private function generateRequest(Handshake $handshake, string $key): string { $uri = $handshake->getUri(); $headers = $handshake->getHeaders(); $headers['host'] = [$uri->getAuthority()]; $headers['connection'] = ['Upgrade']; $headers['upgrade'] = ['websocket']; $headers['sec-websocket-version'] = ['13']; $headers['sec-websocket-key'] = [$key]; if ($handshake->getOptions()->isCompressionEnabled()) { $headers['sec-websocket-extensions'] = [$this->compressionFactory->createRequestHeader()]; } if (($path = $uri->getPath()) === '') { $path = '/'; } if (($query = $uri->getQuery()) !== '') { $path .= '?' . $query; } return \sprintf("GET %s HTTP/1.1\r\n%s\r\n", $path, Rfc7230::formatHeaders($headers)); } private function handleResponse(string $headerBuffer, string $key): array { if (\substr($headerBuffer, -4) !== "\r\n\r\n") { throw new ConnectionException('Invalid header provided'); } $position = \strpos($headerBuffer, "\r\n"); $startLine = \substr($headerBuffer, 0, $position); if (!\preg_match("/^HTTP\/(1\.[01]) (\d{3}) ([^\x01-\x08\x10-\x19]*)$/i", $startLine, $matches)) { throw new ConnectionException('Invalid response start line: ' . $startLine); } $version = $matches[1]; $status = (int) $matches[2]; $reason = $matches[3]; if ($version !== '1.1' || $status !== Status::SWITCHING_PROTOCOLS) { throw new ConnectionException( \sprintf('Did not receive switching protocols response: %d %s', $status, $reason), $status ); } $headerBuffer = \substr($headerBuffer, $position + 2, -2); $headers = Rfc7230::parseHeaders($headerBuffer); $upgrade = $headers['upgrade'][0] ?? ''; if (\strtolower($upgrade) !== 'websocket') { throw new ConnectionException('Missing "Upgrade: websocket" header'); } $connection = $headers['connection'][0] ?? ''; if (!\in_array('upgrade', \array_map('trim', \array_map('strtolower', \explode(',', $connection))), true)) { throw new ConnectionException('Missing "Connection: upgrade" header'); } $secWebsocketAccept = $headers['sec-websocket-accept'][0] ?? ''; if (!Websocket\validateAcceptForKey($secWebsocketAccept, $key)) { throw new ConnectionException('Invalid "Sec-WebSocket-Accept" header'); } return $headers; } final protected function createCompressionContext(array $headers): ?Websocket\CompressionContext { $extensions = $headers['sec-websocket-extensions'][0] ?? ''; $extensions = \array_map('trim', \explode(',', $extensions)); foreach ($extensions as $extension) { if ($compressionContext = $this->compressionFactory->fromServerHeader($extension)) { return $compressionContext; } } return null; } protected function createConnection(ClientSocket $socket, Websocket\Options $options, array $headers): Connection { if ($options->isCompressionEnabled()) { $compressionContext = $this->createCompressionContext($headers); } $client = new Rfc6455Client($socket, $options, true, $compressionContext ?? null); return new Rfc6455Connection($client, $headers); } } { "name": "amphp/file", "homepage": "https://github.com/amphp/file", "description": "Allows non-blocking access to the filesystem for Amp.", "support": { "issues": "https://github.com/amphp/file/issues" }, "keywords": [ "file", "disk", "static", "async", "non-blocking", "amp", "amphp", "io", "filesystem" ], "license": "MIT", "authors": [ { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1", "amphp/parallel": "^1" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "amphp/php-cs-fixer-config": "dev-master" }, "autoload": { "psr-4": { "Amp\\File\\": "lib" }, "files": ["lib/functions.php"] }, "autoload-dev": { "psr-4": { "Amp\\File\\Test\\": "test" } }, "config": { "platform": { "php": "7.0.0" } } } <?php namespace Amp\File\Test; use Amp\File; abstract class AsyncHandleTest extends HandleTest { /** * @expectedException \Amp\File\PendingOperationError */ public function testSimultaneousReads() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $promise1 = $handle->read(); $promise2 = $handle->read(); $expected = \substr(yield File\get(__FILE__), 0, 20); $this->assertSame($expected, yield $promise1); yield $promise2; }); } /** * @expectedException \Amp\File\PendingOperationError */ public function testSeekWhileReading() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $promise1 = $handle->read(10); $promise2 = $handle->seek(0); $expected = \substr(yield File\get(__FILE__), 0, 10); $this->assertSame($expected, yield $promise1); yield $promise2; }); } /** * @expectedException \Amp\File\PendingOperationError */ public function testReadWhileWriting() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $data = "test"; $promise1 = $handle->write($data); $promise2 = $handle->read(10); $this->assertSame(\strlen($data), yield $promise1); yield $promise2; }); } /** * @expectedException \Amp\File\PendingOperationError */ public function testWriteWhileReading() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $promise1 = $handle->read(10); $promise2 = $handle->write("test"); $expected = \substr(yield File\get(__FILE__), 0, 10); $this->assertSame($expected, yield $promise1); yield $promise2; }); } } <?php namespace Amp\File\Test; final class Fixture { private static $fixtureId; public static function path() { if (empty(self::$fixtureId)) { self::$fixtureId = \uniqid(); } return \sys_get_temp_dir() . "/amphp_file_fixture/" . \strtr(__CLASS__, "\\", ".") . self::$fixtureId; } public static function init() { $fixtureDir = self::path(); self::clear(); if (!\mkdir($fixtureDir, $mode = 0777, $recursive = true)) { throw new \RuntimeException( "Failed creating temporary test fixture directory: {$fixtureDir}" ); } if (!\mkdir($fixtureDir . "/dir", $mode = 0777, $recursive = true)) { throw new \RuntimeException( "Failed creating temporary test fixture directory" ); } if (!\file_put_contents($fixtureDir . "/small.txt", "small")) { throw new \RuntimeException( "Failed creating temporary test fixture file" ); } } public static function clear() { $fixtureDir = self::path(); if (!\file_exists($fixtureDir)) { return; } if (\stripos(\PHP_OS, "win") === 0) { \system('rd /Q /S "' . $fixtureDir . '"'); } else { \system('/bin/rm -rf ' . \escapeshellarg($fixtureDir)); } } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use Amp\Parallel\Worker\DefaultPool; use function Amp\call; class ParallelDriverTest extends DriverTest { protected function execute(callable $cb) { Loop::run(function () use ($cb) { $pool = new DefaultPool; File\filesystem(new File\ParallelDriver($pool)); yield call($cb); yield $pool->shutdown(); }); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use function Amp\asyncCall; class UvDriverTest extends DriverTest { protected function execute(callable $cb) { if (!\extension_loaded("uv")) { $this->markTestSkipped( "php-uv extension not loaded" ); } $loop = new Loop\UvDriver; Loop::set($loop); Loop::run(function () use ($cb, $loop) { File\filesystem(new File\UvDriver($loop)); asyncCall($cb); }); } /** * @dataProvider readlinkPathProvider * * @param \Closure $linkResolver */ public function testReadlinkError(\Closure $linkResolver) { $this->markTestSkipped('UvDriver Test Skipped: Causes Crash'); } } <?php namespace Amp\File\Test; use Amp\File as file; use Amp\PHPUnit\TestCase; abstract class DriverTest extends TestCase { protected function setUp() { Fixture::init(); File\StatCache::clear(); } protected function tearDown() { Fixture::clear(); } abstract protected function execute(callable $cb); public function testScandir() { $this->execute(function () { $fixtureDir = Fixture::path(); $actual = yield File\scandir($fixtureDir); $expected = ["dir", "small.txt"]; $this->assertSame($expected, $actual); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testScandirThrowsIfPathNotADirectory() { $this->execute(function () { (yield File\scandir(__FILE__)); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testScandirThrowsIfPathDoesntExist() { $this->execute(function () { $path = Fixture::path() . "/nonexistent"; (yield File\scandir($path)); }); } public function testSymlink() { $this->execute(function () { $fixtureDir = Fixture::path(); $original = "{$fixtureDir}/small.txt"; $link = "{$fixtureDir}/symlink.txt"; $this->assertTrue(yield File\symlink($original, $link)); $this->assertTrue(\is_link($link)); yield File\unlink($link); }); } public function testReadlink() { $this->execute(function () { $fixtureDir = Fixture::path(); $original = "{$fixtureDir}/small.txt"; $link = "{$fixtureDir}/symlink.txt"; \symlink($original, $link); $this->assertSame($original, yield File\readlink($link)); }); } public function readlinkPathProvider() { return [ 'nonExistingPath' => [function () { return Fixture::path() . '/' . \uniqid(); }], 'notLink' => [function () { return Fixture::path(); }], ]; } /** * @dataProvider readlinkPathProvider * @expectedException \Amp\File\FilesystemException * * @param \Closure $linkResolver */ public function testReadlinkError(\Closure $linkResolver) { $this->execute(function () use ($linkResolver) { $link = $linkResolver(); yield File\readlink($link); }); } public function testLstat() { $this->execute(function () { $fixtureDir = Fixture::path(); $target = "{$fixtureDir}/small.txt"; $link = "{$fixtureDir}/symlink.txt"; $this->assertTrue(yield File\symlink($target, $link)); $this->assertInternalType('array', yield File\lstat($link)); yield File\unlink($link); }); } public function testFileStat() { $this->execute(function () { $fixtureDir = Fixture::path(); $stat = (yield File\stat("{$fixtureDir}/small.txt")); $this->assertInternalType("array", $stat); $this->assertStatSame(\stat("{$fixtureDir}/small.txt"), $stat); }); } public function testDirStat() { $this->execute(function () { $fixtureDir = Fixture::path(); $stat = (yield File\stat("{$fixtureDir}/dir")); $this->assertInternalType("array", $stat); $this->assertStatSame(\stat("{$fixtureDir}/dir"), $stat); }); } public function testNonexistentPathStatResolvesToNull() { $this->execute(function () { $fixtureDir = Fixture::path(); $stat = (yield File\stat("{$fixtureDir}/nonexistent")); $this->assertNull($stat); }); } public function testExists() { $this->execute(function () { $fixtureDir = Fixture::path(); $this->assertFalse(yield File\exists("{$fixtureDir}/nonexistent")); $this->assertTrue(yield File\exists("{$fixtureDir}/small.txt")); }); } public function testGet() { $this->execute(function () { $fixtureDir = Fixture::path(); $this->assertSame("small", yield File\get("{$fixtureDir}/small.txt")); }); } public function testSize() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/small.txt"; $stat = (yield File\stat($path)); $size = $stat["size"]; File\StatCache::clear($path); $this->assertSame($size, (yield File\size($path))); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testSizeFailsOnNonexistentPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/nonexistent"; yield File\size($path); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testSizeFailsOnDirectoryPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/dir"; $this->assertTrue(yield File\isdir($path)); File\StatCache::clear($path); yield File\size($path); }); } public function testIsdirResolvesTrueOnDirectoryPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/dir"; $this->assertTrue(yield File\isdir($path)); }); } public function testIsdirResolvesFalseOnFilePath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/small.txt"; $this->assertFalse(yield File\isdir($path)); }); } public function testIsdirResolvesFalseOnNonexistentPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/nonexistent"; $this->assertFalse(yield File\isdir($path)); }); } public function testIsfileResolvesTrueOnFilePath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/small.txt"; $this->assertTrue(yield File\isfile($path)); }); } public function testIsfileResolvesFalseOnDirectoryPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/dir"; $this->assertFalse(yield File\isfile($path)); }); } public function testIsfileResolvesFalseOnNonexistentPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/nonexistent"; $this->assertFalse(yield File\isfile($path)); }); } public function testRename() { $this->execute(function () { $fixtureDir = Fixture::path(); $contents1 = "rename test"; $old = "{$fixtureDir}/rename1.txt"; $new = "{$fixtureDir}/rename2.txt"; yield File\put($old, $contents1); yield File\rename($old, $new); $contents2 = (yield File\get($new)); yield File\unlink($new); $this->assertSame($contents1, $contents2); }); } public function testUnlink() { $this->execute(function () { $fixtureDir = Fixture::path(); $toUnlink = "{$fixtureDir}/unlink"; yield File\put($toUnlink, "unlink me"); yield File\unlink($toUnlink); $this->assertNull(yield File\stat($toUnlink)); }); } public function testMkdirRmdir() { $this->execute(function () { $fixtureDir = Fixture::path(); $dir = "{$fixtureDir}/newdir"; \umask(0022); yield File\mkdir($dir); $stat = yield File\stat($dir); $this->assertSame('0755', $this->getPermissionsFromStat($stat)); yield File\rmdir($dir); $this->assertNull(yield File\stat($dir)); // test for 0, because previous array_filter made that not work $dir = "{$fixtureDir}/newdir/with/recursive/creation/0/1/2"; yield File\mkdir($dir, 0764, true); $stat = yield File\stat($dir); $this->assertSame('0744', $this->getPermissionsFromStat($stat)); }); } public function testMtime() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/small.txt"; $stat = (yield File\stat($path)); $statMtime = $stat["mtime"]; File\StatCache::clear($path); $this->assertSame($statMtime, (yield File\mtime($path))); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testMtimeFailsOnNonexistentPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/nonexistent"; yield File\mtime($path); }); } public function testAtime() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/small.txt"; $stat = (yield File\stat($path)); $statAtime = $stat["atime"]; File\StatCache::clear($path); $this->assertSame($statAtime, (yield File\atime($path))); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testAtimeFailsOnNonexistentPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/nonexistent"; yield File\atime($path); }); } public function testCtime() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/small.txt"; $stat = (yield File\stat($path)); $statCtime = $stat["ctime"]; File\StatCache::clear($path); $this->assertSame($statCtime, (yield File\ctime($path))); }); } /** * @expectedException \Amp\File\FilesystemException */ public function testCtimeFailsOnNonexistentPath() { $this->execute(function () { $fixtureDir = Fixture::path(); $path = "{$fixtureDir}/nonexistent"; yield File\ctime($path); }); } /** * @group slow */ public function testTouch() { $this->execute(function () { $fixtureDir = Fixture::path(); $touch = "{$fixtureDir}/touch"; yield File\put($touch, "touch me"); $oldStat = (yield File\stat($touch)); yield File\touch($touch, \time() + 10, \time() + 20); File\StatCache::clear($touch); $newStat = (yield File\stat($touch)); yield File\unlink($touch); $this->assertTrue($newStat["atime"] > $oldStat["atime"]); $this->assertTrue($newStat["mtime"] > $oldStat["mtime"]); }); } private function assertStatSame(array $expected, array $actual) { $filter = function (array $stat) { $filtered = \array_filter( $stat, function (string $key): bool { return !\is_numeric($key); }, ARRAY_FILTER_USE_KEY ); \ksort($filtered); return $filtered; }; $this->assertSame($filter($expected), $filter($actual)); } /** * @param array $stat * @return string */ private function getPermissionsFromStat(array $stat): string { return \substr(\decoct($stat["mode"]), 1); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use function Amp\asyncCall; class BlockingDriverTest extends DriverTest { protected function execute(callable $cb) { Loop::run(function () use ($cb) { File\filesystem(new File\BlockingDriver); asyncCall($cb); }); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use function Amp\asyncCall; class EioHandleTest extends AsyncHandleTest { protected function execute(callable $cb) { if (!\extension_loaded("eio")) { $this->markTestSkipped( "eio extension not loaded" ); } Loop::run(function () use ($cb) { File\filesystem(new File\EioDriver); asyncCall($cb); }); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use function Amp\asyncCall; class UvHandleTest extends AsyncHandleTest { protected function execute(callable $cb) { if (!\extension_loaded("uv")) { $this->markTestSkipped( "php-uv extension not loaded" ); } $loop = new Loop\UvDriver; Loop::set($loop); Loop::run(function () use ($cb, $loop) { File\filesystem(new File\UvDriver($loop)); asyncCall($cb); }); } } <?php namespace Amp\File\Test; use Amp\ByteStream\ClosedException; use Amp\File; use Amp\PHPUnit\TestCase; abstract class HandleTest extends TestCase { protected function setUp() { Fixture::init(); File\StatCache::clear(); } protected function tearDown() { Fixture::clear(); } abstract protected function execute(callable $cb); public function testWrite() { $this->execute(function () { $path = Fixture::path() . "/write"; /** @var \Amp\File\Handle $handle */ $handle = yield File\open($path, "c+"); $this->assertSame(0, $handle->tell()); $handle->write("foo"); yield $handle->write("bar"); yield $handle->seek(0); $contents = yield $handle->read(); $this->assertSame(6, $handle->tell()); $this->assertTrue($handle->eof()); $this->assertSame("foobar", $contents); yield $handle->close(); }); } public function testWriteAfterClose() { $this->execute(function () { $path = Fixture::path() . "/write"; /** @var \Amp\File\Handle $handle */ $handle = yield File\open($path, "c+"); yield $handle->close(); $this->expectException(ClosedException::class); yield $handle->write("bar"); }); } public function testDoubleClose() { $this->execute(function () { $path = Fixture::path() . "/write"; /** @var \Amp\File\Handle $handle */ $handle = yield File\open($path, "c+"); yield $handle->close(); $this->assertNull(yield $handle->close()); }); } public function testWriteAfterEnd() { $this->execute(function () { $path = Fixture::path() . "/write"; /** @var \Amp\File\Handle $handle */ $handle = yield File\open($path, "c+"); $this->assertSame(0, $handle->tell()); yield $handle->end("foo"); $this->expectException(ClosedException::class); yield $handle->write("bar"); }); } public function testWriteInAppendMode() { $this->execute(function () { $path = Fixture::path() . "/write"; /** @var \Amp\File\Handle $handle */ $handle = yield File\open($path, "a+"); $this->assertSame(0, $handle->tell()); yield $handle->write("bar"); yield $handle->write("foo"); yield $handle->write("baz"); $this->assertSame(9, $handle->tell()); yield $handle->seek(0); $this->assertSame(0, $handle->tell()); $this->assertSame("barfoobaz", yield $handle->read()); }); } public function testReadingToEof() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $contents = ""; $position = 0; $stat = yield File\stat(__FILE__); $chunkSize = (int) \floor(($stat["size"] / 5)); while (!$handle->eof()) { $chunk = yield $handle->read($chunkSize); $contents .= $chunk; $position += \strlen($chunk); $this->assertSame($position, $handle->tell()); } $this->assertNull(yield $handle->read()); $this->assertSame(yield File\get(__FILE__), $contents); yield $handle->close(); }); } public function testSequentialReads() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $contents = ""; $contents .= yield $handle->read(10); $contents .= yield $handle->read(10); $expected = \substr(yield File\get(__FILE__), 0, 20); $this->assertSame($expected, $contents); yield $handle->close(); }); } public function testReadingFromOffset() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $this->assertSame(0, $handle->tell()); yield $handle->seek(10); $this->assertSame(10, $handle->tell()); $chunk = yield $handle->read(90); $this->assertSame(100, $handle->tell()); $expected = \substr(yield File\get(__FILE__), 10, 90); $this->assertSame($expected, $chunk); yield $handle->close(); }); } /** * @expectedException \Error */ public function testSeekThrowsOnInvalidWhence() { $this->execute(function () { try { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); yield $handle->seek(0, 99999); } finally { yield $handle->close(); } }); } public function testSeekSetCur() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $this->assertSame(0, $handle->tell()); yield $handle->seek(10); $this->assertSame(10, $handle->tell()); yield $handle->seek(-10, \SEEK_CUR); $this->assertSame(0, $handle->tell()); yield $handle->close(); }); } public function testSeekSetEnd() { $this->execute(function () { $size = yield File\size(__FILE__); /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $this->assertSame(0, $handle->tell()); yield $handle->seek(-10, \SEEK_END); $this->assertSame($size - 10, $handle->tell()); yield $handle->close(); }); } public function testPath() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $this->assertSame(__FILE__, $handle->path()); yield $handle->close(); }); } public function testMode() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); $this->assertSame("r", $handle->mode()); yield $handle->close(); }); } public function testClose() { $this->execute(function () { /** @var \Amp\File\Handle $handle */ $handle = yield File\open(__FILE__, "r"); yield $handle->close(); $this->expectException(ClosedException::class); yield $handle->read(); }); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use function Amp\asyncCall; class BlockingHandleTest extends HandleTest { protected function execute(callable $cb) { Loop::run(function () use ($cb) { File\filesystem(new File\BlockingDriver); asyncCall($cb); }); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use function Amp\asyncCall; class EioDriverTest extends DriverTest { protected function execute(callable $cb) { if (!\extension_loaded("eio")) { $this->markTestSkipped( "eio extension not loaded" ); } Loop::run(function () use ($cb) { File\filesystem(new File\EioDriver); asyncCall($cb); }); } } <?php namespace Amp\File\Test; use Amp\File; use Amp\Loop; use Amp\Parallel\Worker\DefaultPool; use function Amp\call; class ParallelHandleTest extends AsyncHandleTest { protected function execute(callable $cb) { Loop::run(function () use ($cb) { $pool = new DefaultPool; File\filesystem(new File\ParallelDriver($pool)); yield call($cb); yield $pool->shutdown(); }); } } <?php namespace Amp\File; use Amp\Loop; class StatCache { private static $cache = []; private static $timeouts = []; private static $ttl = 3; private static $now = null; private static function init() { self::$now = \time(); $watcher = Loop::repeat(1000, function () { self::$now = $now = \time(); foreach (self::$cache as $path => $expiry) { if ($now > $expiry) { unset( self::$cache[$path], self::$timeouts[$path] ); } else { break; } } }); Loop::unreference($watcher); Loop::setState(self::class, new class($watcher) { private $watcher; private $driver; public function __construct(string $watcher) { $this->watcher = $watcher; $this->driver = Loop::get(); } public function __destruct() { $this->driver->cancel($this->watcher); } }); } public static function get(string $path) { return isset(self::$cache[$path]) ? self::$cache[$path] : null; } public static function set(string $path, array $stat) { if (self::$ttl <= 0) { return; } if (Loop::getState(self::class) === null) { self::init(); } self::$cache[$path] = $stat; self::$timeouts[$path] = self::$now + self::$ttl; } public static function ttl(int $seconds) { self::$ttl = $seconds; } public static function clear(string $path = null) { if (isset($path)) { unset( self::$cache[$path], self::$timeouts[$path] ); } else { self::$cache = []; self::$timeouts = []; } } } <?php namespace Amp\File\Internal; use Amp\CallableMaker; use Amp\Loop; use Amp\Promise; class UvPoll { use CallableMaker; /** @var string */ private $watcher; /** @var int */ private $requests = 0; /** @var callable */ private $onDone; public function __construct() { $this->onDone = $this->callableFromInstanceMethod("done"); $this->watcher = Loop::repeat(\PHP_INT_MAX / 2, function () { // do nothing, it's a dummy watcher }); Loop::disable($this->watcher); Loop::setState(self::class, new class($this->watcher) { private $watcher; public function __construct(string $watcher) { $this->watcher = $watcher; } public function __destruct() { Loop::cancel($this->watcher); } }); } public function listen(Promise $promise) { if ($this->requests++ === 0) { Loop::enable($this->watcher); } $promise->onResolve($this->onDone); } private function done() { if (--$this->requests === 0) { Loop::disable($this->watcher); } \assert($this->requests >= 0); } } <?php namespace Amp\File\Internal; use Amp\CallableMaker; use Amp\Loop; use Amp\Promise; class EioPoll { use CallableMaker; /** @var resource */ private static $stream; /** @var string */ private $watcher; /** @var int */ private $requests = 0; /** @var callable */ private $onDone; public function __construct() { $this->onDone = $this->callableFromInstanceMethod("done"); if (!self::$stream) { \eio_init(); self::$stream = \eio_get_event_stream(); } $this->watcher = Loop::onReadable(self::$stream, static function () { while (\eio_npending()) { \eio_poll(); } }); Loop::disable($this->watcher); Loop::setState(self::class, new class($this->watcher) { private $watcher; public function __construct(string $watcher) { $this->watcher = $watcher; } public function __destruct() { Loop::cancel($this->watcher); // Ensure there are no active operations anymore. This is a safe-guard as some operations might not be // finished on loop exit due to not being yielded. This also ensures a clean shutdown for these if PHP // exists. \eio_event_loop(); } }); } public function listen(Promise $promise) { if ($this->requests++ === 0) { Loop::enable($this->watcher); } $promise->onResolve($this->onDone); } private function done() { if (--$this->requests === 0) { Loop::disable($this->watcher); } \assert($this->requests >= 0); } } <?php namespace Amp\File\Internal; use Amp\File\BlockingDriver; use Amp\File\BlockingHandle; use Amp\File\FilesystemException; use Amp\File\StatCache; use Amp\Parallel\Worker\Environment; use Amp\Parallel\Worker\Task; /** * @codeCoverageIgnore * * @internal */ class FileTask implements Task { const ENV_PREFIX = "amp/file#"; /** @var string */ private $operation; /** @var mixed[] */ private $args; /** @var string|null */ private $id; /** * @param string $operation * @param array $args * @param int $id File ID. * * @throws \Error */ public function __construct(string $operation, array $args = [], int $id = null) { if (!\strlen($operation)) { throw new \Error('Operation must be a non-empty string'); } $this->operation = $operation; $this->args = $args; $this->id = $id; } /** * {@inheritdoc} * * @throws \Amp\File\FilesystemException * @throws \Error */ public function run(Environment $environment) { if ('f' === $this->operation[0]) { if ("fopen" === $this->operation) { $path = $this->args[0]; $mode = \str_replace(['b', 't', 'e'], '', $this->args[1]); switch ($mode) { case "r": case "r+": case "w": case "w+": case "a": case "a+": case "x": case "x+": case "c": case "c+": break; default: throw new \Error("Invalid file mode"); } $handle = @\fopen($path, $mode . 'be'); if (!$handle) { $message = 'Could not open the file.'; if ($error = \error_get_last()) { $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); } throw new FilesystemException($message); } $file = new BlockingHandle($handle, $path, $mode); $id = (int) $handle; $size = \fstat($handle)["size"]; $environment->set(self::makeId($id), $file); return [$id, $size, $mode]; } if ($this->id === null) { throw new FilesystemException("No file ID provided"); } $id = self::makeId($this->id); if (!$environment->exists($id)) { throw new FilesystemException(\sprintf("No file handle with the ID %d has been opened on the worker", $this->id)); } /** @var \Amp\File\BlockingHandle $file */ if (!($file = $environment->get($id)) instanceof BlockingHandle) { throw new FilesystemException("File storage found in inconsistent state"); } switch ($this->operation) { case "fread": case "fwrite": case "fseek": return ([$file, \substr($this->operation, 1)])(...$this->args); case "fclose": $environment->delete($id); $file->close(); return; default: throw new \Error('Invalid operation'); } } StatCache::clear(); switch ($this->operation) { case "stat": case "unlink": case "rename": case "link": case "symlink": case "readlink": case "lstat": case "exists": case "mkdir": case "scandir": case "rmdir": case "chmod": case "chown": case "touch": case "get": case "put": return ([new BlockingDriver, $this->operation])(...$this->args); default: throw new \Error("Invalid operation"); } } /** * @param int $id * * @return string */ private static function makeId(int $id): string { return self::ENV_PREFIX . $id; } } <?php namespace Amp\File; use Amp\ByteStream\ClosedException; use Amp\ByteStream\StreamException; use Amp\Deferred; use Amp\Promise; use Amp\Success; use function Amp\call; class EioHandle implements Handle { /** @var \Amp\File\Internal\EioPoll */ private $poll; /** @var resource eio file handle. */ private $fh; /** @var string */ private $path; /** @var string */ private $mode; /** @var int */ private $size; /** @var int */ private $position; /** @var \SplQueue */ private $queue; /** @var bool */ private $isActive = false; /** @var bool */ private $writable = true; /** @var \Amp\Promise|null */ private $closing; public function __construct(Internal\EioPoll $poll, $fh, string $path, string $mode, int $size) { $this->poll = $poll; $this->fh = $fh; $this->path = $path; $this->mode = $mode; $this->size = $size; $this->position = ($mode[0] === "a") ? $size : 0; $this->queue = new \SplQueue; } /** * {@inheritdoc} */ public function read(int $length = self::DEFAULT_READ_LENGTH): Promise { if ($this->isActive) { throw new PendingOperationError; } $this->isActive = true; $remaining = $this->size - $this->position; $length = $length > $remaining ? $remaining : $length; $deferred = new Deferred; $this->poll->listen($deferred->promise()); \eio_read( $this->fh, $length, $this->position, \EIO_PRI_DEFAULT, [$this, "onRead"], $deferred ); return $deferred->promise(); } private function onRead(Deferred $deferred, $result, $req) { $this->isActive = false; if ($result === -1) { $error = \eio_get_last_error($req); if ($error === "Bad file descriptor") { $deferred->fail(new ClosedException("Reading from the file failed due to a closed handle")); } else { $deferred->fail(new StreamException("Reading from the file failed:" . $error)); } } else { $this->position += \strlen($result); $deferred->resolve(\strlen($result) ? $result : null); } } /** * {@inheritdoc} */ public function write(string $data): Promise { if ($this->isActive && $this->queue->isEmpty()) { throw new PendingOperationError; } if (!$this->writable) { throw new ClosedException("The file is no longer writable"); } $this->isActive = true; if ($this->queue->isEmpty()) { $promise = $this->push($data); } else { $promise = $this->queue->top(); $promise = call(function () use ($promise, $data) { yield $promise; return yield $this->push($data); }); } $this->queue->push($promise); return $promise; } private function push(string $data): Promise { $length = \strlen($data); $deferred = new Deferred; $this->poll->listen($deferred->promise()); \eio_write( $this->fh, $data, $length, $this->position, \EIO_PRI_DEFAULT, [$this, "onWrite"], $deferred ); return $deferred->promise(); } /** * {@inheritdoc} */ public function end(string $data = ""): Promise { return call(function () use ($data) { $promise = $this->write($data); $this->writable = false; // ignore any errors yield Promise\any([$this->close()]); return $promise; }); } private function onWrite(Deferred $deferred, $result, $req) { if ($this->queue->isEmpty()) { $deferred->fail(new ClosedException('No pending write, the file may have been closed')); } $this->queue->shift(); if ($this->queue->isEmpty()) { $this->isActive = false; } if ($result === -1) { $error = \eio_get_last_error($req); if ($error === "Bad file descriptor") { $deferred->fail(new ClosedException("Writing to the file failed due to a closed handle")); } else { $deferred->fail(new StreamException("Writing to the file failed: " . $error)); } } else { $this->position += $result; if ($this->position > $this->size) { $this->size = $this->position; } $deferred->resolve($result); } } /** * {@inheritdoc} */ public function close(): Promise { if ($this->closing) { return $this->closing; } $deferred = new Deferred; $this->poll->listen($this->closing = $deferred->promise()); \eio_close($this->fh, \EIO_PRI_DEFAULT, [$this, "onClose"], $deferred); return $deferred->promise(); } private function onClose(Deferred $deferred, $result, $req) { // Ignore errors when closing file, as the handle will become invalid anyway. $deferred->resolve(); } /** * {@inheritdoc} */ public function seek(int $offset, int $whence = \SEEK_SET): Promise { if ($this->isActive) { throw new PendingOperationError; } switch ($whence) { case \SEEK_SET: $this->position = $offset; break; case \SEEK_CUR: $this->position = $this->position + $offset; break; case \SEEK_END: $this->position = $this->size + $offset; break; default: throw new \Error( "Invalid whence parameter; SEEK_SET, SEEK_CUR or SEEK_END expected" ); } return new Success($this->position); } /** * {@inheritdoc} */ public function tell(): int { return $this->position; } /** * {@inheritdoc} */ public function eof(): bool { return !$this->queue->isEmpty() ? false : ($this->size <= $this->position); } /** * {@inheritdoc} */ public function path(): string { return $this->path; } /** * {@inheritdoc} */ public function mode(): string { return $this->mode; } } <?php namespace Amp\File; use Amp\Loop; use Amp\Promise; const LOOP_STATE_IDENTIFIER = Driver::class; /** * Retrieve the application-wide filesystem instance. * * @param \Amp\File\Driver $driver Use the specified object as the application-wide filesystem instance * @return \Amp\File\Driver */ function filesystem(Driver $driver = null): Driver { if ($driver === null) { $driver = Loop::getState(LOOP_STATE_IDENTIFIER); if ($driver) { return $driver; } $driver = driver(); } if (\defined("AMP_WORKER") && $driver instanceof ParallelDriver) { throw new \Error("Cannot use the parallel driver within a worker"); } Loop::setState(LOOP_STATE_IDENTIFIER, $driver); return $driver; } /** * Create a new filesystem driver best-suited for the current environment. * * @return \Amp\File\Driver */ function driver(): Driver { $driver = Loop::get(); if (UvDriver::isSupported($driver)) { return new UvDriver($driver); } if (EioDriver::isSupported()) { return new EioDriver; } if (\defined("AMP_WORKER")) { // Prevent spawning infinite workers. return new BlockingDriver; } return new ParallelDriver; } /** * Open a handle for the specified path. * * @param string $path * @param string $mode * @return \Amp\Promise<\Amp\File\Handle> */ function open(string $path, string $mode): Promise { return filesystem()->open($path, $mode); } /** * Execute a file stat operation. * * If the requested path does not exist the resulting Promise will resolve to NULL. * The returned Promise whould never resolve as a failure. * * @param string $path An absolute file system path * @return \Amp\Promise<array|null> */ function stat(string $path): Promise { return filesystem()->stat($path); } /** * Does the specified path exist? * * This function should never resolve as a failure -- only a successfull bool value * indicating the existence of the specified path. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ function exists(string $path): Promise { return filesystem()->exists($path); } /** * Retrieve the size in bytes of the file at the specified path. * * If the path does not exist or is not a regular file this * function's returned Promise WILL resolve as a failure. * * @param string $path An absolute file system path * @fails \Amp\Files\FilesystemException If the path does not exist or is not a file * @return \Amp\Promise<int> */ function size(string $path): Promise { return filesystem()->size($path); } /** * Does the specified path exist and is it a directory? * * If the path does not exist the returned Promise will resolve * to FALSE and will not reject with an error. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ function isdir(string $path): Promise { return filesystem()->isdir($path); } /** * Does the specified path exist and is it a file? * * If the path does not exist the returned Promise will resolve * to FALSE and will not reject with an error. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ function isfile(string $path): Promise { return filesystem()->isfile($path); } /** * Retrieve the path's last modification time as a unix timestamp. * * @param string $path An absolute file system path * @fails \Amp\Files\FilesystemException If the path does not exist * @return \Amp\Promise<int> */ function mtime(string $path): Promise { return filesystem()->mtime($path); } /** * Retrieve the path's last access time as a unix timestamp. * * @param string $path An absolute file system path * @fails \Amp\Files\FilesystemException If the path does not exist * @return \Amp\Promise<int> */ function atime($path) { return filesystem()->atime($path); } /** * Retrieve the path's creation time as a unix timestamp. * * @param string $path An absolute file system path * @fails \Amp\Files\FilesystemException If the path does not exist * @return \Amp\Promise<int> */ function ctime(string $path): Promise { return filesystem()->ctime($path); } /** * Same as stat() except if the path is a link then the link's data is returned. * * If the requested path does not exist the resulting Promise will resolve to NULL. * The returned Promise whould never resolve as a failure. * * @param string $path An absolute file system path * @return \Amp\Promise<array|null> */ function lstat(string $path): Promise { return filesystem()->lstat($path); } /** * Create a symlink $link pointing to the file/directory located at $original. * * @param string $original * @param string $link * @fails \Amp\Files\FilesystemException If the operation fails * @return \Amp\Promise<null> */ function symlink(string $original, string $link): Promise { return filesystem()->symlink($original, $link); } /** * Create a hard link $link pointing to the file/directory located at $original. * * @param string $original * @param string $link * @fails \Amp\Files\FilesystemException If the operation fails * @return \Amp\Promise<null> */ function link(string $original, string $link): Promise { return filesystem()->symlink($original, $link); } /** * Read the symlink at $path. * * @param string $path * @fails \Amp\Files\FilesystemException If the operation fails * @return \Amp\Promise<string> */ function readlink(string $path): Promise { return filesystem()->readlink($path); } /** * Rename a file or directory. * * @param string $from * @param string $to * @fails \Amp\Files\FilesystemException If the operation fails * @return \Amp\Promise<null> */ function rename(string $from, string $to): Promise { return filesystem()->rename($from, $to); } /** * Delete a file. * * @param string $path * @return \Amp\Promise<null> */ function unlink(string $path): Promise { return filesystem()->unlink($path); } /** * Create a director. * * @param string $path * @param int $mode * @param bool $recursive * @return \Amp\Promise<null> */ function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise { return filesystem()->mkdir($path, $mode, $recursive); } /** * Delete a directory. * * @param string $path * @return \Amp\Promise<null> */ function rmdir(string $path): Promise { return filesystem()->rmdir($path); } /** * Retrieve an array of files and directories inside the specified path. * * Dot entries are not included in the resulting array (i.e. "." and ".."). * * @param string $path * @return \Amp\Promise<array> */ function scandir(string $path): Promise { return filesystem()->scandir($path); } /** * chmod a file or directory. * * @param string $path * @param int $mode * @return \Amp\Promise<null> */ function chmod(string $path, int $mode): Promise { return filesystem()->chmod($path, $mode); } /** * chown a file or directory. * * @param string $path * @param int $uid -1 to ignore * @param int $gid -1 to ignore * @return \Amp\Promise<null> */ function chown(string $path, int $uid, int $gid = -1): Promise { return filesystem()->chown($path, $uid, $gid); } /** * Update the access and modification time of the specified path. * * If the file does not exist it will be created automatically. * * @param string $path * @param int $time The touch time. If $time is not supplied, the current system time is used. * @param int $atime The access time. If $atime is not supplied, value passed to the $time parameter is used. * @return \Amp\Promise<null> */ function touch(string $path, int $time = null, int $atime = null): Promise { return filesystem()->touch($path, $time, $atime); } /** * Buffer the specified file's contents. * * @param string $path The file path from which to buffer contents * @return \Amp\Promise<string> */ function get(string $path): Promise { return filesystem()->get($path); } /** * Write the contents string to the specified path. * * @param string $path The file path to which to $contents should be written * @param string $contents The data to write to the specified $path * @return \Amp\Promise A promise resolving to the integer length written upon success */ function put(string $path, string $contents): Promise { return filesystem()->put($path, $contents); } <?php namespace Amp\File; use Amp\ByteStream\ClosedException; use Amp\ByteStream\StreamException; use Amp\Failure; use Amp\Promise; use Amp\Success; use function Amp\call; class BlockingHandle implements Handle { private $fh; private $path; private $mode; /** * @param resource $fh An open uv filesystem descriptor * @param string $path * @param string $mode */ public function __construct($fh, string $path, string $mode) { $this->fh = $fh; $this->path = $path; $this->mode = $mode; } public function __destruct() { if ($this->fh !== null) { \fclose($this->fh); } } /** * {@inheritdoc} */ public function read(int $length = self::DEFAULT_READ_LENGTH): Promise { if ($this->fh === null) { throw new ClosedException("The file has been closed"); } $data = \fread($this->fh, $length); if ($data !== false) { return new Success(\strlen($data) ? $data : null); } return new Failure(new StreamException( "Failed reading from file handle" )); } /** * {@inheritdoc} */ public function write(string $data): Promise { if ($this->fh === null) { throw new ClosedException("The file has been closed"); } $len = \fwrite($this->fh, $data); if ($len !== false) { return new Success($len); } return new Failure(new StreamException( "Failed writing to file handle" )); } /** * {@inheritdoc} */ public function end(string $data = ""): Promise { return call(function () use ($data) { $promise = $this->write($data); // ignore any errors yield Promise\any([$this->close()]); return $promise; }); } /** * {@inheritdoc} */ public function close(): Promise { if ($this->fh === null) { return new Success; } $fh = $this->fh; $this->fh = null; if (@\fclose($fh)) { return new Success; } return new Failure(new StreamException( "Failed closing file handle" )); } /** * {@inheritdoc} */ public function seek(int $position, int $whence = \SEEK_SET): Promise { if ($this->fh === null) { throw new ClosedException("The file has been closed"); } switch ($whence) { case \SEEK_SET: case \SEEK_CUR: case \SEEK_END: if (@\fseek($this->fh, $position, $whence) === -1) { return new Failure(new StreamException("Could not seek in file")); } return new Success($this->tell()); default: throw new \Error( "Invalid whence parameter; SEEK_SET, SEEK_CUR or SEEK_END expected" ); } } /** * {@inheritdoc} */ public function tell(): int { if ($this->fh === null) { throw new ClosedException("The file has been closed"); } return \ftell($this->fh); } /** * {@inheritdoc} */ public function eof(): bool { if ($this->fh === null) { throw new ClosedException("The file has been closed"); } return \feof($this->fh); } /** * {@inheritdoc} */ public function path(): string { return $this->path; } /** * {@inheritdoc} */ public function mode(): string { return $this->mode; } } <?php namespace Amp\File; use Amp\Coroutine; use Amp\Deferred; use Amp\File\Internal\UvPoll; use Amp\Loop; use Amp\Promise; use Amp\Success; class UvDriver implements Driver { /** @var \Amp\Loop\Driver */ private $driver; /** @var \UVLoop|resource Loop resource of type uv_loop or instance of \UVLoop. */ private $loop; /** @var UvPoll */ private $poll; /** * @param \Amp\Loop\Driver The currently active loop driver. * * @return bool Determines if this driver can be used based on the environment. */ public static function isSupported(Loop\Driver $driver): bool { return $driver instanceof Loop\UvDriver; } /** * @param \Amp\Loop\UvDriver $driver */ public function __construct(Loop\UvDriver $driver) { $this->driver = $driver; $this->loop = $driver->getHandle(); $this->poll = new UvPoll; } /** * {@inheritdoc} */ public function open(string $path, string $mode): Promise { $flags = $this->parseMode($mode); $chmod = ($flags & \UV::O_CREAT) ? 0644 : 0; $deferred = new Deferred; $this->poll->listen($deferred->promise()); $openArr = [$mode, $path, $deferred]; \uv_fs_open($this->loop, $path, $flags, $chmod, function ($fh) use ($openArr) { if ($fh) { $this->onOpenHandle($fh, $openArr); } else { list(, $path, $deferred) = $openArr; $deferred->fail(new FilesystemException( "Failed opening file handle to $path" )); } }); return $deferred->promise(); } private function parseMode(string $mode): int { $mode = \str_replace(['b', 't', 'e'], '', $mode); switch ($mode) { case "r": return \UV::O_RDONLY; case "r+": return \UV::O_RDWR; case "w": return \UV::O_WRONLY | \UV::O_CREAT; case "w+": return \UV::O_RDWR | \UV::O_CREAT; case "a": return \UV::O_WRONLY | \UV::O_CREAT | \UV::O_APPEND; case "a+": return \UV::O_RDWR | \UV::O_CREAT | \UV::O_APPEND; case "x": return \UV::O_WRONLY | \UV::O_CREAT | \UV::O_EXCL; case "x+": return \UV::O_RDWR | \UV::O_CREAT | \UV::O_EXCL; case "c": return \UV::O_WRONLY | \UV::O_CREAT; case "c+": return \UV::O_RDWR | \UV::O_CREAT; default: throw new \Error('Invalid file mode'); } } private function onOpenHandle($fh, array $openArr) { list($mode) = $openArr; if ($mode[0] === "w") { \uv_fs_ftruncate($this->loop, $fh, $length = 0, function ($fh) use ($openArr) { if ($fh) { $this->finalizeHandle($fh, $size = 0, $openArr); } else { list(, $path, $deferred) = $openArr; $deferred->fail(new FilesystemException( "Failed truncating file $path" )); } }); } else { \uv_fs_fstat($this->loop, $fh, function ($fh, $stat) use ($openArr) { if ($fh) { StatCache::set($openArr[1], $stat); $this->finalizeHandle($fh, $stat["size"], $openArr); } else { list(, $path, $deferred) = $openArr; $deferred->fail(new FilesystemException( "Failed reading file size from open handle pointing to $path" )); } }); } } private function finalizeHandle($fh, $size, array $openArr) { list($mode, $path, $deferred) = $openArr; $handle = new UvHandle($this->driver, $this->poll, $fh, $path, $mode, $size); $deferred->resolve($handle); } /** * {@inheritdoc} */ public function stat(string $path): Promise { if ($stat = StatCache::get($path)) { return new Success($stat); } $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_stat($this->loop, $path, function ($fh, $stat) use ($deferred, $path) { if (empty($fh)) { $stat = null; } else { // link is not a valid stat type but returned by the uv extension // change link to nlink if (isset($stat['link'])) { $stat['nlink'] = $stat['link']; unset($stat['link']); } StatCache::set($path, $stat); } $deferred->resolve($stat); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function exists(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { $deferred->resolve((bool) $result); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function isdir(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve(!($result["mode"] & \UV::S_IFREG)); } else { $deferred->resolve(false); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function isfile(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve((bool) ($result["mode"] & \UV::S_IFREG)); } else { $deferred->resolve(false); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function size(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if (empty($result)) { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } elseif (($result["mode"] & \UV::S_IFREG)) { $deferred->resolve($result["size"]); } else { $deferred->fail(new FilesystemException( "Specified path is not a regular file" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function mtime(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve($result["mtime"]); } else { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function atime(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve($result["atime"]); } else { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function ctime(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve($result["ctime"]); } else { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function lstat(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_lstat($this->loop, $path, function ($fh, $stat) use ($deferred) { if (empty($fh)) { $stat = null; } $deferred->resolve($stat); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function symlink(string $target, string $link): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_symlink($this->loop, $target, $link, \UV::S_IRWXU | \UV::S_IRUSR, function ($fh) use ($deferred) { $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function link(string $target, string $link): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_link($this->loop, $target, $link, \UV::S_IRWXU | \UV::S_IRUSR, function ($fh) use ($deferred) { $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function readlink(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_readlink($this->loop, $path, function ($fh, $target) use ($deferred) { if (!(bool) $fh) { $deferred->fail(new FilesystemException("Could not read symbolic link")); return; } $deferred->resolve($target); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function rename(string $from, string $to): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_rename($this->loop, $from, $to, function ($fh) use ($deferred, $from) { StatCache::clear($from); $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function unlink(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_unlink($this->loop, $path, function ($fh) use ($deferred, $path) { StatCache::clear($path); $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); if ($recursive) { $path = \str_replace("/", DIRECTORY_SEPARATOR, $path); $arrayPath = \explode(DIRECTORY_SEPARATOR, $path); $tmpPath = ""; $callback = function () use ( &$callback, &$arrayPath, &$tmpPath, $mode, $deferred ) { $tmpPath .= DIRECTORY_SEPARATOR . \array_shift($arrayPath); if (empty($arrayPath)) { \uv_fs_mkdir($this->loop, $tmpPath, $mode, function ($fh) use ($deferred) { $deferred->resolve((bool) $fh); }); } else { $this->isdir($tmpPath)->onResolve(function ($error, $result) use ( $callback, $tmpPath, $mode ) { if ($result) { $callback(); } else { \uv_fs_mkdir($this->loop, $tmpPath, $mode, $callback); } }); } }; $callback(); } else { \uv_fs_mkdir($this->loop, $path, $mode, function ($fh) use ($deferred) { $deferred->resolve((bool) $fh); }); } return $deferred->promise(); } /** * {@inheritdoc} */ public function rmdir(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_rmdir($this->loop, $path, function ($fh) use ($deferred, $path) { StatCache::clear($path); $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function scandir(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_readdir($this->loop, $path, 0, function ($fh, $data) use ($deferred, $path) { if (empty($fh) && $data !== 0) { $deferred->fail(new FilesystemException("Failed reading contents from {$path}")); } elseif ($data === 0) { $deferred->resolve([]); } else { $deferred->resolve($data); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function chmod(string $path, int $mode): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_chmod($this->loop, $path, $mode, function ($fh) use ($deferred) { $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function chown(string $path, int $uid, int $gid): Promise { // @TODO Return a failure in windows environments $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_chown($this->loop, $path, $uid, $gid, function ($fh) use ($deferred) { $deferred->resolve((bool) $fh); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function touch(string $path, int $time = null, int $atime = null): Promise { $time = $time ?? \time(); $atime = $atime ?? $time; $deferred = new Deferred; $this->poll->listen($deferred->promise()); \uv_fs_utime($this->loop, $path, $time, $atime, function () use ($deferred) { // The uv_fs_utime() callback does not receive any args at this time $deferred->resolve(true); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function get(string $path): Promise { $promise = new Coroutine($this->doGet($path)); $this->poll->listen($promise); return $promise; } private function doGet($path): \Generator { $promise = $this->doFsOpen($path, $flags = \UV::O_RDONLY, $mode = 0); if (!$fh = yield $promise) { throw new FilesystemException("Failed opening file handle: {$path}"); } $deferred = new Deferred; $stat = yield $this->doFsStat($fh); if (empty($stat)) { $deferred->fail(new FilesystemException("stat operation failed on open file handle")); } elseif (!$stat["isfile"]) { \uv_fs_close($this->loop, $fh, function () use ($deferred) { $deferred->fail(new FilesystemException("cannot buffer contents: path is not a file")); }); } else { $buffer = yield $this->doFsRead($fh, $offset = 0, $stat["size"]); if ($buffer === false) { \uv_fs_close($this->loop, $fh, function () use ($deferred) { $deferred->fail(new FilesystemException("read operation failed on open file handle")); }); } else { \uv_fs_close($this->loop, $fh, function () use ($deferred, $buffer) { $deferred->resolve($buffer); }); } } return yield $deferred->promise(); } private function doFsOpen($path, $flags, $mode) { $deferred = new Deferred; \uv_fs_open($this->loop, $path, $flags, $mode, function ($fh) use ($deferred, $path) { $deferred->resolve($fh); }); return $deferred->promise(); } private function doFsStat($fh) { $deferred = new Deferred; \uv_fs_fstat($this->loop, $fh, function ($fh, $stat) use ($deferred) { if ($fh) { $stat["isdir"] = (bool) ($stat["mode"] & \UV::S_IFDIR); $stat["isfile"] = !$stat["isdir"]; $deferred->resolve($stat); } else { $deferred->resolve(); } }); return $deferred->promise(); } private function doFsRead($fh, $offset, $len) { $deferred = new Deferred; \uv_fs_read($this->loop, $fh, $offset, $len, function ($fh, $nread, $buffer) use ($deferred) { $deferred->resolve($nread < 0 ? false : $buffer); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function put(string $path, string $contents): Promise { $promise = new Coroutine($this->doPut($path, $contents)); $this->poll->listen($promise); return $promise; } private function doPut($path, $contents): \Generator { $flags = \UV::O_WRONLY | \UV::O_CREAT; $mode = \UV::S_IRWXU | \UV::S_IRUSR; $promise = $this->doFsOpen($path, $flags, $mode); if (!$fh = yield $promise) { throw new FilesystemException("Failed opening write file handle"); } $deferred = new Deferred; $len = \strlen($contents); \uv_fs_write($this->loop, $fh, $contents, $offset = 0, function ($fh, $result) use ($deferred, $len) { \uv_fs_close($this->loop, $fh, function () use ($deferred, $result, $len) { if ($result < 0) { $deferred->fail(new FilesystemException(\uv_strerror($result))); } else { $deferred->resolve($len); } }); }); return yield $deferred->promise(); } } <?php namespace Amp\File; use Amp\ByteStream\InputStream; use Amp\ByteStream\OutputStream; use Amp\Promise; interface Handle extends InputStream, OutputStream { const DEFAULT_READ_LENGTH = 8192; /** * Read $len bytes from the open file handle starting at $offset. * * @param int $length * @return \Amp\Promise<string|null> */ public function read(int $length = self::DEFAULT_READ_LENGTH): Promise; /** * Write $data to the open file handle starting at $offset. * * @param string $data * @return \Amp\Promise<int> */ public function write(string $data): Promise; /** * Write $data to the open file handle and close the handle once the write completes. * * @param string $data * * @return \Amp\Promise<int> */ public function end(string $data = ""): Promise; /** * Close the file handle. * * Applications are not required to manually close handles -- they will * be unloaded automatically when the object is garbage collected. * * @return \Amp\Promise */ public function close(): Promise; /** * Set the handle's internal pointer position. * * $whence values: * * SEEK_SET - Set position equal to offset bytes. * SEEK_CUR - Set position to current location plus offset. * SEEK_END - Set position to end-of-file plus offset. * * @param int $position * @param int $whence * @return \Amp\Promise<int> New offset position. */ public function seek(int $position, int $whence = \SEEK_SET): Promise; /** * Return the current internal offset position of the file handle. * * @return int */ public function tell(): int; /** * Test for "end-of-file" on the file handle. * * @return bool */ public function eof(): bool; /** * Retrieve the path used when opening the file handle. * * @return string */ public function path(): string; /** * Retrieve the mode used when opening the file handle. * * @return string */ public function mode(): string; } <?php namespace Amp\File; use Amp\ByteStream\ClosedException; use Amp\ByteStream\StreamException; use Amp\Coroutine; use Amp\Parallel\Worker\TaskException; use Amp\Parallel\Worker\Worker; use Amp\Parallel\Worker\WorkerException; use Amp\Promise; use Amp\Success; use function Amp\call; class ParallelHandle implements Handle { /** @var \Amp\Parallel\Worker\Worker */ private $worker; /** @var int|null */ private $id; /** @var string */ private $path; /** @var int */ private $position; /** @var int */ private $size; /** @var string */ private $mode; /** @var bool True if an operation is pending. */ private $busy = false; /** @var int Number of pending write operations. */ private $pendingWrites = 0; /** @var bool */ private $writable = true; /** @var \Amp\Promise|null */ private $closing; /** * @param \Amp\Parallel\Worker\Worker $worker * @param int $id * @param string $path * @param int $size * @param string $mode */ public function __construct(Worker $worker, int $id, string $path, int $size, string $mode) { $this->worker = $worker; $this->id = $id; $this->path = $path; $this->size = $size; $this->mode = $mode; $this->position = $this->mode[0] === 'a' ? $this->size : 0; } public function __destruct() { if ($this->id !== null) { $this->close(); } } /** * {@inheritdoc} */ public function path(): string { return $this->path; } /** * {@inheritdoc} */ public function close(): Promise { if ($this->closing) { return $this->closing; } $this->writable = false; if ($this->worker->isRunning()) { $this->closing = $this->worker->enqueue(new Internal\FileTask('fclose', [], $this->id)); $this->id = null; } else { $this->closing = new Success; } return $this->closing; } /** * {@inheritdoc} */ public function eof(): bool { return $this->pendingWrites === 0 && $this->size <= $this->position; } public function read(int $length = self::DEFAULT_READ_LENGTH): Promise { if ($this->id === null) { throw new ClosedException("The file has been closed"); } if ($this->busy) { throw new PendingOperationError; } return new Coroutine($this->doRead($length)); } private function doRead(int $length): \Generator { $this->busy = true; try { $data = yield $this->worker->enqueue(new Internal\FileTask('fread', [$length], $this->id)); $this->position += \strlen($data); return $data; } catch (TaskException $exception) { throw new StreamException("Reading from the file failed", 0, $exception); } catch (WorkerException $exception) { throw new StreamException("Sending the task to the worker failed", 0, $exception); } finally { $this->busy = false; } } /** * {@inheritdoc} */ public function write(string $data): Promise { if ($this->id === null) { throw new ClosedException("The file has been closed"); } if ($this->busy && $this->pendingWrites === 0) { throw new PendingOperationError; } if (!$this->writable) { throw new ClosedException("The file is no longer writable"); } return new Coroutine($this->doWrite($data)); } /** * {@inheritdoc} */ public function end(string $data = ""): Promise { return call(function () use ($data) { $promise = $this->write($data); $this->writable = false; // ignore any errors yield Promise\any([$this->close()]); return $promise; }); } private function doWrite(string $data): \Generator { ++$this->pendingWrites; $this->busy = true; try { $length = yield $this->worker->enqueue(new Internal\FileTask('fwrite', [$data], $this->id)); } catch (TaskException $exception) { throw new StreamException("Writing to the file failed", 0, $exception); } catch (WorkerException $exception) { throw new StreamException("Sending the task to the worker failed", 0, $exception); } finally { if (--$this->pendingWrites === 0) { $this->busy = false; } } $this->position += $length; return $length; } /** * {@inheritdoc} */ public function seek(int $offset, int $whence = SEEK_SET): Promise { if ($this->id === null) { throw new ClosedException("The file has been closed"); } if ($this->busy) { throw new PendingOperationError; } return new Coroutine($this->doSeek($offset, $whence)); } private function doSeek(int $offset, int $whence) { switch ($whence) { case \SEEK_SET: case \SEEK_CUR: case \SEEK_END: try { $this->position = yield $this->worker->enqueue( new Internal\FileTask('fseek', [$offset, $whence], $this->id) ); if ($this->position > $this->size) { $this->size = $this->position; } return $this->position; } catch (TaskException $exception) { throw new StreamException('Seeking in the file failed.', 0, $exception); } catch (WorkerException $exception) { throw new StreamException("Sending the task to the worker failed", 0, $exception); } default: throw new \Error('Invalid whence value. Use SEEK_SET, SEEK_CUR, or SEEK_END.'); } } /** * {@inheritdoc} */ public function tell(): int { return $this->position; } /** * {@inheritdoc} */ public function size(): int { return $this->size; } /** * {@inheritdoc} */ public function mode(): string { return $this->mode; } } <?php namespace Amp\File; class PendingOperationError extends \Error { public function __construct( string $message = "The previous file operation must complete before another can be started", int $code = 0, \Throwable $previous = null ) { parent::__construct($message, $code, $previous); } } <?php namespace Amp\File; use Amp\ByteStream\ClosedException; use Amp\ByteStream\StreamException; use Amp\Deferred; use Amp\File\Internal\UvPoll; use Amp\Loop; use Amp\Promise; use Amp\Success; use function Amp\call; class UvHandle implements Handle { /** @var UvPoll */ private $poll; /** @var \UVLoop */ private $loop; /** @var resource */ private $fh; /** @var string */ private $path; /** @var string */ private $mode; /** @var int */ private $size; /** @var int */ private $position; /** @var \SplQueue */ private $queue; /** @var bool */ private $isActive = false; /** @var bool */ private $writable = true; /** @var \Amp\Promise|null */ private $closing; /** * @param \Amp\Loop\UvDriver $driver * @param UvPoll $poll Poll for keeping the loop active. * @param resource $fh File handle. * @param string $path * @param string $mode * @param int $size */ public function __construct(Loop\UvDriver $driver, UvPoll $poll, $fh, string $path, string $mode, int $size) { $this->poll = $poll; $this->fh = $fh; $this->path = $path; $this->mode = $mode; $this->size = $size; $this->loop = $driver->getHandle(); $this->position = ($mode[0] === "a") ? $size : 0; $this->queue = new \SplQueue; } public function read(int $length = self::DEFAULT_READ_LENGTH): Promise { if ($this->isActive) { throw new PendingOperationError; } $deferred = new Deferred; $this->poll->listen($deferred->promise()); $this->isActive = true; $onRead = function ($fh, $result, $buffer) use ($deferred) { $this->isActive = false; if ($result < 0) { $error = \uv_strerror($result); if ($error === "bad file descriptor") { $deferred->fail(new ClosedException("Reading from the file failed due to a closed handle")); } else { $deferred->fail(new StreamException("Reading from the file failed: " . $error)); } } else { $length = \strlen($buffer); $this->position = $this->position + $length; $deferred->resolve($length ? $buffer : null); } }; \uv_fs_read($this->loop, $this->fh, $this->position, $length, $onRead); return $deferred->promise(); } /** * {@inheritdoc} */ public function write(string $data): Promise { if ($this->isActive && $this->queue->isEmpty()) { throw new PendingOperationError; } if (!$this->writable) { throw new ClosedException("The file is no longer writable"); } $this->isActive = true; if ($this->queue->isEmpty()) { $promise = $this->push($data); } else { $promise = $this->queue->top(); $promise = call(function () use ($promise, $data) { yield $promise; return yield $this->push($data); }); } $this->queue->push($promise); return $promise; } /** * {@inheritdoc} */ public function end(string $data = ""): Promise { return call(function () use ($data) { $promise = $this->write($data); $this->writable = false; // ignore any errors yield Promise\any([$this->close()]); return $promise; }); } private function push(string $data): Promise { $length = \strlen($data); $deferred = new Deferred; $this->poll->listen($deferred->promise()); $onWrite = function ($fh, $result) use ($deferred, $length) { if ($this->queue->isEmpty()) { $deferred->fail(new ClosedException('No pending write, the file may have been closed')); } $this->queue->shift(); if ($this->queue->isEmpty()) { $this->isActive = false; } if ($result < 0) { $error = \uv_strerror($result); if ($error === "bad file descriptor") { $deferred->fail(new ClosedException("Writing to the file failed due to a closed handle")); } else { $deferred->fail(new StreamException("Writing to the file failed: " . $error)); } } else { StatCache::clear($this->path); $this->position += $length; if ($this->position > $this->size) { $this->size = $this->position; } $deferred->resolve($length); } }; \uv_fs_write($this->loop, $this->fh, $data, $this->position, $onWrite); return $deferred->promise(); } /** * {@inheritdoc} */ public function seek(int $offset, int $whence = \SEEK_SET): Promise { if ($this->isActive) { throw new PendingOperationError; } $offset = (int) $offset; switch ($whence) { case \SEEK_SET: $this->position = $offset; break; case \SEEK_CUR: $this->position = $this->position + $offset; break; case \SEEK_END: $this->position = $this->size + $offset; break; default: throw new \Error( "Invalid whence parameter; SEEK_SET, SEEK_CUR or SEEK_END expected" ); } return new Success($this->position); } /** * {@inheritdoc} */ public function tell(): int { return $this->position; } /** * {@inheritdoc} */ public function eof(): bool { return !$this->queue->isEmpty() ? false : ($this->size <= $this->position); } /** * {@inheritdoc} */ public function path(): string { return $this->path; } /** * {@inheritdoc} */ public function mode(): string { return $this->mode; } /** * {@inheritdoc} */ public function close(): Promise { if ($this->closing) { return $this->closing; } $deferred = new Deferred; $this->poll->listen($this->closing = $deferred->promise()); \uv_fs_close($this->loop, $this->fh, function ($fh) use ($deferred) { // Ignore errors when closing file, as the handle will become invalid anyway. $deferred->resolve(); }); return $deferred->promise(); } } <?php namespace Amp\File; use Amp\Promise; interface Driver { /** * Open a handle for the specified path. * * @param string $path * @param string $mode * @return \Amp\Promise<\Amp\File\Handle> */ public function open(string $path, string $mode): Promise; /** * Execute a file stat operation. * * If the requested path does not exist the resulting Promise will resolve to NULL. * * @param string $path The file system path to stat * @return \Amp\Promise<array|null> */ public function stat(string $path): Promise; /** * Does the specified path exist? * * This function should never resolve as a failure -- only a successfull bool value * indicating the existence of the specified path. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ public function exists(string $path): Promise; /** * Retrieve the size in bytes of the file at the specified path. * * If the path does not exist or is not a regular file this * function's returned Promise WILL resolve as a failure. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function size(string $path): Promise; /** * Does the specified path exist and is it a directory? * * If the path does not exist the returned Promise will resolve * to FALSE and will not reject with an error. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ public function isdir(string $path): Promise; /** * Does the specified path exist and is it a file? * * If the path does not exist the returned Promise will resolve * to FALSE and will not reject with an error. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ public function isfile(string $path): Promise; /** * Retrieve the path's last modification time as a unix timestamp. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function mtime(string $path): Promise; /** * Retrieve the path's last access time as a unix timestamp. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function atime(string $path): Promise; /** * Retrieve the path's creation time as a unix timestamp. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function ctime(string $path): Promise; /** * Same as stat() except if the path is a link then the link's data is returned. * * @param string $path The file system path to stat * @return \Amp\Promise A promise resolving to an associative array upon successful resolution */ public function lstat(string $path): Promise; /** * Create a symlink $link pointing to the file/directory located at $target. * * @param string $target * @param string $link * @return \Amp\Promise */ public function symlink(string $target, string $link): Promise; /** * Create a hard link $link pointing to the file/directory located at $target. * * @param string $target * @param string $link * @return \Amp\Promise */ public function link(string $target, string $link): Promise; /** * Read the symlink at $path. * * @param string $target * @return \Amp\Promise */ public function readlink(string $target): Promise; /** * Rename a file or directory. * * @param string $from * @param string $to * @return \Amp\Promise */ public function rename(string $from, string $to): Promise; /** * Delete a file. * * @param string $path * @return \Amp\Promise */ public function unlink(string $path): Promise; /** * Create a director. * * @param string $path * @param int $mode * @param bool $recursive * @return \Amp\Promise */ public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise; /** * Delete a directory. * * @param string $path * @return \Amp\Promise */ public function rmdir(string $path): Promise; /** * Retrieve an array of files and directories inside the specified path. * * Dot entries are not included in the resulting array (i.e. "." and ".."). * * @param string $path * @return \Amp\Promise */ public function scandir(string $path): Promise; /** * chmod a file or directory. * * @param string $path * @param int $mode * @return \Amp\Promise */ public function chmod(string $path, int $mode): Promise; /** * chown a file or directory. * * @param string $path * @param int $uid * @param int $gid * @return \Amp\Promise */ public function chown(string $path, int $uid, int $gid): Promise; /** * Update the access and modification time of the specified path. * * If the file does not exist it will be created automatically. * * @param string $path * @param int $time The touch time. If $time is not supplied, the current system time is used. * @param int $atime The access time. If $atime is not supplied, value passed to the $time parameter is used. * @return \Amp\Promise */ public function touch(string $path, int $time = null, int $atime = null): Promise; /** * Buffer the specified file's contents. * * @param string $path The file path from which to buffer contents * @return \Amp\Promise A promise resolving to a string upon successful resolution */ public function get(string $path): Promise; /** * Write the contents string to the specified path. * * @param string $path The file path to which to $contents should be written * @param string $contents The data to write to the specified $path * @return \Amp\Promise A promise resolving to the integer length written upon success */ public function put(string $path, string $contents): Promise; } <?php namespace Amp\File; use Amp\Deferred; use Amp\Promise; use Amp\Success; class EioDriver implements Driver { /** @var \Amp\File\Internal\EioPoll */ private $poll; /** * @return bool Determines if this driver can be used based on the environment. */ public static function isSupported(): bool { return \extension_loaded('eio'); } public function __construct() { $this->poll = new Internal\EioPoll; } /** * {@inheritdoc} */ public function open(string $path, string $mode): Promise { $flags = \EIO_O_NONBLOCK | \EIO_O_FSYNC | $this->parseMode($mode); $chmod = ($flags & \EIO_O_CREAT) ? 0644 : 0; $deferred = new Deferred; $this->poll->listen($deferred->promise()); $openArr = [$mode, $path, $deferred]; \eio_open($path, $flags, $chmod, \EIO_PRI_DEFAULT, [$this, "onOpenHandle"], $openArr); return $deferred->promise(); } private function parseMode(string $mode): int { $mode = \str_replace(['b', 't', 'e'], '', $mode); switch ($mode) { case 'r': return \EIO_O_RDONLY; case 'r+': return \EIO_O_RDWR; case 'w': return \EIO_O_WRONLY | \EIO_O_TRUNC | \EIO_O_CREAT; case 'w+': return \EIO_O_RDWR | \EIO_O_TRUNC | \EIO_O_CREAT; case 'a': return \EIO_O_WRONLY | \EIO_O_APPEND | \EIO_O_CREAT; case 'a+': return \EIO_O_RDWR | \EIO_O_APPEND | \EIO_O_CREAT; case 'x': return \EIO_O_WRONLY | \EIO_O_CREAT | \EIO_O_EXCL; case 'x+': return \EIO_O_RDWR | \EIO_O_CREAT | \EIO_O_EXCL; case 'c': return \EIO_O_WRONLY | \EIO_O_CREAT; case 'c+': return \EIO_O_RDWR | \EIO_O_CREAT; default: throw new \Error('Invalid file mode'); } } private function onOpenHandle($openArr, $result, $req) { list($mode, $path, $deferred) = $openArr; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } elseif ($mode[0] === "a") { \array_unshift($openArr, $result); \eio_ftruncate($result, $offset = 0, \EIO_PRI_DEFAULT, [$this, "onOpenFtruncate"], $openArr); } else { \array_unshift($openArr, $result); \eio_fstat($result, \EIO_PRI_DEFAULT, [$this, "onOpenFstat"], $openArr); } } private function onOpenFtruncate($openArr, $result, $req) { list($fh, $mode, $path, $deferred) = $openArr; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $handle = new EioHandle($this->poll, $fh, $path, $mode, $size = 0); $deferred->resolve($handle); } } private function onOpenFstat($openArr, $result, $req) { list($fh, $mode, $path, $deferred) = $openArr; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { StatCache::set($path, $result); $handle = new EioHandle($this->poll, $fh, $path, $mode, $result["size"]); $deferred->resolve($handle); } } /** * {@inheritdoc} */ public function stat(string $path): Promise { if ($stat = StatCache::get($path)) { return new Success($stat); } $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; $data = [$deferred, $path]; \eio_stat($path, $priority, [$this, "onStat"], $data); return $deferred->promise(); } private function onStat($data, $result, $req) { list($deferred, $path) = $data; if ($result === -1) { $deferred->resolve(null); } else { StatCache::set($path, $result); $deferred->resolve($result); } } /** * {@inheritdoc} */ public function exists(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { $deferred->resolve((bool) $result); }); return $deferred->promise(); } /** * {@inheritdoc} */ public function isdir(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve(!($result["mode"] & \EIO_S_IFREG)); } else { $deferred->resolve(false); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function isfile(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve((bool) ($result["mode"] & \EIO_S_IFREG)); } else { $deferred->resolve(false); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function size(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if (empty($result)) { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } elseif ($result["mode"] & \EIO_S_IFREG) { $deferred->resolve($result["size"]); } else { $deferred->fail(new FilesystemException( "Specified path is not a regular file" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function mtime(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve($result["mtime"]); } else { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function atime(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve($result["atime"]); } else { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function ctime(string $path): Promise { $deferred = new Deferred; $this->stat($path)->onResolve(function ($error, $result) use ($deferred) { if ($result) { $deferred->resolve($result["ctime"]); } else { $deferred->fail(new FilesystemException( "Specified path does not exist" )); } }); return $deferred->promise(); } /** * {@inheritdoc} */ public function lstat(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_lstat($path, $priority, [$this, "onLstat"], $deferred); return $deferred->promise(); } private function onLstat($deferred, $result, $req) { if ($result === -1) { $deferred->resolve(null); } else { $deferred->resolve($result); } } /** * {@inheritdoc} */ public function symlink(string $target, string $link): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_symlink($target, $link, $priority, [$this, "onGenericResult"], $deferred); return $deferred->promise(); } /** * {@inheritdoc} */ public function link(string $target, string $link): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_link($target, $link, $priority, [$this, "onGenericResult"], $deferred); return $deferred->promise(); } /** * {@inheritdoc} */ public function readlink(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_readlink($path, $priority, [$this, "onReadlink"], $deferred); return $deferred->promise(); } private function onReadlink($deferred, $result, $req) { if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $deferred->resolve($result); } } private function onGenericResult($deferred, $result, $req) { if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $deferred->resolve(true); } } /** * {@inheritdoc} */ public function rename(string $from, string $to): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_rename($from, $to, $priority, [$this, "onGenericResult"], $deferred); return $deferred->promise(); } /** * {@inheritdoc} */ public function unlink(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; $data = [$deferred, $path]; \eio_unlink($path, $priority, [$this, "onUnlink"], $data); return $deferred->promise(); } private function onUnlink($data, $result, $req) { list($deferred, $path) = $data; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { StatCache::clear($path); $deferred->resolve(true); } } /** * {@inheritdoc} */ public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; if ($recursive) { $path = \str_replace("/", DIRECTORY_SEPARATOR, $path); $arrayPath = \explode(DIRECTORY_SEPARATOR, $path); $tmpPath = ""; $callback = function () use ( &$callback, &$arrayPath, &$tmpPath, $mode, $priority, $deferred ) { $tmpPath .= DIRECTORY_SEPARATOR . \array_shift($arrayPath); if (empty($arrayPath)) { \eio_mkdir($tmpPath, $mode, $priority, [$this, "onGenericResult"], $deferred); } else { $this->isdir($tmpPath)->onResolve(function ($error, $result) use ( $callback, $tmpPath, $mode, $priority ) { if ($result) { $callback(); } else { \eio_mkdir($tmpPath, $mode, $priority, $callback); } }); } }; $callback(); } else { \eio_mkdir($path, $mode, $priority, [$this, "onGenericResult"], $deferred); } return $deferred->promise(); } /** * {@inheritdoc} */ public function rmdir(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; $data = [$deferred, $path]; \eio_rmdir($path, $priority, [$this, "onRmdir"], $data); return $deferred->promise(); } private function onRmdir($data, $result, $req) { list($deferred, $path) = $data; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { StatCache::clear($path); $deferred->resolve(true); } } /** * {@inheritdoc} */ public function scandir(string $path): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $flags = \EIO_READDIR_STAT_ORDER | \EIO_READDIR_DIRS_FIRST; $priority = \EIO_PRI_DEFAULT; \eio_readdir($path, $flags, $priority, [$this, "onScandir"], $deferred); return $deferred->promise(); } private function onScandir($deferred, $result, $req) { if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $result = $result["names"]; \sort($result); $deferred->resolve($result); } } /** * {@inheritdoc} */ public function chmod(string $path, int $mode): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_chmod($path, $mode, $priority, [$this, "onGenericResult"], $deferred); return $deferred->promise(); } /** * {@inheritdoc} */ public function chown(string $path, int $uid, int $gid): Promise { $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_chown($path, $uid, $gid, $priority, [$this, "onGenericResult"], $deferred); return $deferred->promise(); } /** * {@inheritdoc} */ public function touch(string $path, int $time = null, int $atime = null): Promise { $time = $time ?? \time(); $atime = $atime ?? $time; $deferred = new Deferred; $this->poll->listen($deferred->promise()); $priority = \EIO_PRI_DEFAULT; \eio_utime($path, $atime, $time, $priority, [$this, "onGenericResult"], $deferred); return $deferred->promise(); } /** * {@inheritdoc} */ public function get(string $path): Promise { $flags = $flags = \EIO_O_RDONLY; $mode = 0; $priority = \EIO_PRI_DEFAULT; $deferred = new Deferred; $this->poll->listen($deferred->promise()); \eio_open($path, $flags, $mode, $priority, [$this, "onGetOpen"], $deferred); return $deferred->promise(); } private function onGetOpen($deferred, $result, $req) { if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $priority = \EIO_PRI_DEFAULT; \eio_fstat($result, $priority, [$this, "onGetFstat"], [$result, $deferred]); } } private function onGetFstat($fhAndPromisor, $result, $req) { list($fh, $deferred) = $fhAndPromisor; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); return; } $offset = 0; $length = $result["size"]; $priority = \EIO_PRI_DEFAULT; \eio_read($fh, $length, $offset, $priority, [$this, "onGetRead"], $fhAndPromisor); } private function onGetRead($fhAndPromisor, $result, $req) { list($fh, $deferred) = $fhAndPromisor; \eio_close($fh); if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $deferred->resolve($result); } } /** * {@inheritdoc} */ public function put(string $path, string $contents): Promise { $flags = \EIO_O_RDWR | \EIO_O_CREAT; $mode = \EIO_S_IRUSR | \EIO_S_IWUSR | \EIO_S_IXUSR; $priority = \EIO_PRI_DEFAULT; $deferred = new Deferred; $this->poll->listen($deferred->promise()); $data = [$contents, $deferred]; \eio_open($path, $flags, $mode, $priority, [$this, "onPutOpen"], $data); return $deferred->promise(); } private function onPutOpen($data, $result, $req) { list($contents, $deferred) = $data; if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $length = \strlen($contents); $offset = 0; $priority = \EIO_PRI_DEFAULT; $callback = [$this, "onPutWrite"]; $fhAndPromisor = [$result, $deferred]; \eio_write($result, $contents, $length, $offset, $priority, $callback, $fhAndPromisor); } } private function onPutWrite($fhAndPromisor, $result, $req) { list($fh, $deferred) = $fhAndPromisor; \eio_close($fh); if ($result === -1) { $deferred->fail(new FilesystemException(\eio_get_last_error($req))); } else { $deferred->resolve($result); } } } <?php namespace Amp\File; use Amp\Failure; use Amp\Promise; use Amp\Success; class BlockingDriver implements Driver { /** * {@inheritdoc} */ public function open(string $path, string $mode): Promise { $mode = \str_replace(['b', 't', 'e'], '', $mode); switch ($mode) { case "r": case "r+": case "w": case "w+": case "a": case "a+": case "x": case "x+": case "c": case "c+": break; default: throw new \Error("Invalid file mode"); } if (!$fh = \fopen($path, $mode . 'be')) { return new Failure(new FilesystemException( "Failed opening file handle" )); } return new Success(new BlockingHandle($fh, $path, $mode)); } /** * {@inheritdoc} */ public function stat(string $path): Promise { if ($stat = StatCache::get($path)) { return new Success($stat); } elseif ($stat = @\stat($path)) { StatCache::set($path, $stat); \clearstatcache(true, $path); } else { $stat = null; } return new Success($stat); } /** * {@inheritdoc} */ public function exists(string $path): Promise { if ($exists = @\file_exists($path)) { \clearstatcache(true, $path); } return new Success($exists); } /** * Retrieve the size in bytes of the file at the specified path. * * If the path does not exist or is not a regular file this * function's returned Promise WILL resolve as a failure. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function size(string $path): Promise { if (!@\file_exists($path)) { return new Failure(new FilesystemException( "Path does not exist" )); } if (!@\is_file($path)) { return new Failure(new FilesystemException( "Path is not a regular file" )); } if (($size = @\filesize($path)) === false) { return new Failure(new FilesystemException( \error_get_last()["message"] )); } \clearstatcache(true, $path); return new Success($size); } /** * Does the specified path exist and is it a directory? * * If the path does not exist the returned Promise will resolve * to FALSE. It will NOT reject with an error. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ public function isdir(string $path): Promise { if (!@\file_exists($path)) { return new Success(false); } $isDir = @\is_dir($path); \clearstatcache(true, $path); return new Success($isDir); } /** * Does the specified path exist and is it a file? * * If the path does not exist the returned Promise will resolve * to FALSE. It will NOT reject with an error. * * @param string $path An absolute file system path * @return \Amp\Promise<bool> */ public function isfile(string $path): Promise { if (!@\file_exists($path)) { return new Success(false); } $isFile = @\is_file($path); \clearstatcache(true, $path); return new Success($isFile); } /** * Retrieve the path's last modification time as a unix timestamp. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function mtime(string $path): Promise { if (!@\file_exists($path)) { return new Failure(new FilesystemException( "Path does not exist" )); } $mtime = @\filemtime($path); \clearstatcache(true, $path); return new Success($mtime); } /** * Retrieve the path's last access time as a unix timestamp. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function atime(string $path): Promise { if (!@\file_exists($path)) { return new Failure(new FilesystemException( "Path does not exist" )); } $atime = @\fileatime($path); \clearstatcache(true, $path); return new Success($atime); } /** * Retrieve the path's creation time as a unix timestamp. * * @param string $path An absolute file system path * @return \Amp\Promise<int> */ public function ctime(string $path): Promise { if (!@\file_exists($path)) { return new Failure(new FilesystemException( "Path does not exist" )); } $ctime = @\filectime($path); \clearstatcache(true, $path); return new Success($ctime); } /** * {@inheritdoc} */ public function lstat(string $path): Promise { if ($stat = @\lstat($path)) { \clearstatcache(true, $path); } else { $stat = null; } return new Success($stat); } /** * {@inheritdoc} */ public function symlink(string $target, string $link): Promise { if (!@\symlink($target, $link)) { return new Failure(new FilesystemException("Could not create symbolic link")); } return new Success(true); } /** * {@inheritdoc} */ public function link(string $target, string $link): Promise { if (!@\link($target, $link)) { return new Failure(new FilesystemException("Could not create hard link")); } return new Success(true); } /** * {@inheritdoc} */ public function readlink(string $path): Promise { if (!($result = @\readlink($path))) { return new Failure(new FilesystemException("Could not read symbolic link")); } return new Success($result); } /** * {@inheritdoc} */ public function rename(string $from, string $to): Promise { if (!@\rename($from, $to)) { return new Failure(new FilesystemException("Could not rename file")); } return new Success(true); } /** * {@inheritdoc} */ public function unlink(string $path): Promise { StatCache::clear($path); return new Success((bool) @\unlink($path)); } /** * {@inheritdoc} */ public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise { return new Success((bool) @\mkdir($path, $mode, $recursive)); } /** * {@inheritdoc} */ public function rmdir(string $path): Promise { StatCache::clear($path); return new Success((bool) @\rmdir($path)); } /** * {@inheritdoc} */ public function scandir(string $path): Promise { if (!@\is_dir($path)) { return new Failure(new FilesystemException( "Not a directory" )); } elseif ($arr = @\scandir($path)) { $arr = \array_values(\array_filter($arr, function ($el) { return !($el === "." || $el === ".."); })); \clearstatcache(true, $path); return new Success($arr); } return new Failure(new FilesystemException( "Failed reading contents from {$path}" )); } /** * {@inheritdoc} */ public function chmod(string $path, int $mode): Promise { return new Success((bool) @\chmod($path, $mode)); } /** * {@inheritdoc} */ public function chown(string $path, int $uid, int $gid): Promise { if ($uid !== -1 && !@\chown($path, $uid)) { return new Failure(new FilesystemException( \error_get_last()["message"] )); } if ($gid !== -1 && !@\chgrp($path, $gid)) { return new Failure(new FilesystemException( \error_get_last()["message"] )); } return new Success; } /** * {@inheritdoc} */ public function touch(string $path, int $time = null, int $atime = null): Promise { $time = $time ?? \time(); $atime = $atime ?? $time; return new Success((bool) \touch($path, $time, $atime)); } /** * {@inheritdoc} */ public function get(string $path): Promise { $result = @\file_get_contents($path); return ($result === false) ? new Failure(new FilesystemException(\error_get_last()["message"])) : new Success($result); } /** * {@inheritdoc} */ public function put(string $path, string $contents): Promise { $result = @\file_put_contents($path, $contents); return ($result === false) ? new Failure(new FilesystemException(\error_get_last()["message"])) : new Success($result); } } <?php namespace Amp\File; class FilesystemException extends \Exception { public function __construct(string $message, \Throwable $previous = null) { parent::__construct($message, 0, $previous); } } <?php namespace Amp\File; use Amp\Coroutine; use Amp\Parallel\Worker; use Amp\Parallel\Worker\Pool; use Amp\Parallel\Worker\TaskException; use Amp\Parallel\Worker\WorkerException; use Amp\Promise; use Amp\Success; use function Amp\call; class ParallelDriver implements Driver { /** * @var \Amp\Parallel\Worker\Pool */ private $pool; /** * @param \Amp\Parallel\Worker\Pool|null $pool */ public function __construct(Pool $pool = null) { $this->pool = $pool ?: Worker\pool(); } /** * {@inheritdoc} */ public function open(string $path, string $mode): Promise { return call(function () use ($path, $mode) { $worker = $this->pool->getWorker(); try { list($id, $size, $mode) = yield $worker->enqueue(new Internal\FileTask("fopen", [$path, $mode])); } catch (TaskException $exception) { throw new FilesystemException("Could not open file", $exception); } catch (WorkerException $exception) { throw new FilesystemException("Could not send open request to worker", $exception); } return new ParallelHandle($worker, $id, $path, $size, $mode); }); } private function runFileTask(Internal\FileTask $task): \Generator { try { return yield $this->pool->enqueue($task); } catch (TaskException $exception) { throw new FilesystemException("The file operation failed", $exception); } catch (WorkerException $exception) { throw new FilesystemException("Could not send the file task to worker", $exception); } } /** * {@inheritdoc} */ public function unlink(string $path): Promise { return call(function () use ($path) { $result = yield from $this->runFileTask(new Internal\FileTask("unlink", [$path])); StatCache::clear($path); return $result; }); } /** * {@inheritdoc} */ public function stat(string $path): Promise { if ($stat = StatCache::get($path)) { return new Success($stat); } return call(function () use ($path) { $stat = yield from $this->runFileTask(new Internal\FileTask("stat", [$path])); if (!empty($stat)) { StatCache::set($path, $stat); } return $stat; }); } /** * {@inheritdoc} */ public function rename(string $from, string $to): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("rename", [$from, $to]))); } /** * {@inheritdoc} */ public function isfile(string $path): Promise { return call(function () use ($path) { $stat = yield $this->stat($path); if (empty($stat)) { return false; } if ($stat["mode"] & 0100000) { return true; } return false; }); } /** * {@inheritdoc} */ public function isdir(string $path): Promise { return call(function () use ($path) { $stat = yield $this->stat($path); if (empty($stat)) { return false; } if ($stat["mode"] & 0040000) { return true; } return false; }); } /** * {@inheritdoc} */ public function link(string $target, string $link): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("link", [$target, $link]))); } /** * {@inheritdoc} */ public function symlink(string $target, string $link): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("symlink", [$target, $link]))); } /** * {@inheritdoc} */ public function readlink(string $path): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("readlink", [$path]))); } /** * {@inheritdoc} */ public function mkdir(string $path, int $mode = 0777, bool $recursive = false): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("mkdir", [$path, $mode, $recursive]))); } /** * {@inheritdoc} */ public function scandir(string $path): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("scandir", [$path]))); } /** * {@inheritdoc} */ public function rmdir(string $path): Promise { return call(function () use ($path) { $result = yield from $this->runFileTask(new Internal\FileTask("rmdir", [$path])); StatCache::clear($path); return $result; }); } /** * {@inheritdoc} */ public function chmod(string $path, int $mode): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("chmod", [$path, $mode]))); } /** * {@inheritdoc} */ public function chown(string $path, int $uid, int $gid): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("chown", [$path, $uid, $gid]))); } /** * {@inheritdoc} */ public function exists(string $path): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("exists", [$path]))); } /** * {@inheritdoc} */ public function size(string $path): Promise { return call(function () use ($path) { $stat = yield $this->stat($path); if (empty($stat)) { throw new FilesystemException("Specified path does not exist"); } if ($stat["mode"] & 0100000) { return $stat["size"]; } throw new FilesystemException("Specified path is not a regular file"); }); } /** * {@inheritdoc} */ public function mtime(string $path): Promise { return call(function () use ($path) { $stat = yield $this->stat($path); if (empty($stat)) { throw new FilesystemException("Specified path does not exist"); } return $stat["mtime"]; }); } /** * {@inheritdoc} */ public function atime(string $path): Promise { return call(function () use ($path) { $stat = yield $this->stat($path); if (empty($stat)) { throw new FilesystemException("Specified path does not exist"); } return $stat["atime"]; }); } /** * {@inheritdoc} */ public function ctime(string $path): Promise { return call(function () use ($path) { $stat = yield $this->stat($path); if (empty($stat)) { throw new FilesystemException("Specified path does not exist"); } return $stat["ctime"]; }); } /** * {@inheritdoc} */ public function lstat(string $path): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("lstat", [$path]))); } /** * {@inheritdoc} */ public function touch(string $path, int $time = null, int $atime = null): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("touch", [$path, $time, $atime]))); } /** * {@inheritdoc} */ public function get(string $path): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("get", [$path]))); } /** * {@inheritdoc} */ public function put(string $path, string $contents): Promise { return new Coroutine($this->runFileTask(new Internal\FileTask("put", [$path, $contents]))); } } { "name": "amphp/websocket", "description": "Shared code for websocket servers and clients.", "license": "MIT", "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "support": { "issues": "https://github.com/amphp/websocket/issues" }, "keywords": [ "async", "non-blocking", "websocket", "http", "amp", "amphp" ], "require": { "php": ">=7.1", "amphp/amp": "^2", "amphp/byte-stream": "^1.5", "amphp/socket": "^0.10", "cash/lrucache": "^1.0" }, "require-dev": { "phpunit/phpunit": "^6", "amphp/phpunit-util": "^1", "amphp/php-cs-fixer-config": "dev-master" }, "suggest": { "ext-zlib": "Required for compression" }, "autoload": { "psr-4": { "Amp\\Websocket\\": "src" }, "files": [ "src/functions.php" ] }, "autoload-dev": { "psr-4": { "Amp\\Websocket\\Test\\": "test" }, "files": [ "test/functions.php" ] }, "config": { "platform": { "php": "7.1" } } } <?php namespace Amp\Websocket\Test; // 4-bit "random" mask const MASK = "\xF4\x37\x7A\x9C"; function compile(int $opcode, bool $masked, bool $isFinal, string $data = "", int $rsv = 0b000): string { $length = \strlen($data); $w = \chr(($isFinal << 7) | ($rsv << 4) | $opcode); $maskFlag = $masked ? 0x80 : 0; if ($length > 0xFFFF) { $w .= \chr(0x7F | $maskFlag) . \pack('J', $length); } elseif ($length > 0x7D) { $w .= \chr(0x7E | $maskFlag) . \pack('n', $length); } else { $w .= \chr($length | $maskFlag); } if ($masked) { return $w . MASK . ($data ^ \str_repeat(MASK, ($length + 3) >> 2)); } return $w . $data; } <?php namespace Amp\Websocket\Test; use Amp\ByteStream\IteratorStream; use Amp\Delayed; use Amp\Emitter; use Amp\Loop; use Amp\PHPUnit\TestCase; use Amp\Promise; use Amp\Socket\Socket; use Amp\Success; use Amp\Websocket\Code; use Amp\Websocket\Opcode; use Amp\Websocket\Options; use Amp\Websocket\Rfc6455Client; use PHPUnit\Framework\MockObject\MockObject; class ClientTest extends TestCase { /** * @return Socket|MockObject */ protected function createSocket(): Socket { $socket = $this->createMock(Socket::class); $socket->method('getResource') ->willReturn(\fopen('php://memory', 'r')); return $socket; } public function testGetId(): void { $socket = $this->createSocket(); $options = Options::createServerDefault(); $client1 = new Rfc6455Client($socket, $options, false); $client2 = new Rfc6455Client($socket, $options, false); $this->assertNotSame($client1->getId(), $client2->getId()); } public function testClose(): void { Loop::run(function () { $code = Code::PROTOCOL_ERROR; $reason = 'Close reason'; $socket = $this->createSocket(); $packet = compile(Opcode::CLOSE, false, true, \pack('n', $code) . $reason); $socket->expects($this->once()) ->method('write') ->with($packet) ->willReturn(new Success(\strlen($packet))); $socket->expects($this->exactly(2)) ->method('read') ->willReturnOnConsecutiveCalls( new Delayed(0, compile(Opcode::CLOSE, true, true, \pack('n', $code) . $reason)), new Success ); $client = new Rfc6455Client($socket, Options::createServerDefault(), false); yield $client->close($code, $reason); $this->assertFalse($client->isConnected()); $this->assertFalse($client->didPeerInitiateClose()); $this->assertSame($code, $client->getCloseCode()); $this->assertSame($reason, $client->getCloseReason()); }); } public function testCloseWithoutResponse(): void { Loop::run(function () { $code = Code::NORMAL_CLOSE; $reason = 'Close reason'; $socket = $this->createSocket(); $packet = compile(Opcode::CLOSE, false, true, \pack('n', $code) . $reason); $socket->expects($this->once()) ->method('write') ->with($packet) ->willReturn(new Success(\strlen($packet))); $socket->expects($this->once()) ->method('read') ->willReturn(new Delayed(1200)); $client = new Rfc6455Client($socket, Options::createServerDefault()->withClosePeriod(1), false); $invoked = false; $client->onClose(function () use (&$invoked) { $invoked = true; }); Loop::delay(1100, function () use (&$invoked) { if (!$invoked) { $this->fail("Close timeout period not enforced"); } }); yield $client->close($code, $reason); $this->assertFalse($client->isConnected()); $this->assertFalse($client->didPeerInitiateClose()); $this->assertSame($code, $client->getCloseCode()); $this->assertSame($reason, $client->getCloseReason()); $this->assertTrue($invoked); }); } public function testPing(): void { Loop::run(function () { $socket = $this->createSocket(); $packet = compile(Opcode::PING, false, true, '1'); $socket->expects($this->once()) ->method('write') ->with($packet) ->willReturn(new Success(\strlen($packet))); $client = new Rfc6455Client($socket, Options::createServerDefault(), false); yield $client->ping(); }); } public function testSend(): void { Loop::run(function () { $socket = $this->createSocket(); $packet = compile(Opcode::TEXT, false, true, 'data'); $socket->expects($this->once()) ->method('write') ->with($packet) ->willReturn(new Success(\strlen($packet))); $client = new Rfc6455Client($socket, Options::createServerDefault(), false); yield $client->send('data'); }); } public function testSendBinary(): void { Loop::run(function () { $socket = $this->createSocket(); $packet = compile(Opcode::BIN, false, true, 'data'); $socket->expects($this->once()) ->method('write') ->with($packet) ->willReturn(new Success(\strlen($packet))); $client = new Rfc6455Client($socket, Options::createServerDefault(), false); yield $client->sendBinary('data'); }); } public function testStream(): void { Loop::run(function () { $socket = $this->createSocket(); $packet = compile(Opcode::TEXT, false, true, 'chunk1chunk2chunk3'); $socket->expects($this->once()) ->method('write') ->with($packet) ->willReturn(new Success(\strlen($packet))); $client = new Rfc6455Client($socket, Options::createServerDefault(), false); $emitter = new Emitter; $emitter->emit('chunk1'); $emitter->emit('chunk2'); $emitter->emit('chunk3'); $emitter->complete(); $stream = new IteratorStream($emitter->iterate()); yield $client->stream($stream); }); } public function testStreamMultipleChunks(): void { Loop::run(function () { $packets = [ compile(Opcode::TEXT, false, false, 'chunk1chunk2'), compile(Opcode::CONT, false, true, 'chunk3'), ]; $socket = $this->createSocket(); $socket->expects($this->exactly(2)) ->method('write') ->withConsecutive(...\array_map(function (string $packet) { return [$packet]; }, $packets)) ->willReturnOnConsecutiveCalls( ...\array_map(function (string $packet): Promise { return new Success(\strlen($packet)); }, $packets) ); $client = new Rfc6455Client($socket, Options::createServerDefault()->withStreamThreshold(10), false); $emitter = new Emitter; $emitter->emit('chunk1'); $emitter->emit('chunk2'); $emitter->emit('chunk'); $emitter->emit('3'); $emitter->complete(); $stream = new IteratorStream($emitter->iterate()); yield $client->stream($stream); }); } } <?php namespace Amp\Websocket\Test; use Amp\Delayed; use Amp\Loop; use Amp\PHPUnit\TestCase; use Amp\Socket\Socket; use Amp\Success; use Amp\Websocket\ClosedException; use Amp\Websocket\Code; use Amp\Websocket\Message; use Amp\Websocket\Opcode; use Amp\Websocket\Options; use Amp\Websocket\Rfc6455Client; class ParserTest extends TestCase { /** * @dataProvider provideParserData */ public function testParser( string $chunk, ?string $data, bool $isBinary, ?string $reason = null, ?int $code = null ): void { Loop::run(function () use ($chunk, $data, $isBinary, $code, $reason) { $socket = $this->createMock(Socket::class); $socket->method('read') ->willReturnOnConsecutiveCalls(new Success($chunk), new Delayed(1, null)); $socket->method('write') ->willReturnCallback(function (string $data) { return new Success(\strlen($data)); }); $socket->method('getResource') ->willReturn(\fopen('php://memory', 'r')); $client = new Rfc6455Client($socket, Options::createServerDefault(), false); try { while ($message = yield $client->receive()) { \assert($message instanceof Message); $this->assertSame($data, yield $message->buffer()); $this->assertSame(!$isBinary, $message->isText()); $this->assertSame($isBinary, $message->isBinary()); $client->close(); } } catch (ClosedException $exception) { $this->assertSame($code, $exception->getCode()); $this->assertSame($reason, $exception->getReason()); } $this->assertSame($code ?? Code::NORMAL_CLOSE, $client->getCloseCode()); $this->assertSame($reason ?? '', $client->getCloseReason()); }); } public function provideParserData(): array { $return = []; // 0-13 -- basic text and binary frames with fixed lengths --------------------------------> foreach ([0 /* 0-1 */, 125 /* 2-3 */, 126 /* 4-5 */, 127 /* 6-7 */, 128 /* 8-9 */, 65535 /* 10-11 */, 65536 /* 12-13 */] as $length) { $data = \str_repeat("*", $length); foreach ([Opcode::TEXT, Opcode::BIN] as $optype) { $input = compile($optype, true, true, $data); $return[] = [$input, $data, $optype === Opcode::BIN]; } } // // 14-17 - basic control frame parsing ----------------------------------------------------> foreach (["" /* 14 */, "Hello world!" /* 15 */, "\x00\xff\xfe\xfd\xfc\xfb\x00\xff" /* 16 */, \str_repeat("*", 125) /* 17 */] as $data) { $input = compile(Opcode::PING, true, true, $data); $return[] = [$input, null, false, "Underlying TCP connection closed", Code::ABNORMAL_CLOSE]; } // 18 ---- error conditions: using a non-terminated frame with a control opcode -----------> $input = compile(Opcode::PING, true, false); $return[] = [$input, null, false, "Illegal control frame fragmentation", Code::PROTOCOL_ERROR]; // 19 ---- error conditions: using a standalone continuation frame with fin = true --------> $input = compile(Opcode::CONT, true, true); $return[] = [$input, null, false, "Illegal CONTINUATION opcode; initial message payload frame must be TEXT or BINARY", Code::PROTOCOL_ERROR]; // 20 ---- error conditions: using a standalone continuation frame with fin = false -------> $input = compile(Opcode::CONT, true, false); $return[] = [$input, null, false, "Illegal CONTINUATION opcode; initial message payload frame must be TEXT or BINARY", Code::PROTOCOL_ERROR]; // 21 ---- error conditions: using a continuation frame after a finished text frame -------> $input = compile(Opcode::TEXT, true, true, "Hello, world!") . compile(Opcode::CONT, true, true); $return[] = [$input, "Hello, world!", false, "Illegal CONTINUATION opcode; initial message payload frame must be TEXT or BINARY", Code::PROTOCOL_ERROR]; // 22-29 - continuation frame parsing -----------------------------------------------------> foreach ([[1, 0] /* 22-23 */, [126, 125] /* 24-25 */, [32767, 32769] /* 26-27 */, [32768, 32769] /* 28-29 */] as list($len1, $len2)) { // simple $input = compile(Opcode::TEXT, true, false, \str_repeat("*", $len1)) . compile(Opcode::CONT, true, true, \str_repeat("*", $len2)); $return[] = [$input, \str_repeat("*", $len1 + $len2), false]; // with interleaved control frame $input = compile(Opcode::TEXT, true, false, \str_repeat("*", $len1)) . compile(Opcode::PING, true, true, "foo") . compile(Opcode::CONT, true, true, \str_repeat("*", $len2)); $return[] = [$input, \str_repeat("*", $len1 + $len2), false]; } // 30 ---- error conditions: using a text frame after a not finished text frame -----------> $input = compile(Opcode::TEXT, true, false, "Hello, world!") . compile(Opcode::TEXT, true, true, "uhm, no!"); $return[] = [$input, null, false, "Illegal data type opcode after unfinished previous data type frame; opcode MUST be CONTINUATION", Code::PROTOCOL_ERROR]; // 31 ---- utf-8 validation must resolve for large utf-8 msgs -----------------------------> $data = "H" . \str_repeat("ö", 32770); $input = compile(Opcode::TEXT, true, false, \substr($data, 0, 32769)) . compile(Opcode::CONT, true, true, \substr($data, 32769)); $return[] = [$input, $data, false]; // 32 ---- utf-8 validation must resolve for interrupted utf-8 across frame boundary ------> $data = "H" . \str_repeat("ö", 32770); $input = compile(Opcode::TEXT, true, false, \substr($data, 0, 32768)) . compile(Opcode::CONT, true, true, \substr($data, 32768)); $return[] = [$input, $data, false]; // 33 ---- utf-8 validation must fail for bad utf-8 data (single frame) -------------------> $input = compile(Opcode::TEXT, true, true, \substr(\str_repeat("ö", 2), 1)); $return[] = [$input, null, false, "Invalid TEXT data; UTF-8 required", Code::INCONSISTENT_FRAME_DATA_TYPE]; // 34 ---- utf-8 validation must fail for bad utf-8 data (multiple small frames) ----------> $data = "H" . \str_repeat("ö", 3); $input = compile(Opcode::TEXT, true, false, \substr($data, 0, 2)) . compile(Opcode::CONT, true, true, \substr($data, 3)); $return[] = [$input, null, false, "Invalid TEXT data; UTF-8 required", Code::INCONSISTENT_FRAME_DATA_TYPE]; // 35 ---- utf-8 validation must fail for bad utf-8 data (multiple big frames) ------------> $data = "H" . \str_repeat("ö", 40000); $input = compile(Opcode::TEXT, true, false, \substr($data, 0, 32767)) . compile(Opcode::CONT, true, false, \substr($data, 32768)); $return[] = [$input, null, false, "Invalid TEXT data; UTF-8 required", Code::INCONSISTENT_FRAME_DATA_TYPE]; // 36 ---- error conditions: using a too large payload with a control opcode --------------> $input = compile(Opcode::PING, true, true, \str_repeat("*", 126)); $return[] = [$input, null, false, "Control frame payload must be of maximum 125 bytes or less", Code::PROTOCOL_ERROR]; // 37 ---- error conditions: unmasked data ------------------------------------------------> $input = \substr(compile(Opcode::PING, true, true, \str_repeat("*", 125)), 0, -4) & ("\xFF\x7F" . \str_repeat("\xFF", 0xFF)); $return[] = [$input, null, false, "Payload mask error", Code::PROTOCOL_ERROR]; // 38 ---- error conditions: too large frame (> 2^63 bit) ---------------------------------> $input = compile(Opcode::BIN, true, true, \str_repeat("*", 65536)) | ("\x00\x00\x80" . \str_repeat("\x00", 0xFF)); $return[] = [$input, null, true, "Most significant bit of 64-bit length field set", Code::PROTOCOL_ERROR]; // 39 ---- utf-8 must be accepted for interrupted text with interleaved control frame -----> $data = "H" . \str_repeat("ö", 32770); $input = compile(Opcode::TEXT, true, false, \substr($data, 0, 32768)) . compile(Opcode::PING, true, true, "foo") . compile(Opcode::CONT, true, true, \substr($data, 32768)); $return[] = [$input, $data, false]; // 40 ---- close frame --------------------------------------------------------------------> $input = compile(Opcode::CLOSE, true, true); $return[] = [$input, null, true, '', Code::NONE]; // 41 ---- invalid close code -------------------------------------------------------------> $input = compile(Opcode::CLOSE, true, true, \pack('n', 5000)); $return[] = [$input, null, true, "Invalid close code", Code::PROTOCOL_ERROR]; // 42 ---- invalid close payload ----------------------------------------------------------> $input = compile(Opcode::CLOSE, true, true, "0"); $return[] = [$input, null, true, "Close code must be two bytes", Code::PROTOCOL_ERROR]; // 43 ---- non-utf-8 close payload --------------------------------------------------------> $input = compile(Opcode::CLOSE, true, true, \pack('n', Code::NORMAL_CLOSE) . "\x80\x00"); $return[] = [$input, null, true, "Close reason must be valid UTF-8", Code::INCONSISTENT_FRAME_DATA_TYPE]; // 44 ---- pong frame ---------------------------------------------------------------------> $input = compile(Opcode::PONG, true, true, "123"); $return[] = [$input, null, true, "Underlying TCP connection closed", Code::ABNORMAL_CLOSE]; // 45 ---- pong frame with invalid payload ------------------------------------------------> $input = compile(Opcode::PONG, true, true, "0"); $return[] = [$input, null, true, "Underlying TCP connection closed", Code::ABNORMAL_CLOSE]; // x --------------------------------------------------------------------------------------> return $return; } } <?php namespace Amp\Websocket; interface CompressionContext { /** * @return int The RSV value for this compression extension. */ public function getRsv(): int; /** * @return int Minimum number of bytes a message must be before compressing. */ public function getCompressionThreshold(): int; /** * Compress the given payload data. * * @param string $data * @param bool $isFinal * * @return string */ public function compress(string $data, bool $isFinal): string; /** * Decompress the given payload data. Null should be returned if decompression fails. * * @param string $data * @param bool $isFinal * * @return string|null */ public function decompress(string $data, bool $isFinal): ?string; } <?php namespace Amp\Websocket; final class Opcode { public const CONT = 0x00; public const TEXT = 0x01; public const BIN = 0x02; public const CLOSE = 0x08; public const PING = 0x09; public const PONG = 0x0A; /** * @codeCoverageIgnore Class cannot be instigated. */ private function __construct() { // forbid instances } } <?php namespace Amp\Websocket; final class Rfc7692CompressionFactory implements CompressionContextFactory { public function fromClientHeader(string $headerIn, ?string &$headerOut): ?CompressionContext { return Rfc7692Compression::fromClientHeader($headerIn, $headerOut); } public function fromServerHeader(string $header): ?CompressionContext { return Rfc7692Compression::fromServerHeader($header); } public function createRequestHeader(): string { return Rfc7692Compression::createRequestHeader(); } } <?php namespace Amp\Websocket; // defined in https://tools.ietf.org/html/rfc6455#section-4 const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; /** * @param int $length Random bytes to use to generate the key. * * @return string * * @throws \Exception If generating a random key fails. */ function generateKey(int $length = 16): string { return \base64_encode(\random_bytes($length)); } /** * Generates the value for the Sec-Websocket-Accept header based on the given Sec-Websocket-Key header value. * * @param string $key * * @return string */ function generateAcceptFromKey(string $key): string { return \base64_encode(\sha1($key . GUID, true)); } /** * Determines if the Sec-Websocket-Accept value given matches the expected value for the Sec-Websocket-Key header. * * @param string $accept * @param string $key * * @return bool */ function validateAcceptForKey(string $accept, string $key): bool { return $accept === generateAcceptFromKey($key); } <?php namespace Amp\Websocket; use Amp\Socket\Socket; use Amp\Struct; final class ClientMetadata { use Struct; /** @var string Next sequential client ID. */ private static $nextId = 'a'; /** @var string */ public $id; /** @var bool */ public $peerInitiatedClose = false; /** @var int|null */ public $closeCode; /** @var string|null */ public $closeReason; // Timestamps of when the event occurred. public $connectedAt = 0; public $closedAt = 0; public $lastReadAt = 0; public $lastSentAt = 0; public $lastDataReadAt = 0; public $lastDataSentAt = 0; public $lastHeartbeatAt = 0; // Simple counters. public $bytesRead = 0; public $bytesSent = 0; public $framesRead = 0; public $framesSent = 0; public $messagesRead = 0; public $messagesSent = 0; public $pingCount = 0; public $pongCount = 0; /** @var bool */ public $compressionEnabled; /** @var string */ public $localAddress; /** @var int|null */ public $localPort; /** @var string */ public $remoteAddress; /** @var int|null */ public $remotePort; /** @var bool */ public $isEncrypted; /** @var mixed[] Array from stream_get_meta_data($this->socket)["crypto"] or an empty array. */ public $cryptoInfo = []; /** * @param Socket $socket * @param int $time Current timestamp. * @param bool $compressionEnabled */ public function __construct(Socket $socket, int $time, bool $compressionEnabled) { $this->id = self::$nextId++; $resource = $socket->getResource(); if ($resource !== null) { $this->cryptoInfo = \stream_get_meta_data($resource)["crypto"] ?? []; } $this->isEncrypted = !empty($this->cryptoInfo); $this->connectedAt = $time; $this->compressionEnabled = $compressionEnabled; $localName = (string) $socket->getLocalAddress(); if ($portStartPos = \strrpos($localName, ":")) { $this->localAddress = \substr($localName, 0, $portStartPos); $this->localPort = (int) \substr($localName, $portStartPos + 1); } else { $this->localAddress = $localName; } $remoteName = (string) $socket->getRemoteAddress(); if ($portStartPos = \strrpos($remoteName, ":")) { $this->remoteAddress = \substr($remoteName, 0, $portStartPos); $this->remotePort = (int) \substr($remoteName, $portStartPos + 1); } else { $this->remoteAddress = $localName; } } } <?php namespace Amp\Websocket; interface CompressionContextFactory { /** * Create a compression context from a header received from a websocket client request. * * @param string $headerIn Header from request. * @param string $headerOut Sec-Websocket-Extension response header. * * @return CompressionContext|null */ public function fromClientHeader(string $headerIn, ?string &$headerOut): ?CompressionContext; /** * Create a compression context from a header received from a websocket server response. * * @param string $header Header from response. * * @return CompressionContext|null */ public function fromServerHeader(string $header): ?CompressionContext; /** * @return string Header value for Sec-Websocket-Extension header. */ public function createRequestHeader(): string; } <?php namespace Amp\Websocket; use Amp\ByteStream\InputStream; use Amp\Promise; interface Client { /** * Receive a message from the remote Websocket endpoint. * * @return Promise<Message|null> Resolves to message sent by the remote. * * @throws ClosedException Thrown if the connection is closed. */ public function receive(): Promise; /** * @return string Unique identifier for the client. */ public function getId(): string; /** * @return bool True if the client is still connected, false otherwise. Returns false as soon as the closing * handshake is initiated by the server or client. */ public function isConnected(): bool; /** * @return string The local IP address or unix socket path of the client. */ public function getLocalAddress(): string; /** * @return int|null The local port or null for unix sockets. */ public function getLocalPort(): ?int; /** * @return string The remote IP address or unix socket path of the client. */ public function getRemoteAddress(): string; /** * @return int|null The remote port or null for unix sockets. */ public function getRemotePort(): ?int; /** * @return bool `true` if the client is encrypted, `false` if plaintext. */ public function isEncrypted(): bool; /** * If the client is encrypted, returns the array returned from stream_get_meta_data($this->socket)["crypto"]. * Otherwise returns an empty array. * * @return array */ public function getCryptoContext(): array; /** * @return int Number of pings sent that have not been answered. */ public function getUnansweredPingCount(): int; /** * @return int Client close code (generally one of those listed in Code, though not necessarily). * * @throws \Error Thrown if the client has not closed. */ public function getCloseCode(): int; /** * @return string Client close reason. * * @throws \Error Thrown if the client has not closed. */ public function getCloseReason(): string; /** * @return bool True if the peer initiated the websocket close. * * @throws \Error Thrown if the client has not closed. */ public function didPeerInitiateClose(): bool; /** * Sends a text message to the endpoint. All data sent with this method must be valid UTF-8. Use `sendBinary()` if * you want to send binary data. * * @param string $data Payload to send. * * @return Promise<int> Resolves with the number of bytes sent to the other endpoint. * * @throws ClosedException Thrown if sending to the client fails. */ public function send(string $data): Promise; /** * Sends a binary message to the endpoint. * * @param string $data Payload to send. * * @return Promise<int> Resolves with the number of bytes sent to the other endpoint. * * @throws ClosedException Thrown if sending to the client fails. */ public function sendBinary(string $data): Promise; /** * Streams the given UTF-8 text stream to the endpoint. This method should be used only for large payloads such as * files. Use send() for smaller payloads. * * @param InputStream $stream * * @return Promise<int> Resolves with the number of bytes sent to the other endpoint. * * @throws ClosedException Thrown if sending to the client fails. */ public function stream(InputStream $stream): Promise; /** * Streams the given binary to the endpoint. This method should be used only for large payloads such as * files. Use sendBinary() for smaller payloads. * * @param InputStream $stream * * @return Promise<int> Resolves with the number of bytes sent to the other endpoint. * * @throws ClosedException Thrown if sending to the client fails. */ public function streamBinary(InputStream $stream): Promise; /** * Sends a ping to the endpoint. * * @return Promise<int> Resolves with the number of bytes sent to the other endpoint. */ public function ping(): Promise; /** * @return Options The options object associated with this client. */ public function getOptions(): Options; /** * Returns connection metadata. * * @return ClientMetadata */ public function getInfo(): ClientMetadata; /** * Closes the client connection. * * @param int $code * @param string $reason * * @return Promise<int> Resolves with the number of bytes sent to the other endpoint. */ public function close(int $code = Code::NORMAL_CLOSE, string $reason = ''): Promise; /** * Attaches a callback invoked when the client closes. The callback is passed this object as the first parameter, * the close code as the second parameter, and the close reason as the third parameter. * * @param callable(Client $client, int $code, string $reason) $callback */ public function onClose(callable $callback): void; } <?php namespace Amp\Websocket; final class ClosedException extends \Exception { /** @var string */ private $reason; public function __construct(string $message, int $code, string $reason) { parent::__construct($message, $code); $this->reason = $reason; } public function getReason(): string { return $this->reason; } } <?php namespace Amp\Websocket; final class Code { public const NORMAL_CLOSE = 1000; public const GOING_AWAY = 1001; public const PROTOCOL_ERROR = 1002; public const UNACCEPTABLE_TYPE = 1003; // 1004 reserved and unused. public const NONE = 1005; public const ABNORMAL_CLOSE = 1006; public const INCONSISTENT_FRAME_DATA_TYPE = 1007; public const POLICY_VIOLATION = 1008; public const MESSAGE_TOO_LARGE = 1009; public const EXPECTED_EXTENSION_MISSING = 1010; public const UNEXPECTED_SERVER_ERROR = 1011; public const SERVICE_RESTARTING = 1012; public const TRY_AGAIN_LATER = 1013; public const BAD_GATEWAY = 1014; public const TLS_HANDSHAKE_FAILURE = 1015; /** * @codeCoverageIgnore Class cannot be instigated. */ private function __construct() { // no instances allowed } } <?php namespace Amp\Websocket; final class Options { private $streamThreshold = 32768; // 32KB private $frameSplitThreshold = 32768; // 32KB private $bytesPerSecondLimit = 1048576; // 1MB private $framesPerSecondLimit = 100; private $frameSizeLimit = 2097152; // 2MB private $messageSizeLimit = 10485760; // 10MB private $textOnly = false; private $validateUtf8 = true; private $closePeriod = 3; private $compressionEnabled = false; private $heartbeatEnabled = true; private $heartbeatPeriod = 10; private $queuedPingLimit = 3; /** * Creates an Options object with values as documented on the accessor methods. * * @return self */ public static function createServerDefault(): self { return new self; // Initial parameter values already tuned for servers. } /** * Creates an Options object with values as documented on the accessor methods except for the following: * * Compression is enabled if the zlib extension is installed. * Bytes per second limit is set to PHP_INT_MAX (effectively removing the limit). * Frames per second limit is set to PHP_INI_MAX (effectively removing the limit). * Message size limit is set to 1 GB. * Frame size limit is set to 100 MB. * * @return self */ public static function createClientDefault(): self { $options = new self; $options->bytesPerSecondLimit = \PHP_INT_MAX; $options->framesPerSecondLimit = \PHP_INT_MAX; $options->messageSizeLimit = 2 ** 30; // 1 GB $options->frameSizeLimit = 2 ** 20 * 100; // 100 MB if (\extension_loaded('zlib')) { $options->compressionEnabled = true; } return $options; } private function __construct() { // Private constructor to require use of named constructors. } /** * @return int Number of bytes that will be buffered when streaming a message * body before sending a frame. */ public function getStreamThreshold(): int { return $this->streamThreshold; } /** * @param int $streamThreshold Number of bytes that will be buffered when * streaming a message body before sending a frame. Default is 32768 (32KB) * * @return self * * @throws \Error if the number is less than 1. */ public function withStreamThreshold(int $streamThreshold): self { if ($streamThreshold < 1) { throw new \Error('$streamThreshold must be a positive integer greater than 0'); } $clone = clone $this; $clone->streamThreshold = $streamThreshold; return $clone; } /** * @return int If a message exceeds this number of bytes, it is split into * multiple frames, each no bigger than this value. */ public function getFrameSplitThreshold(): int { return $this->frameSplitThreshold; } /** * @param int $frameSplitThreshold If a message exceeds this number of bytes, * it is split into multiple frames, each no bigger than this value. * Default is 32768 (32KB) * * @return self * * @throws \Error if number is less than 1. */ public function withFrameSplitThreshold(int $frameSplitThreshold): self { if ($frameSplitThreshold < 1) { throw new \Error('$frameSplitThreshold must be a positive integer greater than 0'); } $clone = clone $this; $clone->frameSplitThreshold = $frameSplitThreshold; return $clone; } /** * @return int Maximum frame size that can be received from the peer. If a * larger frame is received, the connection is ended with a POLICY_VIOLATION. */ public function getFrameSizeLimit(): int { return $this->frameSizeLimit; } /** * @param int $frameSizeLimit Maximum frame size that can be received from the peer. * If a larger frame is received, the connection is ended with a POLICY_VIOLATION. * Default is 2097152 (2MB) * * @return self * * @throws \Error if number is less than 1. */ public function withFrameSizeLimit(int $frameSizeLimit): self { if ($frameSizeLimit < 1) { throw new \Error('$frameSizeLimit must be a positive integer greater than 0'); } $clone = clone $this; $clone->frameSizeLimit = $frameSizeLimit; return $clone; } /** * @return int Maximum number of bytes the peer can send per second before being throttled. */ public function getBytesPerSecondLimit(): int { return $this->bytesPerSecondLimit; } /** * @param int $bytesPerSecond Maximum number of bytes the peer can send per * second before being throttled. Default is 1048576 (1MB) * * @return self * * @throws \Error if number is less than 1. */ public function withBytesPerSecondLimit(int $bytesPerSecond): self { if ($bytesPerSecond < 1) { throw new \Error('$bytesPerSecond must be a positive integer greater than 0'); } $clone = clone $this; $clone->bytesPerSecondLimit = $bytesPerSecond; return $clone; } /** * @return int Maximum number of frames the peer can send per second before being throttled. */ public function getFramesPerSecondLimit(): int { return $this->bytesPerSecondLimit; } /** * @param int $framesPerSecond Maximum number of frames the peer can send per * second before being throttled. * * @return self * * @throws \Error if number is less than 1. */ public function withFramesPerSecondLimit(int $framesPerSecond): self { if ($framesPerSecond < 1) { throw new \Error('$bytesPerSecond must be a positive integer greater than 0'); } $clone = clone $this; $clone->framesPerSecondLimit = $framesPerSecond; return $clone; } /** * @return int Maximum message size that can be received from the remote endpoint. * If a larger message is received, the connection is ended with a POLICY_VIOLATION. */ public function getMessageSizeLimit(): int { return $this->messageSizeLimit; } /** * @param int $messageSizeLimit Maximum message size that can be received * from the remote endpoint. If a larger message is received, the connection * is ended with a POLICY_VIOLATION. Default is 10485760 (10MB) * * @return self * * @throws \Error if number is less than 1. */ public function withMessageSizeLimit(int $messageSizeLimit): self { if ($messageSizeLimit < 1) { throw new \Error('$messageSizeLimit must be a positive integer greater than 0'); } $clone = clone $this; $clone->messageSizeLimit = $messageSizeLimit; return $clone; } /** * @return bool If true ends the connection if a binary frame is received. */ public function isTextOnly(): bool { return $this->textOnly; } /** * @param bool $textOnly If true ends the connection if a binary frame is received. * * @return self */ public function withTextOnly(bool $textOnly): self { $clone = clone $this; $clone->textOnly = $textOnly; return $clone; } /** * @return bool If true validates that all text received and sent is UTF-8. */ public function isValidateUtf8(): bool { return $this->validateUtf8; } /** * @param bool $validateUtf8 If true validates that all text received and sent is UTF-8. * * @return self */ public function withValidateUtf8(bool $validateUtf8): self { $clone = clone $this; $clone->validateUtf8 = $validateUtf8; return $clone; } /** * @return int Number of seconds to wait to receive peer close frame. */ public function getClosePeriod(): int { return $this->closePeriod; } /** * @param int $closePeriod Number of seconds to wait to receive peer close * frame. Default is 3. * * @return self * * @throws \Error if number is less than 1. */ public function withClosePeriod(int $closePeriod): self { if ($closePeriod < 1) { throw new \Error('$closePeriod must be a positive integer greater than 0'); } $clone = clone $this; $clone->closePeriod = $closePeriod; return $clone; } /** * @return bool Whether to request or accept per-message compression. */ public function isCompressionEnabled(): bool { return $this->compressionEnabled; } /** * @return self Enables requesting or accepting per-message compression. */ public function withCompression(): self { $clone = clone $this; $clone->compressionEnabled = true; return $clone; } /** * @return self Disables requesting or accepting per-message compression. */ public function withoutCompression(): self { $clone = clone $this; $clone->compressionEnabled = false; return $clone; } /** * @return bool If enabled, sends a ping frame to the peer every X seconds (determined * by the heartbeat period) if there is no other activity on the connection. */ public function isHeartbeatEnabled(): bool { return $this->heartbeatEnabled; } /** * @return self Enables heartbeat; If enabled, sends a ping frame to the * peer every X seconds (determined by the heartbeat period) if there * is no other activity on the connection. */ public function withHeartbeat(): self { $clone = clone $this; $clone->heartbeatEnabled = true; return $clone; } /** * @return self Disables heartbeat; If disabled, will not periodically send * a ping frame to the peer during timetrames of inactivity on the connection. */ public function withoutHeartbeat(): self { $clone = clone $this; $clone->heartbeatEnabled = false; return $clone; } /** * @return int Duration in seconds between pings or other connection activity if the heartbeat is enabled. */ public function getHeartbeatPeriod(): int { return $this->heartbeatPeriod; } /** * @param int $heartbeatPeriod Duration in seconds between pings or other * connection activity if the heartbeat is enabled. Default is 10. * * @return self * * @throws \Error if number is less than 1. */ public function withHeartbeatPeriod(int $heartbeatPeriod): self { if ($heartbeatPeriod < 1) { throw new \Error('$heartbeatPeriod must be a positive integer greater than 0'); } $clone = clone $this; $clone->heartbeatPeriod = $heartbeatPeriod; return $clone; } /** * @return int The number of unanswered pings before the connection is closed. */ public function getQueuedPingLimit(): int { return $this->queuedPingLimit; } /** * @param int $queuedPingLimit The number of unanswered pings before the connection is closed. * * @return self * * @throws \Error if number is less than 1. */ public function withQueuedPingLimit(int $queuedPingLimit): self { if ($queuedPingLimit < 1) { throw new \Error('$queuedPingLimit must be a positive integer greater than 0'); } $clone = clone $this; $clone->queuedPingLimit = $queuedPingLimit; return $clone; } } <?php namespace Amp\Websocket; use Amp\ByteStream\InputStream; use Amp\ByteStream\Payload; /** * This class allows streamed and buffered access to the websocket message by extending Payload. */ final class Message extends Payload { /** @var bool */ private $binary; public function __construct(InputStream $stream, bool $binary) { parent::__construct($stream); $this->binary = $binary; } /** * @return bool True if the message is UTF-8 text, false if it is binary. * * @see Message::isBinary() */ public function isText(): bool { return !$this->binary; } /** * @return bool True if the message is binary, false if it is UTF-8 text. * * @see Message::isText() */ public function isBinary(): bool { return $this->binary; } } <?php namespace Amp\Websocket; use Amp\ByteStream\InputStream; use Amp\ByteStream\IteratorStream; use Amp\ByteStream\StreamException; use Amp\Coroutine; use Amp\Deferred; use Amp\Emitter; use Amp\Loop; use Amp\Promise; use Amp\Socket\Socket; use Amp\Success; use cash\LRUCache; use function Amp\call; final class Rfc6455Client implements Client { /** @var self[] */ private static $clients; /** @var int[] */ private static $bytesReadInLastSecond = []; /** @var int[] */ private static $framesReadInLastSecond = []; /** @var Deferred[] */ private static $rateDeferreds = []; /** @var string */ private static $watcher; /** @var LRUCache Array of next ping (heartbeat) times. */ private static $heartbeatTimeouts; /** @var int Cached current time. */ private static $now; /** @var Options */ private $options; /** @var \Amp\Socket\Socket */ private $socket; /** @var \Amp\Promise|null */ private $lastWrite; /** @var Promise|null */ private $lastEmit; /** @var string */ private $emitBuffer = ''; /** @var bool */ private $masked; /** @var CompressionContext|null */ private $compressionContext; /** @var Emitter|null */ private $currentMessageEmitter; /** @var Deferred|null */ private $nextMessageDeferred; /** @var Message[] */ private $messages = []; /** @var callable[]|null */ private $onClose = []; /** @var ClientMetadata */ private $metadata; /** @var Deferred */ private $closeDeferred; /** * @param Socket $socket * @param Options $options * @param bool $masked True for client, false for server. * @param CompressionContext|null $compression */ public function __construct( Socket $socket, Options $options, bool $masked, ?CompressionContext $compression = null ) { $this->socket = $socket; $this->options = $options; $this->masked = $masked; $this->compressionContext = $compression; $this->closeDeferred = new Deferred; if (self::$watcher === null) { self::$now = \time(); self::$heartbeatTimeouts = new class(\PHP_INT_MAX) extends LRUCache implements \IteratorAggregate { public function getIterator(): \Iterator { yield from $this->data; } }; self::$watcher = Loop::repeat(1000, static function (): void { self::$now = \time(); self::$bytesReadInLastSecond = []; self::$framesReadInLastSecond = []; if (!empty(self::$rateDeferreds)) { Loop::unreference(self::$watcher); $rateDeferreds = self::$rateDeferreds; self::$rateDeferreds = []; foreach ($rateDeferreds as $deferred) { $deferred->resolve(); } } foreach (self::$heartbeatTimeouts as $clientId => $expiryTime) { if ($expiryTime >= self::$now) { break; } $client = self::$clients[$clientId]; \assert($client instanceof self); self::$heartbeatTimeouts->put($clientId, self::$now + $client->options->getHeartbeatPeriod()); if ($client->getUnansweredPingCount() > $client->options->getQueuedPingLimit()) { $client->close(Code::POLICY_VIOLATION, 'Exceeded unanswered PING limit'); continue; } $client->ping(); } }); Loop::unreference(self::$watcher); } $this->metadata = new ClientMetadata($socket, self::$now, $compression !== null); self::$clients[$this->metadata->id] = $this; if ($this->options->isHeartbeatEnabled()) { self::$heartbeatTimeouts->put($this->metadata->id, self::$now + $this->options->getHeartbeatPeriod()); } Promise\rethrow(new Coroutine($this->read())); } public function receive(): Promise { if ($this->nextMessageDeferred) { throw new \Error('Await the previous promise returned from receive() before calling receive() again.'); } // There might be messages already buffered and a close frame already received if ($this->messages) { $message = \reset($this->messages); unset($this->messages[\key($this->messages)]); return new Success($message); } if ($this->metadata->closedAt) { return new Success; } $this->nextMessageDeferred = new Deferred; return $this->nextMessageDeferred->promise(); } public function getId(): string { return $this->metadata->id; } public function getUnansweredPingCount(): int { return $this->metadata->pingCount - $this->metadata->pongCount; } public function isConnected(): bool { return !$this->metadata->closedAt; } public function getLocalAddress(): string { return $this->metadata->localAddress; } public function getLocalPort(): ?int { return $this->metadata->localPort; } public function getRemoteAddress(): string { return $this->metadata->remoteAddress; } public function getRemotePort(): ?int { return $this->metadata->remotePort; } public function isEncrypted(): bool { return !empty($this->metadata->cryptoInfo); } public function getCryptoContext(): array { return $this->metadata->cryptoInfo; } public function getCloseCode(): int { if (!$this->metadata->closedAt) { throw new \Error('The client has not closed'); } return $this->metadata->closeCode; } public function getCloseReason(): string { if (!$this->metadata->closedAt) { throw new \Error('The client has not closed'); } return $this->metadata->closeReason; } public function didPeerInitiateClose(): bool { if (!$this->metadata->closedAt) { throw new \Error('The client has not closed'); } return $this->metadata->peerInitiatedClose; } public function getOptions(): Options { return $this->options; } public function getInfo(): ClientMetadata { return clone $this->metadata; } private function read(): \Generator { $maxFramesPerSecond = $this->options->getFramesPerSecondLimit(); $maxBytesPerSecond = $this->options->getBytesPerSecondLimit(); $heartbeatEnabled = $this->options->isHeartbeatEnabled(); $heartbeatPeriod = $this->options->getHeartbeatPeriod(); $parser = $this->parser(); try { while (($chunk = yield $this->socket->read()) !== null) { if ($chunk === '') { continue; } $this->metadata->lastReadAt = self::$now; self::$bytesReadInLastSecond[$this->metadata->id] = (self::$bytesReadInLastSecond[$this->metadata->id] ?? 0) + \strlen($chunk); if ($heartbeatEnabled) { self::$heartbeatTimeouts->put($this->metadata->id, self::$now + $heartbeatPeriod); } $parser->send($chunk); $chunk = ''; // Free memory from last chunk read. if ((self::$framesReadInLastSecond[$this->metadata->id] ?? 0) >= $maxFramesPerSecond || self::$bytesReadInLastSecond[$this->metadata->id] >= $maxBytesPerSecond) { Loop::reference(self::$watcher); // Reference watcher to keep loop running until rate limit released. self::$rateDeferreds[$this->metadata->id] = $deferred = new Deferred; yield $deferred->promise(); } if ($this->lastEmit && !$this->metadata->closedAt) { yield $this->lastEmit; } } } catch (\Throwable $exception) { // Ignore stream exception, connection will be closed below anyway. } if ($this->closeDeferred !== null) { $deferred = $this->closeDeferred; $this->closeDeferred = null; $deferred->resolve(); } if (!$this->metadata->closedAt) { $this->close(Code::ABNORMAL_CLOSE, 'Underlying TCP connection closed'); } } private function onData(int $opcode, string $data, bool $terminated): void { // Ignore further data received after initiating close. if ($this->metadata->closedAt) { return; } $this->metadata->lastDataReadAt = self::$now; ++$this->metadata->framesRead; self::$framesReadInLastSecond[$this->metadata->id] = (self::$framesReadInLastSecond[$this->metadata->id] ?? 0) + 1; if (!$this->currentMessageEmitter) { if ($opcode === Opcode::CONT) { $this->onError( Code::PROTOCOL_ERROR, 'Illegal CONTINUATION opcode; initial message payload frame must be TEXT or BINARY' ); return; } $this->currentMessageEmitter = new Emitter; $message = new Message(new IteratorStream($this->currentMessageEmitter->iterate()), $opcode === Opcode::BIN); if ($this->nextMessageDeferred) { $deferred = $this->nextMessageDeferred; $this->nextMessageDeferred = null; $deferred->resolve($message); } else { $this->messages[] = $message; } } elseif ($opcode !== Opcode::CONT) { $this->onError( Code::PROTOCOL_ERROR, 'Illegal data type opcode after unfinished previous data type frame; opcode MUST be CONTINUATION' ); return; } $this->emitBuffer .= $data; if ($terminated || \strlen($this->emitBuffer) >= $this->options->getStreamThreshold()) { $promise = $this->currentMessageEmitter->emit($this->emitBuffer); $this->lastEmit = $this->nextMessageDeferred ? null : $promise; $this->emitBuffer = ''; } if ($terminated) { $emitter = $this->currentMessageEmitter; $this->currentMessageEmitter = null; $emitter->complete(); ++$this->metadata->messagesRead; } } private function onControlFrame(int $opcode, string $data): void { // Close already completed, so ignore any further data from the parser. if ($this->metadata->closedAt && $this->closeDeferred === null) { return; } ++$this->metadata->framesRead; self::$framesReadInLastSecond[$this->metadata->id] = (self::$framesReadInLastSecond[$this->metadata->id] ?? 0) + 1; switch ($opcode) { case Opcode::CLOSE: if ($this->closeDeferred) { $deferred = $this->closeDeferred; $this->closeDeferred = null; $deferred->resolve(); } if ($this->metadata->closedAt) { break; } $this->metadata->peerInitiatedClose = true; $length = \strlen($data); if ($length === 0) { $code = Code::NONE; $reason = ''; } elseif ($length < 2) { $code = Code::PROTOCOL_ERROR; $reason = 'Close code must be two bytes'; } else { $code = \current(\unpack('n', \substr($data, 0, 2))); $reason = \substr($data, 2); if ($code < 1000 // Reserved and unused. || ($code >= 1004 && $code <= 1006) // Should not be sent over wire. || ($code >= 1014 && $code <= 1015) // Should not be sent over wire. || ($code >= 1016 && $code <= 1999) // Reserved for future use || ($code >= 2000 && $code <= 2999) // Reserved for WebSocket extensions. || $code >= 5000 // 3000-3999 for libraries, 4000-4999 for applications, >= 5000 invalid. ) { $code = Code::PROTOCOL_ERROR; $reason = 'Invalid close code'; } elseif ($this->options->isValidateUtf8() && !\preg_match('//u', $reason)) { $code = Code::INCONSISTENT_FRAME_DATA_TYPE; $reason = 'Close reason must be valid UTF-8'; } } $this->close($code, $reason); break; case Opcode::PING: $this->write($data, Opcode::PONG); break; case Opcode::PONG: if (!\preg_match('/^[1-9][0-9]*$/', $data)) { // Ignore pong payload that is not an integer. break; } // We need a min() here, else someone might just send a pong frame with a very high pong count and // leave TCP connection in open state... Then we'd accumulate connections which never are cleaned up... $this->metadata->pongCount = \min($this->metadata->pingCount, (int) $data); break; } } private function onError(int $code, string $reason): void { $this->close($code, $reason); } public function send(string $data): Promise { \assert(\preg_match('//u', $data), 'Text data must be UTF-8'); return $this->lastWrite = new Coroutine($this->sendData($data, Opcode::TEXT)); } public function sendBinary(string $data): Promise { return $this->lastWrite = new Coroutine($this->sendData($data, Opcode::BIN)); } public function stream(InputStream $stream): Promise { return $this->lastWrite = new Coroutine($this->sendStream($stream, Opcode::TEXT)); } public function streamBinary(InputStream $stream): Promise { return $this->lastWrite = new Coroutine($this->sendStream($stream, Opcode::BIN)); } public function ping(): Promise { $this->metadata->lastHeartbeatAt = self::$now; ++$this->metadata->pingCount; return $this->write((string) $this->metadata->pingCount, Opcode::PING); } private function sendData(string $data, int $opcode): \Generator { if ($this->lastWrite) { yield $this->lastWrite; } ++$this->metadata->messagesSent; $this->metadata->lastDataSentAt = self::$now; $rsv = 0; $compress = false; if ($this->compressionContext && $opcode === Opcode::TEXT && \strlen($data) > $this->compressionContext->getCompressionThreshold() ) { $rsv |= $this->compressionContext->getRsv(); $compress = true; } try { $bytes = 0; if (\strlen($data) > $this->options->getFrameSplitThreshold()) { $length = \strlen($data); $slices = (int) \ceil($length / $this->options->getFrameSplitThreshold()); $length = (int) \ceil($length / $slices); while ($data !== '') { $chunk = \substr($data, 0, $length); $data = (string) \substr($data, $length); if ($compress) { $chunk = $this->compressionContext->compress($chunk, $data === ''); } $bytes += yield $this->write($chunk, $opcode, $rsv, $data === ''); $opcode = Opcode::CONT; $rsv = 0; // RSV must be 0 in continuation frames. } } else { if ($compress) { $data = $this->compressionContext->compress($data, true); } $bytes = yield $this->write($data, $opcode, $rsv, true); } } catch (StreamException $exception) { $code = Code::ABNORMAL_CLOSE; $reason = 'Writing to the client failed'; yield $this->close($code, $reason); throw new ClosedException('Client unexpectedly closed', $code, $reason); } return $bytes; } private function sendStream(InputStream $stream, int $opcode): \Generator { if ($this->lastWrite) { yield $this->lastWrite; } $rsv = 0; $compress = false; if ($this->compressionContext && $opcode === Opcode::TEXT) { $rsv |= $this->compressionContext->getRsv(); $compress = true; } try { $buffer = yield $stream->read(); if ($buffer === null) { return yield $this->write('', $opcode, 0, true); } $written = 0; $streamThreshold = $this->options->getStreamThreshold(); while (($chunk = yield $stream->read()) !== null) { if ($chunk === '') { continue; } if (\strlen($buffer) < $streamThreshold) { $buffer .= $chunk; continue; } if ($compress) { $buffer = $this->compressionContext->compress($buffer, false); } $written += yield $this->write($buffer, $opcode, $rsv, false); $opcode = Opcode::CONT; $rsv = 0; // RSV must be 0 in continuation frames. $buffer = $chunk; } if ($compress) { $buffer = $this->compressionContext->compress($buffer, true); } $written += yield $this->write($buffer, $opcode, $rsv, true); } catch (StreamException $exception) { $code = Code::ABNORMAL_CLOSE; $reason = 'Writing to the client failed'; yield $this->close($code, $reason); throw new ClosedException('Client unexpectedly closed', $code, $reason); } catch (\Throwable $exception) { yield $this->close(Code::UNEXPECTED_SERVER_ERROR, 'Error while reading message data'); throw $exception; } return $written; } private function write(string $data, int $opcode, int $rsv = 0, bool $isFinal = true): Promise { if ($this->metadata->closedAt) { return new Success(0); } $frame = $this->compile($data, $opcode, $rsv, $isFinal); ++$this->metadata->framesSent; $this->metadata->bytesSent += \strlen($frame); $this->metadata->lastSentAt = self::$now; return $this->socket->write($frame); } private function compile(string $data, int $opcode, int $rsv, bool $isFinal): string { $length = \strlen($data); $w = \chr(($isFinal << 7) | ($rsv << 4) | $opcode); $maskFlag = $this->masked ? 0x80 : 0; if ($length > 0xFFFF) { $w .= \chr(0x7F | $maskFlag) . \pack('J', $length); } elseif ($length > 0x7D) { $w .= \chr(0x7E | $maskFlag) . \pack('n', $length); } else { $w .= \chr($length | $maskFlag); } if ($this->masked) { $mask = \random_bytes(4); return $w . $mask . ($data ^ \str_repeat($mask, ($length + 3) >> 2)); } return $w . $data; } public function close(int $code = Code::NORMAL_CLOSE, string $reason = ''): Promise { if ($this->metadata->closedAt) { return new Success(0); } return call(function () use ($code, $reason) { $bytes = 0; try { \assert($code !== Code::NONE || $reason === ''); $promise = $this->write($code !== Code::NONE ? \pack('n', $code) . $reason : '', Opcode::CLOSE); $this->metadata->closedAt = self::$now; $this->metadata->closeCode = $code; $this->metadata->closeReason = $reason; if ($this->currentMessageEmitter) { $emitter = $this->currentMessageEmitter; $this->currentMessageEmitter = null; $emitter->fail(new ClosedException('Connection closed while streaming message body', $code, $reason)); } if ($this->nextMessageDeferred) { $deferred = $this->nextMessageDeferred; $this->nextMessageDeferred = null; $deferred->resolve(); } $bytes = yield $promise; if ($this->closeDeferred !== null) { yield Promise\timeout($this->closeDeferred->promise(), $this->options->getClosePeriod() * 1000); } } catch (\Throwable $exception) { // Failed to write close frame or to receive response frame, but we were disconnecting anyway. } $this->socket->close(); $this->lastWrite = null; $this->lastEmit = null; $onClose = $this->onClose; $this->onClose = null; foreach ($onClose as $callback) { Promise\rethrow(call($callback, $this, $code, $reason)); } unset(self::$clients[$this->metadata->id]); self::$heartbeatTimeouts->remove($this->metadata->id); if (empty(self::$clients)) { Loop::cancel(self::$watcher); self::$watcher = null; self::$heartbeatTimeouts = null; } return $bytes; }); } public function onClose(callable $callback): void { if ($this->onClose === null) { Promise\rethrow(call($callback, $this, $this->metadata->closeCode, $this->metadata->closeReason)); return; } $this->onClose[] = $callback; } /** * A stateful generator websocket frame parser. * * @return \Generator */ private function parser(): \Generator { $frameSizeLimit = $this->options->getFrameSizeLimit(); $messageSizeLimit = $this->options->getMessageSizeLimit(); $textOnly = $this->options->isTextOnly(); $doUtf8Validation = $validateUtf8 = $this->options->isValidateUtf8(); $compressionContext = $this->compressionContext; $compressedFlag = $compressionContext ? $compressionContext->getRsv() : 0; $dataMsgBytesRecd = 0; $savedBuffer = ''; $compressed = false; $buffer = yield; $offset = 0; $bufferSize = \strlen($buffer); while (true) { $payload = ''; // Free memory from last frame payload. while ($bufferSize < 2) { $buffer = \substr($buffer, $offset); $offset = 0; $buffer .= yield; $bufferSize = \strlen($buffer); } $firstByte = \ord($buffer[$offset]); $secondByte = \ord($buffer[$offset + 1]); $offset += 2; $bufferSize -= 2; $final = (bool) ($firstByte & 0b10000000); $rsv = ($firstByte & 0b01110000) >> 4; $opcode = $firstByte & 0b00001111; $isMasked = (bool) ($secondByte & 0b10000000); $maskingKey = null; $frameLength = $secondByte & 0b01111111; if ($opcode >= 3 && $opcode <= 7) { $this->onError(Code::PROTOCOL_ERROR, 'Use of reserved non-control frame opcode'); return; } if ($opcode >= 11 && $opcode <= 15) { $this->onError(Code::PROTOCOL_ERROR, 'Use of reserved control frame opcode'); return; } $isControlFrame = $opcode >= 0x08; if ($isControlFrame || $opcode === Opcode::CONT) { // Control and continuation frames if ($rsv !== 0) { $this->onError(Code::PROTOCOL_ERROR, 'RSV must be 0 for control or continuation frames'); return; } } else { // Text and binary frames if ($rsv !== 0 && (!$compressionContext || $rsv & ~$compressedFlag)) { $this->onError(Code::PROTOCOL_ERROR, 'Invalid RSV value for negotiated extensions'); return; } $doUtf8Validation = $validateUtf8 && $opcode === Opcode::TEXT; $compressed = (bool) ($rsv & $compressedFlag); } if ($frameLength === 0x7E) { while ($bufferSize < 2) { $buffer = \substr($buffer, $offset); $offset = 0; $buffer .= yield; $bufferSize = \strlen($buffer); } $frameLength = \unpack('n', $buffer[$offset] . $buffer[$offset + 1])[1]; $offset += 2; $bufferSize -= 2; } elseif ($frameLength === 0x7F) { while ($bufferSize < 8) { $buffer = \substr($buffer, $offset); $offset = 0; $buffer .= yield; $bufferSize = \strlen($buffer); } $lengthLong32Pair = \unpack('N2', \substr($buffer, $offset, 8)); $offset += 8; $bufferSize -= 8; if (\PHP_INT_MAX === 0x7fffffff) { if ($lengthLong32Pair[1] !== 0 || $lengthLong32Pair[2] < 0) { $this->onError( Code::MESSAGE_TOO_LARGE, 'Received payload exceeds maximum allowable size' ); return; } $frameLength = $lengthLong32Pair[2]; } else { $frameLength = ($lengthLong32Pair[1] << 32) | $lengthLong32Pair[2]; if ($frameLength < 0) { $this->onError( Code::PROTOCOL_ERROR, 'Most significant bit of 64-bit length field set' ); return; } } } if ($frameLength > 0 && $isMasked === $this->masked) { $this->onError( Code::PROTOCOL_ERROR, 'Payload mask error' ); return; } if ($isControlFrame) { if (!$final) { $this->onError( Code::PROTOCOL_ERROR, 'Illegal control frame fragmentation' ); return; } if ($frameLength > 125) { $this->onError( Code::PROTOCOL_ERROR, 'Control frame payload must be of maximum 125 bytes or less' ); return; } } if ($frameSizeLimit && $frameLength > $frameSizeLimit) { $this->onError( Code::MESSAGE_TOO_LARGE, 'Received payload exceeds maximum allowable size' ); return; } if ($messageSizeLimit && ($frameLength + $dataMsgBytesRecd) > $messageSizeLimit) { $this->onError( Code::MESSAGE_TOO_LARGE, 'Received payload exceeds maximum allowable size' ); return; } if ($textOnly && $opcode === Opcode::BIN) { $this->onError( Code::UNACCEPTABLE_TYPE, 'BINARY opcodes (0x02) not accepted' ); return; } if ($isMasked) { while ($bufferSize < 4) { $buffer = \substr($buffer, $offset); $offset = 0; $buffer .= yield; $bufferSize = \strlen($buffer); } $maskingKey = \substr($buffer, $offset, 4); $offset += 4; $bufferSize -= 4; } while ($bufferSize < $frameLength) { $chunk = yield; $buffer .= $chunk; $bufferSize += \strlen($chunk); } $payload = \substr($buffer, $offset, $frameLength); $buffer = \substr($buffer, $offset + $frameLength); $offset = 0; $bufferSize = \strlen($buffer); if ($isMasked) { // This is memory hungry but it's ~70x faster than iterating byte-by-byte // over the masked string. Deal with it; manual iteration is untenable. $payload ^= \str_repeat($maskingKey, ($frameLength + 3) >> 2); } if ($isControlFrame) { $this->onControlFrame($opcode, $payload); continue; } $dataMsgBytesRecd += $frameLength; if ($savedBuffer !== '') { $payload = $savedBuffer . $payload; $savedBuffer = ''; } if ($compressed) { $payload = $compressionContext->decompress($payload, $final); if ($payload === null) { // Decompression failed. $this->onError( Code::PROTOCOL_ERROR, 'Invalid compressed data' ); return; } } if ($doUtf8Validation) { if ($final) { $valid = \preg_match('//u', $payload); } else { for ($i = 0; !($valid = \preg_match('//u', $payload)); $i++) { $savedBuffer = \substr($payload, -1) . $savedBuffer; $payload = \substr($payload, 0, -1); if ($i === 3) { // Remove a maximum of three bytes break; } } } if (!$valid) { $this->onError( Code::INCONSISTENT_FRAME_DATA_TYPE, 'Invalid TEXT data; UTF-8 required' ); return; } } if ($final) { $dataMsgBytesRecd = 0; } $this->onData($opcode, $payload, $final); } } } <?php /** @noinspection PhpComposerExtensionStubsInspection */ namespace Amp\Websocket; final class Rfc7692Compression implements CompressionContext { public const DEFAULT_WINDOW_SIZE = 15; private const RSV = 0b100; private const MINIMUM_LENGTH = 860; private const EMPTY_BLOCK = "\x0\x0\xff\xff"; /** * Create a compression context from a header received from a websocket client request. * * @param string $headerIn Header from request. * @param string $headerOut Sec-Websocket-Extension response header. * * @return self|null */ public static function fromClientHeader(string $headerIn, ?string &$headerOut): ?self { return self::fromHeader(true, $headerIn, $headerOut); } /** * Create a compression context from a header received from a websocket server response. * * @param string $header Header from response. * * @return self|null */ public static function fromServerHeader(string $header): ?self { return self::fromHeader(false, $header); } /** * @return string Header value for Sec-Websocket-Extension header. */ public static function createRequestHeader(): string { return 'permessage-deflate; server_no_context_takeover; client_no_context_takeover'; } /** * @param bool $isServer True if creating a server context, false if creating a client context. * @param string $headerIn Header from request. * @param string $headerOut Sec-Websocket-Extension response header. * * @return self|null */ private static function fromHeader(bool $isServer, string $headerIn, ?string &$headerOut = null): ?self { $headerIn = \explode(';', \strtolower($headerIn)); $headerIn = \array_map('trim', $headerIn); if (!\in_array('permessage-deflate', $headerIn, true)) { return null; } $serverWindowSize = self::DEFAULT_WINDOW_SIZE; $clientWindowSize = self::DEFAULT_WINDOW_SIZE; $serverContextTakeover = true; $clientContextTakeover = true; $headers = []; $headerOut = 'permessage-deflate'; foreach ($headerIn as $param) { $parts = \explode('=', $param, 2); if (\in_array($parts[0], $headers, true)) { return null; // Repeat params in header. } $headers[] = $parts[0]; switch ($parts[0]) { case 'permessage-deflate': break; case 'client_max_window_bits': if (isset($parts[1])) { $value = (int) $parts[1]; if ($value < 8 || $value > 15) { return null; // Invalid option value. } $clientWindowSize = $value; } $headerOut .= '; client_max_window_bits=' . $clientWindowSize; break; case 'client_no_context_takeover': $clientContextTakeover = false; $headerOut .= '; client_no_context_takeover'; break; case 'server_max_window_bits': if (isset($parts[1])) { $value = (int) $parts[1]; if ($value < 8 || $value > 15) { return null; // Invalid option value. } $serverWindowSize = $value; } $headerOut .= '; server_max_window_bits=' . $serverWindowSize; break; case 'server_no_context_takeover': $serverContextTakeover = false; $headerOut .= '; server_no_context_takeover'; break; default: return null; // Unrecognized option; do not accept extension request. } } if ($isServer) { return new self($clientWindowSize, $serverWindowSize, $clientContextTakeover, $serverContextTakeover); } return new self($serverWindowSize, $clientWindowSize, $serverContextTakeover, $clientContextTakeover); } /** @var resource */ private $deflate; /** @var resource */ private $inflate; /** @var bool */ private $sendingFlushMode; /** @var bool */ private $receivingFlushMode; private function __construct( int $receivingWindowSize, int $sendingWindowSize, bool $receivingContextTakeover, bool $sendingContextTakeover ) { $this->receivingFlushMode = $receivingContextTakeover ? \ZLIB_SYNC_FLUSH : \ZLIB_FULL_FLUSH; $this->sendingFlushMode = $sendingContextTakeover ? \ZLIB_SYNC_FLUSH : \ZLIB_FULL_FLUSH; if (($this->inflate = \inflate_init(\ZLIB_ENCODING_RAW, ['window' => $receivingWindowSize])) === false) { throw new \RuntimeException('Failed initializing inflate context'); } if (($this->deflate = \deflate_init(\ZLIB_ENCODING_RAW, ['window' => $sendingWindowSize])) === false) { throw new \RuntimeException('Failed initializing deflate context'); } } public function getRsv(): int { return self::RSV; } public function getCompressionThreshold(): int { return self::MINIMUM_LENGTH; } public function decompress(string $data, bool $isFinal): ?string { if ($isFinal) { $data .= self::EMPTY_BLOCK; } $data = \inflate_add($this->inflate, $data, $this->receivingFlushMode); if (false === $data) { return null; } return $data; } public function compress(string $data, bool $isFinal): string { $data = \deflate_add($this->deflate, $data, $this->sendingFlushMode); if ($data === false) { throw new \RuntimeException('Failed to compress data'); } if ($isFinal && \substr($data, -4) === self::EMPTY_BLOCK) { $data = \substr($data, 0, -4); } return $data; } } { "name": "amphp/process", "homepage": "https://github.com/amphp/process", "description": "Asynchronous process manager.", "require": { "php": ">=7", "amphp/amp": "^2", "amphp/byte-stream": "^1.4" }, "require-dev": { "phpunit/phpunit": "^6", "amphp/phpunit-util": "^1", "amphp/php-cs-fixer-config": "dev-master" }, "license": "MIT", "authors": [ { "name": "Bob Weinand", "email": "bobwei9@hotmail.com" }, { "name": "Aaron Piotrowski", "email": "aaron@trowski.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "autoload": { "psr-4": { "Amp\\Process\\": "lib" }, "files": ["lib/functions.php"] }, "autoload-dev": { "psr-4": { "Amp\\Process\\Test\\": "test" } }, "config": { "platform": { "php": "7.0.0" } }, "scripts": { "check": [ "@cs", "@test" ], "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff --dry-run", "cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix -v --diff", "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text" } } <?php namespace Amp\Process\Internal; use Amp\Process\ProcessException; use Amp\Promise; interface ProcessRunner { /** * Start a process using the supplied parameters. * * @param string $command The command to execute. * @param string|null $cwd The working directory for the child process. * @param array $env Environment variables to pass to the child process. * @param array $options `proc_open()` options. * * @return ProcessHandle * * @throws ProcessException If starting the process fails. */ public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle; /** * Wait for the child process to end. * * @param ProcessHandle $handle The process descriptor. * * @return Promise <int> Succeeds with exit code of the process or fails if the process is killed. */ public function join(ProcessHandle $handle): Promise; /** * Forcibly end the child process. * * @param ProcessHandle $handle The process descriptor. * * @throws ProcessException If terminating the process fails. */ public function kill(ProcessHandle $handle); /** * Send a signal signal to the child process. * * @param ProcessHandle $handle The process descriptor. * @param int $signo Signal number to send to process. * * @throws ProcessException If sending the signal fails. */ public function signal(ProcessHandle $handle, int $signo); /** * Release all resources held by the process handle. * * @param ProcessHandle $handle The process descriptor. */ public function destroy(ProcessHandle $handle); } <?php namespace Amp\Process\Internal\Posix; use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\Deferred; use Amp\Loop; use Amp\Process\Internal\ProcessHandle; use Amp\Process\Internal\ProcessRunner; use Amp\Process\Internal\ProcessStatus; use Amp\Process\ProcessException; use Amp\Process\ProcessInputStream; use Amp\Process\ProcessOutputStream; use Amp\Promise; /** @internal */ final class Runner implements ProcessRunner { const FD_SPEC = [ ["pipe", "r"], // stdin ["pipe", "w"], // stdout ["pipe", "w"], // stderr ["pipe", "w"], // exit code pipe ]; /** @var string|null */ private static $fdPath; public static function onProcessEndExtraDataPipeReadable($watcher, $stream, Handle $handle) { Loop::cancel($watcher); $handle->extraDataPipeWatcher = null; $handle->status = ProcessStatus::ENDED; if (!\is_resource($stream) || \feof($stream)) { $handle->joinDeferred->fail(new ProcessException("Process ended unexpectedly")); } else { $handle->joinDeferred->resolve((int) \rtrim(@\stream_get_contents($stream))); } } public static function onProcessStartExtraDataPipeReadable($watcher, $stream, $data) { Loop::cancel($watcher); $pid = \rtrim(@\fgets($stream)); /** @var $deferreds Deferred[] */ list($handle, $pipes, $deferreds) = $data; if (!$pid || !\is_numeric($pid)) { $error = new ProcessException("Could not determine PID"); $handle->pidDeferred->fail($error); foreach ($deferreds as $deferred) { /** @var $deferred Deferred */ $deferred->fail($error); } if ($handle->status < ProcessStatus::ENDED) { $handle->status = ProcessStatus::ENDED; $handle->joinDeferred->fail($error); } return; } $handle->status = ProcessStatus::RUNNING; $handle->pidDeferred->resolve((int) $pid); $deferreds[0]->resolve($pipes[0]); $deferreds[1]->resolve($pipes[1]); $deferreds[2]->resolve($pipes[2]); if ($handle->extraDataPipeWatcher !== null) { Loop::enable($handle->extraDataPipeWatcher); } } /** @inheritdoc */ public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle { $command = \sprintf( '{ (%s) <&3 3<&- 3>/dev/null & } 3<&0; trap "" INT TERM QUIT HUP;' . 'pid=$!; echo $pid >&3; wait $pid; RC=$?; echo $RC >&3; exit $RC', $command ); $handle = new Handle; $handle->proc = @\proc_open($command, $this->generateFds(), $pipes, $cwd ?: null, $env ?: null, $options); if (!\is_resource($handle->proc)) { $message = "Could not start process"; if ($error = \error_get_last()) { $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); } throw new ProcessException($message); } $status = \proc_get_status($handle->proc); if (!$status) { \proc_close($handle->proc); throw new ProcessException("Could not get process status"); } $stdinDeferred = new Deferred; $handle->stdin = new ProcessOutputStream($stdinDeferred->promise()); $stdoutDeferred = new Deferred; $handle->stdout = new ProcessInputStream($stdoutDeferred->promise()); $stderrDeferred = new Deferred; $handle->stderr = new ProcessInputStream($stderrDeferred->promise()); $handle->extraDataPipe = $pipes[3]; \stream_set_blocking($pipes[3], false); $handle->extraDataPipeStartWatcher = Loop::onReadable($pipes[3], [self::class, 'onProcessStartExtraDataPipeReadable'], [$handle, [ new ResourceOutputStream($pipes[0]), new ResourceInputStream($pipes[1]), new ResourceInputStream($pipes[2]), ], [ $stdinDeferred, $stdoutDeferred, $stderrDeferred ]]); $handle->extraDataPipeWatcher = Loop::onReadable($pipes[3], [self::class, 'onProcessEndExtraDataPipeReadable'], $handle); Loop::unreference($handle->extraDataPipeWatcher); Loop::disable($handle->extraDataPipeWatcher); return $handle; } private function generateFds(): array { if (self::$fdPath === null) { self::$fdPath = \file_exists("/dev/fd") ? "/dev/fd" : "/proc/self/fd"; } $fdList = @\scandir(self::$fdPath, \SCANDIR_SORT_NONE); if ($fdList === false) { throw new ProcessException("Unable to list open file descriptors"); } $fdList = \array_filter($fdList, function (string $path): bool { return $path !== "." && $path !== ".."; }); $fds = []; foreach ($fdList as $id) { $fds[(int) $id] = ["file", "/dev/null", "r"]; } return self::FD_SPEC + $fds; } /** @inheritdoc */ public function join(ProcessHandle $handle): Promise { /** @var Handle $handle */ if ($handle->extraDataPipeWatcher !== null) { Loop::reference($handle->extraDataPipeWatcher); } return $handle->joinDeferred->promise(); } /** @inheritdoc */ public function kill(ProcessHandle $handle) { /** @var Handle $handle */ if ($handle->extraDataPipeWatcher !== null) { Loop::cancel($handle->extraDataPipeWatcher); $handle->extraDataPipeWatcher = null; } /** @var Handle $handle */ if ($handle->extraDataPipeStartWatcher !== null) { Loop::cancel($handle->extraDataPipeStartWatcher); $handle->extraDataPipeStartWatcher = null; } if (!\proc_terminate($handle->proc, 9)) { // Forcefully kill the process using SIGKILL. throw new ProcessException("Terminating process failed"); } $handle->pidDeferred->promise()->onResolve(function ($error, $pid) { // The function should not call posix_kill() if $pid is null (i.e., there was an error starting the process). if ($error) { return; } // ignore errors because process not always detached @\posix_kill($pid, 9); }); if ($handle->status < ProcessStatus::ENDED) { $handle->status = ProcessStatus::ENDED; $handle->joinDeferred->fail(new ProcessException("The process was killed")); } $this->free($handle); } /** @inheritdoc */ public function signal(ProcessHandle $handle, int $signo) { $handle->pidDeferred->promise()->onResolve(function ($error, $pid) use ($signo) { if ($error) { return; } @\posix_kill($pid, $signo); }); } /** @inheritdoc */ public function destroy(ProcessHandle $handle) { /** @var Handle $handle */ if ($handle->status < ProcessStatus::ENDED && \getmypid() === $handle->originalParentPid) { try { $this->kill($handle); return; } catch (ProcessException $e) { // ignore } } $this->free($handle); } private function free(Handle $handle) { /** @var Handle $handle */ if ($handle->extraDataPipeWatcher !== null) { Loop::cancel($handle->extraDataPipeWatcher); $handle->extraDataPipeWatcher = null; } /** @var Handle $handle */ if ($handle->extraDataPipeStartWatcher !== null) { Loop::cancel($handle->extraDataPipeStartWatcher); $handle->extraDataPipeStartWatcher = null; } if (\is_resource($handle->extraDataPipe)) { \fclose($handle->extraDataPipe); } $handle->stdin->close(); $handle->stdout->close(); $handle->stderr->close(); if (\is_resource($handle->proc)) { \proc_close($handle->proc); } } } <?php namespace Amp\Process\Internal\Posix; use Amp\Deferred; use Amp\Process\Internal\ProcessHandle; /** @internal */ final class Handle extends ProcessHandle { public function __construct() { $this->pidDeferred = new Deferred; $this->joinDeferred = new Deferred; $this->originalParentPid = \getmypid(); } /** @var Deferred */ public $joinDeferred; /** @var resource */ public $proc; /** @var resource */ public $extraDataPipe; /** @var string */ public $extraDataPipeWatcher; /** @var string */ public $extraDataPipeStartWatcher; /** @var int */ public $originalParentPid; } <?php namespace Amp\Process\Internal\Windows; use Amp\Deferred; use Amp\Loop; use Amp\Process\Internal\ProcessHandle; use Amp\Process\Internal\ProcessRunner; use Amp\Process\Internal\ProcessStatus; use Amp\Process\ProcessException; use Amp\Process\ProcessInputStream; use Amp\Process\ProcessOutputStream; use Amp\Promise; use const Amp\Process\BIN_DIR; /** * @internal * @codeCoverageIgnore Windows only. */ final class Runner implements ProcessRunner { const FD_SPEC = [ ["pipe", "r"], // stdin ["pipe", "w"], // stdout ["pipe", "w"], // stderr ["pipe", "w"], // exit code pipe ]; const WRAPPER_EXE_PATH = PHP_INT_SIZE === 8 ? BIN_DIR . '\\windows\\ProcessWrapper64.exe' : BIN_DIR . '\\windows\\ProcessWrapper.exe'; private static $pharWrapperPath; private $socketConnector; private function makeCommand(string $workingDirectory): string { $wrapperPath = self::WRAPPER_EXE_PATH; // We can't execute the exe from within the PHAR, so copy it out... if (\strncmp($wrapperPath, "phar://", 7) === 0) { if (self::$pharWrapperPath === null) { self::$pharWrapperPath = \tempnam(\sys_get_temp_dir(), "amphp-process-wrapper-"); \copy(self::WRAPPER_EXE_PATH, self::$pharWrapperPath); \register_shutdown_function(static function () { @\unlink(self::$pharWrapperPath); }); } $wrapperPath = self::$pharWrapperPath; } $result = \sprintf( '%s --address=%s --port=%d --token-size=%d', \escapeshellarg($wrapperPath), $this->socketConnector->address, $this->socketConnector->port, SocketConnector::SECURITY_TOKEN_SIZE ); if ($workingDirectory !== '') { $result .= ' ' . \escapeshellarg('--cwd=' . \rtrim($workingDirectory, '\\')); } return $result; } public function __construct() { $this->socketConnector = new SocketConnector; } /** @inheritdoc */ public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle { if (\strpos($command, "\0") !== false) { throw new ProcessException("Can't execute commands that contain null bytes."); } $options['bypass_shell'] = true; $handle = new Handle; $handle->proc = @\proc_open($this->makeCommand($cwd ?? ''), self::FD_SPEC, $pipes, $cwd ?: null, $env ?: null, $options); if (!\is_resource($handle->proc)) { $message = "Could not start process"; if ($error = \error_get_last()) { $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); } throw new ProcessException($message); } $status = \proc_get_status($handle->proc); if (!$status) { \proc_close($handle->proc); throw new ProcessException("Could not get process status"); } $securityTokens = \random_bytes(SocketConnector::SECURITY_TOKEN_SIZE * 6); $written = \fwrite($pipes[0], $securityTokens . "\0" . $command . "\0"); \fclose($pipes[0]); \fclose($pipes[1]); if ($written !== SocketConnector::SECURITY_TOKEN_SIZE * 6 + \strlen($command) + 2) { \fclose($pipes[2]); \proc_close($handle->proc); throw new ProcessException("Could not send security tokens / command to process wrapper"); } $handle->securityTokens = \str_split($securityTokens, SocketConnector::SECURITY_TOKEN_SIZE); $handle->wrapperPid = $status['pid']; $handle->wrapperStderrPipe = $pipes[2]; $stdinDeferred = new Deferred; $handle->stdioDeferreds[] = $stdinDeferred; $handle->stdin = new ProcessOutputStream($stdinDeferred->promise()); $stdoutDeferred = new Deferred; $handle->stdioDeferreds[] = $stdoutDeferred; $handle->stdout = new ProcessInputStream($stdoutDeferred->promise()); $stderrDeferred = new Deferred; $handle->stdioDeferreds[] = $stderrDeferred; $handle->stderr = new ProcessInputStream($stderrDeferred->promise()); $this->socketConnector->registerPendingProcess($handle); return $handle; } /** @inheritdoc */ public function join(ProcessHandle $handle): Promise { /** @var Handle $handle */ $handle->exitCodeRequested = true; if ($handle->exitCodeWatcher !== null) { Loop::reference($handle->exitCodeWatcher); } return $handle->joinDeferred->promise(); } /** @inheritdoc */ public function kill(ProcessHandle $handle) { /** @var Handle $handle */ // todo: send a signal to the wrapper to kill the child instead? if (!\proc_terminate($handle->proc)) { throw new ProcessException("Terminating process failed"); } $failStart = false; if ($handle->childPidWatcher !== null) { Loop::cancel($handle->childPidWatcher); $handle->childPidWatcher = null; $handle->pidDeferred->fail(new ProcessException("The process was killed")); $failStart = true; } if ($handle->exitCodeWatcher !== null) { Loop::cancel($handle->exitCodeWatcher); $handle->exitCodeWatcher = null; $handle->joinDeferred->fail(new ProcessException("The process was killed")); } $handle->status = ProcessStatus::ENDED; if ($failStart || $handle->stdioDeferreds) { $this->socketConnector->failHandleStart($handle, "The process was killed"); } $this->free($handle); } /** @inheritdoc */ public function signal(ProcessHandle $handle, int $signo) { throw new ProcessException('Signals are not supported on Windows'); } /** @inheritdoc */ public function destroy(ProcessHandle $handle) { /** @var Handle $handle */ if ($handle->status < ProcessStatus::ENDED && \is_resource($handle->proc)) { try { $this->kill($handle); return; } catch (ProcessException $e) { // ignore } } $this->free($handle); } private function free(Handle $handle) { if ($handle->childPidWatcher !== null) { Loop::cancel($handle->childPidWatcher); $handle->childPidWatcher = null; } if ($handle->exitCodeWatcher !== null) { Loop::cancel($handle->exitCodeWatcher); $handle->exitCodeWatcher = null; } $handle->stdin->close(); $handle->stdout->close(); $handle->stderr->close(); foreach ($handle->sockets as $socket) { @\fclose($socket); } @\fclose($handle->wrapperStderrPipe); if (\is_resource($handle->proc)) { \proc_close($handle->proc); } } } <?php namespace Amp\Process\Internal\Windows; use Amp\Struct; /** * @internal * @codeCoverageIgnore Windows only. */ final class PendingSocketClient { use Struct; public $readWatcher; public $timeoutWatcher; public $receivedDataBuffer = ''; public $pid; public $streamId; } <?php namespace Amp\Process\Internal\Windows; use Amp\Deferred; use Amp\Process\Internal\ProcessHandle; /** * @internal * @codeCoverageIgnore Windows only. */ final class Handle extends ProcessHandle { public function __construct() { $this->joinDeferred = new Deferred; $this->pidDeferred = new Deferred; } /** @var Deferred */ public $joinDeferred; /** @var string */ public $exitCodeWatcher; /** @var bool */ public $exitCodeRequested = false; /** @var resource */ public $proc; /** @var int */ public $wrapperPid; /** @var resource */ public $wrapperStderrPipe; /** @var resource[] */ public $sockets = []; /** @var Deferred[] */ public $stdioDeferreds; /** @var string */ public $childPidWatcher; /** @var string */ public $connectTimeoutWatcher; /** @var string[] */ public $securityTokens; } <?php namespace Amp\Process\Internal\Windows; /** * @internal * @codeCoverageIgnore Windows only. */ final class HandshakeStatus { const SUCCESS = 0; const SIGNAL_UNEXPECTED = 0x01; const INVALID_STREAM_ID = 0x02; const INVALID_PROCESS_ID = 0x03; const DUPLICATE_STREAM_ID = 0x04; const INVALID_CLIENT_TOKEN = 0x05; private function __construct() { // empty to prevent instances of this class } } <?php namespace Amp\Process\Internal\Windows; /** * @internal * @codeCoverageIgnore Windows only. */ final class SignalCode { const HANDSHAKE = 0x01; const HANDSHAKE_ACK = 0x02; const CHILD_PID = 0x03; const EXIT_CODE = 0x04; private function __construct() { // empty to prevent instances of this class } } <?php namespace Amp\Process\Internal\Windows; use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\Loop; use Amp\Process\Internal\ProcessStatus; use Amp\Process\ProcessException; /** * @internal * @codeCoverageIgnore Windows only. */ final class SocketConnector { const SERVER_SOCKET_URI = 'tcp://127.0.0.1:0'; const SECURITY_TOKEN_SIZE = 16; const CONNECT_TIMEOUT = 1000; /** @var resource */ private $server; /** @var PendingSocketClient[] */ private $pendingClients = []; /** @var Handle[] */ private $pendingProcesses = []; /** @var string */ public $address; /** @var int */ public $port; public function __construct() { $flags = \STREAM_SERVER_LISTEN | \STREAM_SERVER_BIND; $this->server = \stream_socket_server(self::SERVER_SOCKET_URI, $errNo, $errStr, $flags); if (!$this->server) { throw new \Error("Failed to create TCP server socket for process wrapper: {$errNo}: {$errStr}"); } if (!\stream_set_blocking($this->server, false)) { throw new \Error("Failed to set server socket to non-blocking mode"); } list($this->address, $this->port) = \explode(':', \stream_socket_get_name($this->server, false)); $this->port = (int) $this->port; Loop::unreference(Loop::onReadable($this->server, [$this, 'onServerSocketReadable'])); } private function failClientHandshake($socket, int $code) { \fwrite($socket, \chr(SignalCode::HANDSHAKE_ACK) . \chr($code)); \fclose($socket); unset($this->pendingClients[(int) $socket]); } public function failHandleStart(Handle $handle, string $message,...$args) { Loop::cancel($handle->connectTimeoutWatcher); unset($this->pendingProcesses[$handle->wrapperPid]); foreach ($handle->sockets as $socket) { \fclose($socket); } $error = new ProcessException(\vsprintf($message, $args)); $deferreds = $handle->stdioDeferreds; $deferreds[] = $handle->joinDeferred; $handle->stdioDeferreds = []; foreach ($deferreds as $deferred) { $deferred->fail($error); } } /** * Read data from a client socket. * * This method cleans up internal state as appropriate. Returns null if the read fails or needs to be repeated. * * @param resource $socket * @param int $length * @param PendingSocketClient $state * * @return string|null */ private function readDataFromPendingClient($socket, int $length, PendingSocketClient $state) { $data = \fread($socket, $length); if ($data === false || $data === '') { return null; } $data = $state->receivedDataBuffer . $data; if (\strlen($data) < $length) { $state->receivedDataBuffer = $data; return null; } $state->receivedDataBuffer = ''; Loop::cancel($state->readWatcher); return $data; } public function onReadableHandshake($watcher, $socket) { $socketId = (int) $socket; $pendingClient = $this->pendingClients[$socketId]; if (null === $data = $this->readDataFromPendingClient($socket, self::SECURITY_TOKEN_SIZE + 6, $pendingClient)) { return; } $packet = \unpack('Csignal/Npid/Cstream_id/a*client_token', $data); // validate the client's handshake if ($packet['signal'] !== SignalCode::HANDSHAKE) { $this->failClientHandshake($socket, HandshakeStatus::SIGNAL_UNEXPECTED); return; } if ($packet['stream_id'] > 2) { $this->failClientHandshake($socket, HandshakeStatus::INVALID_STREAM_ID); return; } if (!isset($this->pendingProcesses[$packet['pid']])) { $this->failClientHandshake($socket, HandshakeStatus::INVALID_PROCESS_ID); return; } $handle = $this->pendingProcesses[$packet['pid']]; if (isset($handle->sockets[$packet['stream_id']])) { $this->failClientHandshake($socket, HandshakeStatus::DUPLICATE_STREAM_ID); \trigger_error(\sprintf( "%s: Received duplicate socket for process #%s stream #%d", self::class, $handle->pid, $packet['stream_id'] ), E_USER_WARNING); return; } if (!\hash_equals($packet['client_token'], $handle->securityTokens[$packet['stream_id']])) { $this->failClientHandshake($socket, HandshakeStatus::INVALID_CLIENT_TOKEN); $this->failHandleStart($handle, "Invalid client security token for stream #%d", $packet['stream_id']); return; } $ackData = \chr(SignalCode::HANDSHAKE_ACK) . \chr(HandshakeStatus::SUCCESS) . $handle->securityTokens[$packet['stream_id'] + 3]; // Unless we set the security token size so high that it won't fit in the // buffer, this probably shouldn't ever happen unless something has gone wrong if (\fwrite($socket, $ackData) !== self::SECURITY_TOKEN_SIZE + 2) { unset($this->pendingClients[$socketId]); return; } $pendingClient->pid = $packet['pid']; $pendingClient->streamId = $packet['stream_id']; $pendingClient->readWatcher = Loop::onReadable($socket, [$this, 'onReadableHandshakeAck']); } public function onReadableHandshakeAck($watcher, $socket) { $socketId = (int) $socket; $pendingClient = $this->pendingClients[$socketId]; // can happen if the start promise was failed if (!isset($this->pendingProcesses[$pendingClient->pid]) || $this->pendingProcesses[$pendingClient->pid]->status === ProcessStatus::ENDED) { \fclose($socket); Loop::cancel($watcher); Loop::cancel($pendingClient->timeoutWatcher); unset($this->pendingClients[$socketId]); return; } if (null === $data = $this->readDataFromPendingClient($socket, 2, $pendingClient)) { return; } Loop::cancel($pendingClient->timeoutWatcher); unset($this->pendingClients[$socketId]); $handle = $this->pendingProcesses[$pendingClient->pid]; $packet = \unpack('Csignal/Cstatus', $data); if ($packet['signal'] !== SignalCode::HANDSHAKE_ACK || $packet['status'] !== HandshakeStatus::SUCCESS) { $this->failHandleStart( $handle, "Client rejected handshake with code %d for stream #%d", $packet['status'], $pendingClient->streamId ); return; } $handle->sockets[$pendingClient->streamId] = $socket; if (\count($handle->sockets) === 3) { $handle->childPidWatcher = Loop::onReadable($handle->sockets[0], [$this, 'onReadableChildPid'], $handle); $deferreds = $handle->stdioDeferreds; $handle->stdioDeferreds = []; // clear, so there's no double resolution if process spawn fails $deferreds[0]->resolve(new ResourceOutputStream($handle->sockets[0])); $deferreds[1]->resolve(new ResourceInputStream($handle->sockets[1])); $deferreds[2]->resolve(new ResourceInputStream($handle->sockets[2])); } } public function onReadableChildPid($watcher, $socket, Handle $handle) { $data = \fread($socket, 5); if ($data === false || $data === '') { return; } Loop::cancel($handle->childPidWatcher); Loop::cancel($handle->connectTimeoutWatcher); $handle->childPidWatcher = null; if (\strlen($data) !== 5) { $this->failHandleStart( $handle, 'Failed to read PID from wrapper: Received %d of 5 expected bytes', \strlen($data) ); return; } $packet = \unpack('Csignal/Npid', $data); if ($packet['signal'] !== SignalCode::CHILD_PID) { $this->failHandleStart( $handle, "Failed to read PID from wrapper: Unexpected signal code %d", $packet['signal'] ); return; } // Required, because a process might be destroyed while starting if ($handle->status === ProcessStatus::STARTING) { $handle->status = ProcessStatus::RUNNING; $handle->exitCodeWatcher = Loop::onReadable($handle->sockets[0], [$this, 'onReadableExitCode'], $handle); if (!$handle->exitCodeRequested) { Loop::unreference($handle->exitCodeWatcher); } } $handle->pidDeferred->resolve($packet['pid']); unset($this->pendingProcesses[$handle->wrapperPid]); } public function onReadableExitCode($watcher, $socket, Handle $handle) { $data = \fread($socket, 5); if ($data === false || $data === '') { return; } Loop::cancel($handle->exitCodeWatcher); $handle->exitCodeWatcher = null; if (\strlen($data) !== 5) { $handle->status = ProcessStatus::ENDED; $handle->joinDeferred->fail(new ProcessException( \sprintf('Failed to read exit code from wrapper: Received %d of 5 expected bytes', \strlen($data)) )); return; } $packet = \unpack('Csignal/Ncode', $data); if ($packet['signal'] !== SignalCode::EXIT_CODE) { $this->failHandleStart( $handle, "Failed to read exit code from wrapper: Unexpected signal code %d", $packet['signal'] ); return; } $handle->status = ProcessStatus::ENDED; $handle->joinDeferred->resolve($packet['code']); $handle->stdin->close(); $handle->stdout->close(); $handle->stderr->close(); // Explicitly \fclose() sockets, as resource streams shut only one side down. foreach ($handle->sockets as $sock) { @\fclose($sock); } } public function onClientSocketConnectTimeout($watcher, $socket) { $id = (int) $socket; Loop::cancel($this->pendingClients[$id]->readWatcher); unset($this->pendingClients[$id]); \fclose($socket); } public function onServerSocketReadable() { $socket = \stream_socket_accept($this->server); if (!\stream_set_blocking($socket, false)) { throw new \Error("Failed to set client socket to non-blocking mode"); } $pendingClient = new PendingSocketClient; $pendingClient->readWatcher = Loop::onReadable($socket, [$this, 'onReadableHandshake']); $pendingClient->timeoutWatcher = Loop::delay(self::CONNECT_TIMEOUT, [$this, 'onClientSocketConnectTimeout'], $socket); $this->pendingClients[(int) $socket] = $pendingClient; } public function onProcessConnectTimeout($watcher, Handle $handle) { $running = \is_resource($handle->proc) && \proc_get_status($handle->proc)['running']; $error = null; if (!$running) { $error = \stream_get_contents($handle->wrapperStderrPipe); } $error = $error ?: 'Process did not connect to server before timeout elapsed'; foreach ($handle->sockets as $socket) { \fclose($socket); } $error = new ProcessException(\trim($error)); foreach ($handle->stdioDeferreds as $deferred) { $deferred->fail($error); } \fclose($handle->wrapperStderrPipe); \proc_close($handle->proc); $handle->joinDeferred->fail($error); } public function registerPendingProcess(Handle $handle) { // Use Loop::defer() to start the timeout only after the loop has ticked once. This prevents issues with many // things started at once, see https://github.com/amphp/process/issues/21. $handle->connectTimeoutWatcher = Loop::defer(function () use ($handle) { $handle->connectTimeoutWatcher = Loop::delay( self::CONNECT_TIMEOUT, [$this, 'onProcessConnectTimeout'], $handle ); }); $this->pendingProcesses[$handle->wrapperPid] = $handle; } } <?php namespace Amp\Process\Internal; use Amp\Deferred; use Amp\Process\ProcessInputStream; use Amp\Process\ProcessOutputStream; use Amp\Struct; abstract class ProcessHandle { use Struct; /** @var ProcessOutputStream */ public $stdin; /** @var ProcessInputStream */ public $stdout; /** @var ProcessInputStream */ public $stderr; /** @var Deferred */ public $pidDeferred; /** @var int */ public $status = ProcessStatus::STARTING; } <?php namespace Amp\Process\Internal; final class ProcessStatus { const STARTING = 0; const RUNNING = 1; const ENDED = 2; private function __construct() { // empty to prevent instances of this class } } <?php namespace Amp\Process; const BIN_DIR = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'bin'; const IS_WINDOWS = (PHP_OS & "\xDF\xDF\xDF") === 'WIN'; if (IS_WINDOWS) { /** * Escapes the command argument for safe inclusion into a Windows command string. * * @param string $arg * * @return string */ function escapeArguments(string $arg): string { return '"' . \preg_replace_callback('(\\\\*("|$))', function (array $m): string { return \str_repeat('\\', \strlen($m[0])) . $m[0]; }, $arg) . '"'; } } else { /** * Escapes the command argument for safe inclusion into a Posix shell command string. * * @param string $arg * * @return string */ function escapeArguments(string $arg): string { return \escapeshellarg($arg); } } <?php namespace Amp\Process; use Amp\ByteStream\ClosedException; use Amp\ByteStream\OutputStream; use Amp\ByteStream\ResourceOutputStream; use Amp\ByteStream\StreamException; use Amp\Deferred; use Amp\Failure; use Amp\Promise; final class ProcessOutputStream implements OutputStream { /** @var \SplQueue */ private $queuedWrites; /** @var bool */ private $shouldClose = false; /** @var ResourceOutputStream */ private $resourceStream; /** @var StreamException|null */ private $error; public function __construct(Promise $resourceStreamPromise) { $this->queuedWrites = new \SplQueue; $resourceStreamPromise->onResolve(function ($error, $resourceStream) { if ($error) { $this->error = new StreamException("Failed to launch process", 0, $error); while (!$this->queuedWrites->isEmpty()) { list(, $deferred) = $this->queuedWrites->shift(); $deferred->fail($this->error); } return; } while (!$this->queuedWrites->isEmpty()) { /** * @var string $data * @var \Amp\Deferred $deferred */ list($data, $deferred) = $this->queuedWrites->shift(); $deferred->resolve($resourceStream->write($data)); } $this->resourceStream = $resourceStream; if ($this->shouldClose) { $this->resourceStream->close(); } }); } /** @inheritdoc */ public function write(string $data): Promise { if ($this->resourceStream) { return $this->resourceStream->write($data); } if ($this->error) { return new Failure($this->error); } if ($this->shouldClose) { throw new ClosedException("Stream has already been closed."); } $deferred = new Deferred; $this->queuedWrites->push([$data, $deferred]); return $deferred->promise(); } /** @inheritdoc */ public function end(string $finalData = ""): Promise { if ($this->resourceStream) { return $this->resourceStream->end($finalData); } if ($this->error) { return new Failure($this->error); } if ($this->shouldClose) { throw new ClosedException("Stream has already been closed."); } $deferred = new Deferred; $this->queuedWrites->push([$finalData, $deferred]); $this->shouldClose = true; return $deferred->promise(); } public function close() { $this->shouldClose = true; if ($this->resourceStream) { $this->resourceStream->close(); } elseif (!$this->queuedWrites->isEmpty()) { $error = new ClosedException("Stream closed."); do { list(, $deferred) = $this->queuedWrites->shift(); $deferred->fail($error); } while (!$this->queuedWrites->isEmpty()); } } } <?php namespace Amp\Process; use Amp\ByteStream\InputStream; use Amp\ByteStream\PendingReadError; use Amp\ByteStream\ResourceInputStream; use Amp\ByteStream\StreamException; use Amp\Deferred; use Amp\Failure; use Amp\Promise; use Amp\Success; final class ProcessInputStream implements InputStream { /** @var Deferred */ private $initialRead; /** @var bool */ private $shouldClose = false; /** @var bool */ private $referenced = true; /** @var ResourceInputStream */ private $resourceStream; /** @var StreamException|null */ private $error; public function __construct(Promise $resourceStreamPromise) { $resourceStreamPromise->onResolve(function ($error, $resourceStream) { if ($error) { $this->error = new StreamException("Failed to launch process", 0, $error); if ($this->initialRead) { $initialRead = $this->initialRead; $this->initialRead = null; $initialRead->fail($this->error); } return; } $this->resourceStream = $resourceStream; if (!$this->referenced) { $this->resourceStream->unreference(); } if ($this->shouldClose) { $this->resourceStream->close(); } if ($this->initialRead) { $initialRead = $this->initialRead; $this->initialRead = null; $initialRead->resolve($this->shouldClose ? null : $this->resourceStream->read()); } }); } /** * Reads data from the stream. * * @return Promise Resolves with a string when new data is available or `null` if the stream has closed. * * @throws PendingReadError Thrown if another read operation is still pending. */ public function read(): Promise { if ($this->initialRead) { throw new PendingReadError; } if ($this->error) { return new Failure($this->error); } if ($this->resourceStream) { return $this->resourceStream->read(); } if ($this->shouldClose) { return new Success; // Resolve reads on closed streams with null. } $this->initialRead = new Deferred; return $this->initialRead->promise(); } public function reference() { $this->referenced = true; if ($this->resourceStream) { $this->resourceStream->reference(); } } public function unreference() { $this->referenced = false; if ($this->resourceStream) { $this->resourceStream->unreference(); } } public function close() { $this->shouldClose = true; if ($this->initialRead) { $initialRead = $this->initialRead; $this->initialRead = null; $initialRead->resolve(); } if ($this->resourceStream) { $this->resourceStream->close(); } } } <?php namespace Amp\Process; class ProcessException extends \Exception { } <?php namespace Amp\Process; use Amp\Loop; use Amp\Process\Internal\Posix\Runner as PosixProcessRunner; use Amp\Process\Internal\ProcessHandle; use Amp\Process\Internal\ProcessRunner; use Amp\Process\Internal\ProcessStatus; use Amp\Process\Internal\Windows\Runner as WindowsProcessRunner; use Amp\Promise; use function Amp\call; final class Process { /** @var ProcessRunner */ private $processRunner; /** @var string */ private $command; /** @var string */ private $cwd = ""; /** @var array */ private $env = []; /** @var array */ private $options; /** @var ProcessHandle */ private $handle; /** @var int|null */ private $pid; /** * @param string|string[] $command Command to run. * @param string|null $cwd Working directory or use an empty string to use the working directory of the * parent. * @param mixed[] $env Environment variables or use an empty array to inherit from the parent. * @param mixed[] $options Options for `proc_open()`. * * @throws \Error If the arguments are invalid. */ public function __construct($command, string $cwd = null, array $env = [], array $options = []) { $command = \is_array($command) ? \implode(" ", \array_map(__NAMESPACE__ . "\\escapeArguments", $command)) : (string) $command; $cwd = $cwd ?? ""; $envVars = []; foreach ($env as $key => $value) { if (\is_array($value)) { throw new \Error("\$env cannot accept array values"); } $envVars[(string) $key] = (string) $value; } $this->command = $command; $this->cwd = $cwd; $this->env = $envVars; $this->options = $options; $this->processRunner = Loop::getState(self::class); if ($this->processRunner === null) { $this->processRunner = IS_WINDOWS ? new WindowsProcessRunner : new PosixProcessRunner; Loop::setState(self::class, $this->processRunner); } } /** * Stops the process if it is still running. */ public function __destruct() { if ($this->handle !== null) { $this->processRunner->destroy($this->handle); } } public function __clone() { throw new \Error("Cloning is not allowed!"); } /** * Start the process. * * @return Promise<int> Resolves with the PID. * * @throws StatusError If the process has already been started. */ public function start(): Promise { if ($this->handle) { throw new StatusError("Process has already been started."); } return call(function () { $this->handle = $this->processRunner->start($this->command, $this->cwd, $this->env, $this->options); return $this->pid = yield $this->handle->pidDeferred->promise(); }); } /** * Wait for the process to end. * * @return Promise <int> Succeeds with process exit code or fails with a ProcessException if the process is killed. * * @throws StatusError If the process has already been started. */ public function join(): Promise { if (!$this->handle) { throw new StatusError("Process has not been started."); } return $this->processRunner->join($this->handle); } /** * Forcibly end the process. * * @throws StatusError If the process is not running. * @throws ProcessException If terminating the process fails. */ public function kill() { if (!$this->isRunning()) { throw new StatusError("Process is not running."); } $this->processRunner->kill($this->handle); } /** * Send a signal signal to the process. * * @param int $signo Signal number to send to process. * * @throws StatusError If the process is not running. * @throws ProcessException If sending the signal fails. */ public function signal(int $signo) { if (!$this->isRunning()) { throw new StatusError("Process is not running."); } $this->processRunner->signal($this->handle, $signo); } /** * Returns the PID of the child process. * * @return int * * @throws StatusError If the process has not started or has not completed starting. */ public function getPid(): int { if (!$this->pid) { throw new StatusError("Process has not been started or has not completed starting."); } return $this->pid; } /** * Returns the command to execute. * * @return string The command to execute. */ public function getCommand(): string { return $this->command; } /** * Gets the current working directory. * * @return string The current working directory an empty string if inherited from the current PHP process. */ public function getWorkingDirectory(): string { if ($this->cwd === "") { return \getcwd() ?: ""; } return $this->cwd; } /** * Gets the environment variables array. * * @return string[] Array of environment variables. */ public function getEnv(): array { return $this->env; } /** * Gets the options to pass to proc_open(). * * @return mixed[] Array of options. */ public function getOptions(): array { return $this->options; } /** * Determines if the process is still running. * * @return bool */ public function isRunning(): bool { return $this->handle && $this->handle->status !== ProcessStatus::ENDED; } /** * Gets the process input stream (STDIN). * * @return ProcessOutputStream */ public function getStdin(): ProcessOutputStream { if (!$this->handle || $this->handle->status === ProcessStatus::STARTING) { throw new StatusError("Process has not been started or has not completed starting."); } return $this->handle->stdin; } /** * Gets the process output stream (STDOUT). * * @return ProcessInputStream */ public function getStdout(): ProcessInputStream { if (!$this->handle || $this->handle->status === ProcessStatus::STARTING) { throw new StatusError("Process has not been started or has not completed starting."); } return $this->handle->stdout; } /** * Gets the process error stream (STDERR). * * @return ProcessInputStream */ public function getStderr(): ProcessInputStream { if (!$this->handle || $this->handle->status === ProcessStatus::STARTING) { throw new StatusError("Process has not been started or has not completed starting."); } return $this->handle->stderr; } public function __debugInfo(): array { return [ 'command' => $this->getCommand(), 'cwd' => $this->getWorkingDirectory(), 'env' => $this->getEnv(), 'options' => $this->getOptions(), 'pid' => $this->pid, 'status' => $this->handle ? $this->handle->status : -1, ]; } } <?php namespace Amp\Process; class StatusError extends \Error { } { "name": "amphp/windows-registry", "description": "Windows Registry Reader.", "type": "library", "license": "MIT", "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "autoload": { "psr-4": { "Amp\\WindowsRegistry\\": "lib" } }, "require": { "amphp/amp": "^2", "amphp/byte-stream": "^1.4", "amphp/process": "^1" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master" }, "config": { "platform": { "php": "7.0.0" } } } <?php namespace Amp\WindowsRegistry; use Amp\ByteStream; use Amp\Process\Process; use Amp\Promise; use function Amp\call; class WindowsRegistry { public function read(string $key): Promise { return call(function () use ($key) { $key = \strtr($key, '/', "\\"); $parts = \explode("\\", $key); $value = \array_pop($parts); $key = \implode("\\", $parts); $lines = yield $this->query($key); $lines = \array_filter($lines, function ($line) { return '' !== $line && $line[0] === ' '; }); $values = \array_map(function ($line) { return \preg_split("(\\s+)", \ltrim($line), 3); }, $lines); foreach ($values as $v) { if ($v[0] === $value) { return $v[2]; } } throw new KeyNotFoundException("Windows registry key '{$key}\\{$value}' not found."); }); } public function listKeys(string $key): Promise { return call(function () use ($key) { $lines = yield $this->query($key); $lines = \array_filter($lines, function ($line) { return '' !== $line && $line[0] !== ' '; }); return $lines; }); } private function query(string $key): Promise { return call(function () use ($key) { if (0 !== \stripos(\PHP_OS, 'WIN')) { throw new \Error('Not running on Windows.'); } $key = \strtr($key, '/', "\\"); $cmd = \sprintf('reg query %s', \escapeshellarg($key)); $process = new Process($cmd); yield $process->start(); $stdout = yield ByteStream\buffer($process->getStdout()); $code = yield $process->join(); if ($code !== 0) { throw new KeyNotFoundException("Windows registry key '{$key}' not found."); } return \explode("\n", \str_replace("\r", '', $stdout)); }); } } <?php namespace Amp\WindowsRegistry; class KeyNotFoundException extends \Exception { } <?php use Amp\Http\Rfc7230; require __DIR__ . "/../vendor/autoload.php"; $rawHeaders = "Server: GitHub.com\r\n" . "Date: Tue, 31 Oct 2006 08:00:29 GMT\r\n" . "Connection: close\r\n" . "Content-Length: 0\r\n"; $headers = Rfc7230::parseHeaders($rawHeaders); \var_dump($headers); <?php // This implementation doesn't do any validation and just splits at the first colon in each line. function parse(string $rawHeaders): array { $lines = \explode("\r\n", $rawHeaders); $headers = []; foreach ($lines as $line) { if (empty($line)) { break; } if (\strpos($line, ':') !== false) { $parts = \explode(':', $line, 2); $headers[\strtolower($parts[0])][] = \trim($parts[1] ?? ''); } } return $headers; } $rawHeaders = "Server: Microsoft-IIS/5.0 Date: Tue, 31 Oct 2006 08:00:29 GMT Connection: close Allow: GET, HEAD, POST, TRACE, OPTIONS Content-Length: 0 X-No-Value: X-No-Whitespace: Test X-Trailing-Whitespace: Foobar "; $start = \microtime(true); for ($i = 0; $i < 300000; $i++) { parse($rawHeaders); } print(\microtime(true) - $start) . PHP_EOL; <?php use Amp\Http\Rfc7230; require __DIR__ . "/../../vendor/autoload.php"; $rawHeaders = "Server: Microsoft-IIS/5.0 Date: Tue, 31 Oct 2006 08:00:29 GMT Connection: close Allow: GET, HEAD, POST, TRACE, OPTIONS Content-Length: 0 X-No-Value: X-No-Whitespace: Test X-Trailing-Whitespace: Foobar "; // Normalize line endings, which might be broken by Git otherwise $rawHeaders = \str_replace("\n", "\r\n", \str_replace("\r\n", "\n", $rawHeaders)); $headers = Rfc7230::parseHeaders($rawHeaders); $start = \microtime(true); for ($i = 0; $i < 300000; $i++) { Rfc7230::formatHeaders($headers); } print(\microtime(true) - $start) . PHP_EOL; <?php use Amp\Http\Rfc7230; require __DIR__ . "/../../vendor/autoload.php"; $rawHeaders = "Server: Microsoft-IIS/5.0 Date: Tue, 31 Oct 2006 08:00:29 GMT Connection: close Allow: GET, HEAD, POST, TRACE, OPTIONS Content-Length: 0 X-No-Value: X-No-Whitespace: Test X-Trailing-Whitespace: Foobar "; // Normalize line endings, which might be broken by Git otherwise $rawHeaders = \str_replace("\n", "\r\n", \str_replace("\r\n", "\n", $rawHeaders)); $start = \microtime(true); for ($i = 0; $i < 300000; $i++) { Rfc7230::parseHeaders($rawHeaders); } print(\microtime(true) - $start) . PHP_EOL; <?php use Amp\Http\Cookie\ResponseCookie; use Amp\Http\Rfc7230; require __DIR__ . "/../vendor/autoload.php"; $headers = Rfc7230::formatHeaders([ "server" => [ "GitHub.com", ], "location" => [ "https://github.com/", ], "set-cookie" => [ new ResponseCookie("session", \bin2hex(\random_bytes(16))), new ResponseCookie("user", "amphp"), ] ]); \var_dump($headers); <?php use Amp\Http\Cookie\CookieAttributes; use Amp\Http\Cookie\RequestCookie; use Amp\Http\Cookie\ResponseCookie; require __DIR__ . "/../vendor/autoload.php"; $attributes = CookieAttributes::default()->withSecure(); $cookie = new ResponseCookie("session", \bin2hex(\random_bytes(16)), $attributes); \var_dump($cookie->getName()); \var_dump($cookie->getValue()); \var_dump($cookie->isHttpOnly()); \var_dump("set-cookie: " . $cookie); $cookie = ResponseCookie::fromHeader($cookie); $cookie = new RequestCookie("session", $cookie->getValue()); \var_dump($cookie->getName()); \var_dump($cookie->getValue()); \var_dump("cookie: " . $cookie); { "name": "amphp/http", "description": "Basic HTTP primitives which can be shared by servers and clients.", "type": "library", "license": "MIT", "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "autoload": { "psr-4": { "Amp\\Http\\": "src" } }, "require": { "php": ">=7" }, "require-dev": { "phpunit/phpunit": "^6.5", "amphp/php-cs-fixer-config": "dev-master" }, "config": { "platform": { "php": "7.0.13" } }, "scripts": { "test": "php vendor/bin/phpunit", "code-style": "php vendor/bin/php-cs-fixer fix" } } <?php namespace Amp\Http; use PHPUnit\Framework\TestCase; class StatusTest extends TestCase { public function testEachDefinedStatusHasDefaultReason() { $class = new \ReflectionClass(Status::class); foreach ($class->getConstants() as $statusCode) { $this->assertNotEmpty(Status::getReason($statusCode), "{$statusCode} doesn't have a default reason."); } } public function testEachDefaultReasonHasCorrespondingConstant() { $class = new \ReflectionClass(Status::class); $constants = $class->getConstants(); for ($i = 0; $i < 600; $i++) { $reason = Status::getReason($i); if ($reason !== "") { $this->assertContains($i, $constants); } } } public function testNoDuplicateDefinition() { $class = new \ReflectionClass(Status::class); $constants = $class->getConstants(); // Double array_flip removes any duplicates. $this->assertSame($constants, \array_flip(\array_flip($constants))); } } <?php namespace Amp\Http; use PHPUnit\Framework\TestCase; class Rfc7230Test extends TestCase { /** @dataProvider provideValidHeaders */ public function testValidHeaderParsing(string $rawHeaders, array $expectedResult) { $result = Rfc7230::parseHeaders($rawHeaders); $this->assertSame($result, $expectedResult); } /** @dataProvider provideValidHeaders */ public function testValidHeaderFormatting(string $rawHeaders /* ignored for this case */, array $expectedResult) { $result = Rfc7230::parseHeaders(Rfc7230::formatHeaders($expectedResult)); $this->assertSame($result, $expectedResult); } public function provideValidHeaders() { return [ ["x:y\r\n", ["x" => ["y"]]], ["server:\tamphp.org\r\n", ["server" => ["amphp.org"]]], ["server: \tamphp.org \t \r\n", ["server" => ["amphp.org"]]], ["server: \tamphp.org \t \r\nServer: amphp.org\r\n", ["server" => ["amphp.org", "amphp.org"]]], ["ser124ver:\tamphp.org\r\n", ["ser124ver" => ["amphp.org"]]], ]; } /** @dataProvider provideInvalidHeaders */ public function testInvalidHeaderParsing(string $rawHeaders) { $this->expectException(InvalidHeaderException::class); Rfc7230::parseHeaders($rawHeaders); } public function provideInvalidHeaders() { return [ [" x:y\r\n"], ["x :z\r\n"], [" x:z\r\n"], ["x :z\nfoo: bar\r\n"], ["x:z\nfoo: bar\r\n"], ["ser ver:\tamphp.org\r\n"], ["server:\tamphp.org\r\n fold\r\n"], ]; } public function testIgnoresHttp2PseudoHeaders() { $headers = [ "foobar" => ["bar"], ":method" => ["GET"], "x" => ["y"], ]; $this->assertSame("foobar: bar\r\nx: y\r\n", Rfc7230::formatHeaders($headers)); } public function testDetectsHeaderInjectionsWithLfInValue() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar" => ["test\nbar"]]); } public function testDetectsHeaderInjectionsWithCrInValue() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar" => ["test\rbar"]]); } public function testDetectsHeaderInjectionsWithCrLfInValue() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar" => ["test\r\nbar"]]); } public function testDetectsHeaderInjectionsWithCrLfAndColonInValue() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar" => ["test\r\nfoo: bar"]]); } public function testDetectsHeaderInjectionsWithCrInName() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar\rfoobar" => ["bar"]]); } public function testDetectsHeaderInjectionsWithLfInName() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar\nfoobar" => ["bar"]]); } public function testDetectsHeaderInjectionsWithCrLfInName() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar\r\nfoobar" => ["bar"]]); } public function testDetectsHeaderInjectionsWithCrLfAndColonInName() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foobar: test\r\nfoobar" => ["bar"]]); } public function testDetectsInvalidHeaderSyntax() { $this->expectException(InvalidHeaderException::class); $this->expectExceptionMessage("Invalid headers"); Rfc7230::formatHeaders(["foo bar" => ["bar"]]); } } <?php namespace Amp\Http\Cookie; use PHPUnit\Framework\TestCase; class CookieAttributesTest extends TestCase { public function testMaxAge() { $attributes = CookieAttributes::default()->withMaxAge(10); $this->assertSame(10, $attributes->getMaxAge()); $this->assertNull($attributes->getExpiry()); $attributes = $attributes->withoutMaxAge(); $this->assertNull($attributes->getMaxAge()); $this->assertNull($attributes->getExpiry()); } public function testExpiry() { $expiry = new \DateTimeImmutable("now+10s"); $attributes = CookieAttributes::default()->withExpiry($expiry); $this->assertSame($expiry, $attributes->getExpiry()); $this->assertNull($attributes->getMaxAge()); $attributes = $attributes->withoutExpiry(); $this->assertNull($attributes->getExpiry()); $this->assertNull($attributes->getMaxAge()); } public function testSecure() { $attributes = CookieAttributes::default(); $this->assertFalse($attributes->isSecure()); $this->assertTrue($attributes->withSecure()->isSecure()); $this->assertFalse($attributes->withSecure()->withoutSecure()->isSecure()); } public function testHttpOnly() { $attributes = CookieAttributes::default(); $this->assertTrue($attributes->isHttpOnly()); $this->assertFalse($attributes->withoutHttpOnly()->isHttpOnly()); $this->assertTrue($attributes->withoutHttpOnly()->withHttpOnly()->isHttpOnly()); } public function testToString() { $expiry = new \DateTimeImmutable("now+10s"); $attributes = CookieAttributes::default(); $this->assertSame('; HttpOnly', (string) $attributes); $this->assertSame('; Secure; HttpOnly', (string) $attributes->withSecure()); $this->assertSame('; Max-Age=10; HttpOnly', (string) $attributes->withMaxAge(10)); $this->assertSame('; Path=/; HttpOnly', (string) $attributes->withPath('/')); $this->assertSame('; Domain=localhost; HttpOnly', (string) $attributes->withDomain('localhost')); $this->assertSame('; Expires=' . \gmdate('D, j M Y G:i:s T', $expiry->getTimestamp()) . '; HttpOnly', (string) $attributes->withExpiry($expiry)); } } <?php namespace Amp\Http\Cookie; use PHPUnit\Framework\TestCase; class ResponseCookieTest extends TestCase { public function testParsingOnEmptyName() { $this->assertNull(ResponseCookie::fromHeader("=123438afes7a8")); } public function testParsingOnInvalidNameValueCount() { $this->assertNull(ResponseCookie::fromHeader("; HttpOnly=123")); } public function testParsing() { // Examples from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie $this->assertEquals( new ResponseCookie("sessionid", "38afes7a8", CookieAttributes::empty()->withHttpOnly()->withPath("/")), ResponseCookie::fromHeader("sessionid=38afes7a8; HttpOnly; Path=/") ); $expectedMeta = CookieAttributes::empty() ->withHttpOnly() ->withSecure() ->withExpiry(new \DateTimeImmutable("Wed, 21 Oct 2015 07:28:00", new \DateTimeZone("GMT"))); $this->assertEquals( new ResponseCookie("id", "a3fWa", $expectedMeta), ResponseCookie::fromHeader("id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly") ); // This might fail if the second switches between withMaxAge() and fromHeader() - we take the risk $expectedMeta = CookieAttributes::empty() ->withMaxAge(60); $this->assertEquals( new ResponseCookie("id", "a3fWa", $expectedMeta), ResponseCookie::fromHeader("id=a3fWa; Max-AGE=60") ); // Missing "Wed, " in date, so date is ignored $expectedMeta = CookieAttributes::empty() ->withDomain("example.com") ->withPath("/"); $this->assertEquals( new ResponseCookie("qwerty", "219ffwef9w0f", $expectedMeta), ResponseCookie::fromHeader("qwerty=219ffwef9w0f; Domain=example.com; Path=/; Expires=30 Aug 2019 00:00:00 GMT") ); $expectedMeta = CookieAttributes::empty() ->withDomain("example.com") ->withPath("/") ->withExpiry(new \DateTimeImmutable("Wed, 30 Aug 2019 00:00:00", new \DateTimeZone("GMT"))); $this->assertEquals( new ResponseCookie("qwerty", "219ffwef9w0f", $expectedMeta), $cookie = ResponseCookie::fromHeader("qwerty=219ffwef9w0f; Domain=example.com; Path=/; Expires=Wed, 30 Aug 2019 00:00:00 GMT") ); $this->assertFalse($cookie->isSecure()); $this->assertFalse($cookie->isHttpOnly()); $this->assertSame("qwerty", $cookie->getName()); $this->assertSame("219ffwef9w0f", $cookie->getValue()); $this->assertSame("example.com", $cookie->getDomain()); $this->assertSame("/", $cookie->getPath()); $this->assertSame( (new \DateTimeImmutable("Wed, 30 Aug 2019 00:00:00", new \DateTimeZone("GMT")))->getTimestamp(), $cookie->getExpiry()->getTimestamp() ); // Non-digit in Max-Age $this->assertEquals( new ResponseCookie("qwerty", "219ffwef9w0f", CookieAttributes::empty()), ResponseCookie::fromHeader("qwerty=219ffwef9w0f; Max-Age=12520b") ); // "-" in front in Max-Age $this->assertEquals( new ResponseCookie("qwerty", "219ffwef9w0f", CookieAttributes::empty()->withMaxAge(-1)), ResponseCookie::fromHeader("qwerty=219ffwef9w0f; Max-Age=-1") ); $this->assertNull( ResponseCookie::fromHeader("query foo=129") ); } public function testGetMaxAge() { $responseCookie = new ResponseCookie("qwerty", "219ffwef9w0f", CookieAttributes::empty()->withMaxAge(10)); $this->assertSame(10, $responseCookie->getMaxAge()); } public function testInvalidName() { $this->expectException(InvalidCookieException::class); new ResponseCookie("foo:bar"); } public function testInvalidValue() { $this->expectException(InvalidCookieException::class); new ResponseCookie("foobar", "foo;bar"); } public function testGetAttributes() { $attributes = CookieAttributes::default(); $cookie = new ResponseCookie("foobar", "xxx", $attributes); $this->assertSame($attributes, $cookie->getAttributes()); } public function testToString() { $attributes = CookieAttributes::default(); $cookie = new ResponseCookie("foobar", "xxx", $attributes); $this->assertSame("foobar=xxx; HttpOnly", (string) $cookie); } public function testModifyName() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withName('bar'); $this->assertSame('foobar', $cookie->getName()); $this->assertSame('bar', $newCookie->getName()); } public function testModifyValue() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withValue('what-is-that'); $this->assertSame('what-is-this', $cookie->getValue()); $this->assertSame('what-is-that', $newCookie->getValue()); } public function testModifyHttpOnly() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withoutHttpOnly(); $this->assertTrue($cookie->isHttpOnly()); $this->assertTrue($newCookie->withHttpOnly()->isHttpOnly()); $this->assertFalse($newCookie->isHttpOnly()); } public function testModifySecure() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withSecure(); $this->assertFalse($cookie->isSecure()); $this->assertFalse($newCookie->withoutSecure()->isSecure()); $this->assertTrue($newCookie->isSecure()); } public function testModifyDomain() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withDomain('example.com'); $this->assertSame('', $cookie->getDomain()); $this->assertSame('example.com', $newCookie->getDomain()); } public function testModifyPath() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withPath('/example'); $this->assertSame('', $cookie->getPath()); $this->assertSame('/example', $newCookie->getPath()); } public function testModifyExpiry() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withExpiry(\DateTimeImmutable::createFromFormat('Y-m-d', '2019-06-10')); $this->assertNull($cookie->getExpiry()); $this->assertNull($newCookie->withoutExpiry()->getExpiry()); $this->assertSame('2019-06-10', $newCookie->getExpiry()->format('Y-m-d')); } public function testModifyExpiryMutable() { $cookie = new ResponseCookie("foobar", "what-is-this"); $expiry = \DateTime::createFromFormat('Y-m-d', '2019-06-10'); $newCookie = $cookie->withExpiry($expiry); $this->assertNull($cookie->getExpiry()); $this->assertNull($newCookie->withoutExpiry()->getExpiry()); $this->assertSame('2019-06-10', $newCookie->getExpiry()->format('Y-m-d')); $expiry->add(new \DateInterval('P2D')); $this->assertSame('2019-06-10', $newCookie->getExpiry()->format('Y-m-d')); } public function testModifyMaxAge() { $cookie = new ResponseCookie("foobar", "what-is-this"); $newCookie = $cookie->withMaxAge(12); $this->assertNull($cookie->getMaxAge()); $this->assertNull($newCookie->withoutMaxAge()->getMaxAge()); $this->assertSame(12, $newCookie->getMaxAge()); } public function testInvalidCookieName() { $this->expectException(InvalidCookieException::class); new ResponseCookie("foo bar"); } public function testInvalidCookieNameModify() { $cookie = new ResponseCookie("foobar"); $this->expectException(InvalidCookieException::class); $cookie->withName('foo bar'); } public function testInvalidCookieValue() { $this->expectException(InvalidCookieException::class); new ResponseCookie("foobar", "what is this"); } public function testInvalidCookieValueModify() { $cookie = new ResponseCookie("foobar", "what-is-this"); $this->expectException(InvalidCookieException::class); $cookie->withValue('what is this'); } public function testPreservesUnknownAttributes() { $cookie = ResponseCookie::fromHeader('key=value; HttpOnly; SameSite=strict;Foobar'); $this->assertNotNull($cookie); $this->assertSame('key', $cookie->getName()); $this->assertSame('value', $cookie->getValue()); $this->assertTrue($cookie->isHttpOnly()); $this->assertSame('key=value; HttpOnly; SameSite=strict; Foobar', (string) $cookie); } } <?php namespace Amp\Http\Cookie; use PHPUnit\Framework\TestCase; class RequestCookieTest extends TestCase { public function testParsing() { $this->assertEquals([new RequestCookie("foobar", "xxx")], RequestCookie::fromHeader("foobar=xxx")); $this->assertEquals([new RequestCookie("foobar", "x%20x")], RequestCookie::fromHeader("foobar=x%20x")); $this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "2")], RequestCookie::fromHeader("a=1;b=2")); $this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "2")], RequestCookie::fromHeader("a=1; b=2")); $this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "2")], RequestCookie::fromHeader("a=1 ;b=2")); $this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "-2")], RequestCookie::fromHeader("a=1; b = -2")); $this->assertSame([], RequestCookie::fromHeader("a=1; b=2 2")); // Any missing = MUST discard the full cookie header $this->assertSame([], RequestCookie::fromHeader("a=1; b")); } public function testInvalidCookieName() { $this->expectException(InvalidCookieException::class); new RequestCookie("foo bar"); } public function testInvalidCookieNameModify() { $cookie = new RequestCookie("foobar"); $this->expectException(InvalidCookieException::class); $cookie->withName('foo bar'); } public function testInvalidCookieValue() { $this->expectException(InvalidCookieException::class); new RequestCookie("foobar", "what is this"); } public function testInvalidCookieValueModify() { $cookie = new RequestCookie("foobar", "what-is-this"); $this->expectException(InvalidCookieException::class); $cookie->withValue('what is this'); } public function testGetters() { $cookie = new RequestCookie("foobar", "baz"); $this->assertSame("foobar", $cookie->getName()); $this->assertSame("baz", $cookie->getValue()); $this->assertSame("foobar=baz", (string) $cookie); } public function testModifyName() { $cookie = new RequestCookie("foobar", "what-is-this"); $newCookie = $cookie->withName('bar'); $this->assertSame('foobar', $cookie->getName()); $this->assertSame('bar', $newCookie->getName()); } public function testModifyValue() { $cookie = new RequestCookie("foobar", "what-is-this"); $newCookie = $cookie->withValue('what-is-that'); $this->assertSame('what-is-this', $cookie->getValue()); $this->assertSame('what-is-that', $newCookie->getValue()); } } <?php namespace Amp\Http\Test; use Amp\Http\Message; use PHPUnit\Framework\TestCase; class TestMessage extends Message { public function __construct(array $headers = []) { $this->setHeaders($headers); } public function setHeaders(array $headers) { parent::setHeaders($headers); } public function setHeader(string $name, $value) { parent::setHeader($name, $value); } public function addHeader(string $name, $value) { parent::addHeader($name, $value); } public function removeHeader(string $name) { parent::removeHeader($name); } } class MessageTest extends TestCase { public function testGetHeader() { $message = new TestMessage([ 'foo' => 'bar', ]); $this->assertTrue($message->hasHeader('foo')); $this->assertSame(['foo' => ['bar']], $message->getHeaders()); $this->assertSame('bar', $message->getHeader('foo')); $this->assertSame('bar', $message->getHeader('FOO')); $this->assertSame('bar', $message->getHeader('FoO')); $this->assertNull($message->getHeader('bar')); $this->assertSame(['bar'], $message->getHeaderArray('foo')); $this->assertSame([], $message->getHeaderArray('bar')); } public function testAddHeader() { $message = new TestMessage([ 'foo' => 'bar', ]); $this->assertSame(['bar'], $message->getHeaderArray('foo')); $message->addHeader('foo', 'bar'); $this->assertSame(['bar', 'bar'], $message->getHeaderArray('foo')); $message->addHeader('bar', 'bar'); $this->assertSame(['bar'], $message->getHeaderArray('bar')); $message->addHeader('bar', ['baz']); $this->assertSame(['bar', 'baz'], $message->getHeaderArray('bar')); $message->addHeader('bar', []); $this->assertSame(['bar', 'baz'], $message->getHeaderArray('bar')); } public function testSetHeader() { $message = new TestMessage([ 'foo' => 'bar', ]); $this->assertSame(['bar'], $message->getHeaderArray('foo')); $message->setHeader('foo', 'bar'); $this->assertSame(['bar'], $message->getHeaderArray('foo')); $message->setHeader('bar', 'bar'); $this->assertSame(['bar'], $message->getHeaderArray('bar')); $message->setHeaders(['bar' => []]); $this->assertSame(['bar'], $message->getHeaderArray('foo')); $this->assertFalse($message->hasHeader('bar')); $this->assertSame([], $message->getHeaderArray('bar')); $message->setHeader('bar', ['biz', 'baz']); $this->assertSame(['biz', 'baz'], $message->getHeaderArray('bar')); $this->assertSame('biz', $message->getHeader('bar')); } public function testInvalidName() { $this->expectException(\AssertionError::class); $this->expectExceptionMessage('Invalid header name'); $message = new TestMessage; $message->setHeader("te\0st", 'value'); } public function testInvalidValue() { $this->expectException(\AssertionError::class); $this->expectExceptionMessage('Invalid header value'); $message = new TestMessage; $message->setHeader('foo', "te\0st"); } } <?php namespace Amp\Http\Cookie; /** * A cookie as sent in a response's 'set-cookie' header, so with attributes. * * This class does not deal with encoding of arbitrary names and values. If you want to use arbitrary values, please use * an encoding mechanism like Base64 or URL encoding. * * @link https://tools.ietf.org/html/rfc6265#section-5.2 */ final class ResponseCookie { private static $dateFormats = [ 'D, d M Y H:i:s T', 'D, d-M-y H:i:s T', 'D, d-M-Y H:i:s T', 'D, d-m-y H:i:s T', 'D, d-m-Y H:i:s T', 'D M j G:i:s Y', 'D M d H:i:s Y T', ]; /** @var string[] */ private $unknownAttributes = []; /** * Parses a cookie from a 'set-cookie' header. * * @param string $string Valid 'set-cookie' header line. * * @return self|null Returns a `ResponseCookie` instance on success and `null` on failure. */ public static function fromHeader(string $string) { /* : ?self */ $parts = \array_map("trim", \explode(";", $string)); $nameValue = \explode("=", \array_shift($parts), 2); if (\count($nameValue) !== 2) { return null; } list($name, $value) = $nameValue; $name = \trim($name); $value = \trim($value, " \t\n\r\0\x0B\""); if ($name === "") { return null; } // httpOnly must default to false for parsing $meta = CookieAttributes::empty(); $unknownAttributes = []; foreach ($parts as $part) { $pieces = \array_map('trim', \explode('=', $part, 2)); $key = \strtolower($pieces[0]); if (1 === \count($pieces)) { switch ($key) { case 'secure': $meta = $meta->withSecure(); break; case 'httponly': $meta = $meta->withHttpOnly(); break; default: $unknownAttributes[] = $part; break; } } else { switch ($key) { case 'expires': $time = self::parseDate($pieces[1]); if ($time === null) { break; // break is correct, see https://tools.ietf.org/html/rfc6265#section-5.2.1 } $meta = $meta->withExpiry($time); break; case 'max-age': $maxAge = \trim($pieces[1]); // This also allows +1.42, but avoids a more complicated manual check if (!\is_numeric($maxAge)) { break; // break is correct, see https://tools.ietf.org/html/rfc6265#section-5.2.2 } $meta = $meta->withMaxAge($maxAge); break; case 'path': $meta = $meta->withPath($pieces[1]); break; case 'domain': $meta = $meta->withDomain($pieces[1]); break; default: $unknownAttributes[] = $part; break; } } } try { $cookie = new self($name, $value, $meta); $cookie->unknownAttributes = $unknownAttributes; return $cookie; } catch (InvalidCookieException $e) { return null; } } /** * @param string $date Formatted cookie date * * @return \DateTimeImmutable|null Parsed date. */ private static function parseDate(string $date) { /* ?\DateTimeImmutable */ foreach (self::$dateFormats as $dateFormat) { if ($parsedDate = \DateTimeImmutable::createFromFormat($dateFormat, $date, new \DateTimeZone('GMT'))) { return $parsedDate; } } return null; } /** @var string */ private $name; /** @var string */ private $value; /** @var CookieAttributes */ private $attributes; /** * @param string $name Name of the cookie. * @param string $value Value of the cookie. * @param CookieAttributes $attributes Attributes of the cookie. * * @throws InvalidCookieException If name or value is invalid. */ public function __construct( string $name, string $value = '', CookieAttributes $attributes = null ) { if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++$)', $name)) { throw new InvalidCookieException("Invalid cookie name: '{$name}'"); } if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) { throw new InvalidCookieException("Invalid cookie value: '{$value}'"); } $this->name = $name; $this->value = $value; $this->attributes = $attributes ?? CookieAttributes::default(); } /** * @return string Name of the cookie. */ public function getName(): string { return $this->name; } public function withName(string $name): self { if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++$)', $name)) { throw new InvalidCookieException("Invalid cookie name: '{$name}'"); } $clone = clone $this; $clone->name = $name; return $clone; } /** * @return string Value of the cookie. */ public function getValue(): string { return $this->value; } public function withValue(string $value): self { if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) { throw new InvalidCookieException("Invalid cookie value: '{$value}'"); } $clone = clone $this; $clone->value = $value; return $clone; } /** * @return \DateTimeImmutable|null Expiry if set, otherwise `null`. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.1 */ public function getExpiry() { /* : ?\DateTimeImmutable */ return $this->attributes->getExpiry(); } public function withExpiry(\DateTimeInterface $expiry): self { return $this->withAttributes($this->attributes->withExpiry($expiry)); } public function withoutExpiry(): self { return $this->withAttributes($this->attributes->withoutExpiry()); } /** * @return int|null Max-Age if set, otherwise `null`. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.2 */ public function getMaxAge() { /* : ?int */ return $this->attributes->getMaxAge(); } public function withMaxAge(int $maxAge): self { return $this->withAttributes($this->attributes->withMaxAge($maxAge)); } public function withoutMaxAge(): self { return $this->withAttributes($this->attributes->withoutMaxAge()); } /** * @return string Cookie path. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.4 */ public function getPath(): string { return $this->attributes->getPath(); } public function withPath(string $path): self { return $this->withAttributes($this->attributes->withPath($path)); } /** * @return string Cookie domain. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.3 */ public function getDomain(): string { return $this->attributes->getDomain(); } public function withDomain(string $domain): self { return $this->withAttributes($this->attributes->withDomain($domain)); } /** * @return bool Whether the secure flag is enabled or not. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.5 */ public function isSecure(): bool { return $this->attributes->isSecure(); } public function withSecure(): self { return $this->withAttributes($this->attributes->withSecure()); } public function withoutSecure(): self { return $this->withAttributes($this->attributes->withoutSecure()); } /** * @return bool Whether the httpOnly flag is enabled or not. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.6 */ public function isHttpOnly(): bool { return $this->attributes->isHttpOnly(); } public function withHttpOnly(): self { return $this->withAttributes($this->attributes->withHttpOnly()); } public function withoutHttpOnly(): self { return $this->withAttributes($this->attributes->withoutHttpOnly()); } /** * @return CookieAttributes All cookie attributes. */ public function getAttributes(): CookieAttributes { return $this->attributes; } public function withAttributes(CookieAttributes $attributes): self { $clone = clone $this; $clone->attributes = $attributes; return $clone; } /** * @return string Representation of the cookie as in a 'set-cookie' header. */ public function __toString(): string { $line = $this->name . '=' . $this->value; $line .= $this->attributes; $unknownAttributes = \implode('; ', $this->unknownAttributes); if ($unknownAttributes !== '') { $line .= '; ' . $unknownAttributes; } return $line; } } <?php namespace Amp\Http\Cookie; /** * A cookie as sent in a request's 'cookie' header, so without any attributes. * * This class does not deal with encoding of arbitrary names and values. If you want to use arbitrary values, please use * an encoding mechanism like Base64 or URL encoding. * * @link https://tools.ietf.org/html/rfc6265#section-5.4 */ final class RequestCookie { /** @var string */ private $name; /** @var string */ private $value; /** * Parses the cookies from a 'cookie' header. * * Note: Parsing is aborted if there's an invalid value and no cookies are returned. * * @param string $string Valid 'cookie' header line. * * @return RequestCookie[] */ public static function fromHeader(string $string): array { $cookies = \explode(";", $string); $result = []; try { foreach ($cookies as $cookie) { $parts = \explode('=', $cookie, 2); if (2 !== \count($parts)) { return []; } list($name, $value) = $parts; // We can safely trim quotes, as they're not allowed within cookie values $result[] = new self(\trim($name), \trim($value, " \t\"")); } } catch (InvalidCookieException $e) { return []; } return $result; } /** * @param string $name Cookie name in its decoded form. * @param string $value Cookie value in its decoded form. * * @throws InvalidCookieException If name or value is invalid. */ public function __construct(string $name, string $value = '') { if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]*+$)', $name)) { throw new InvalidCookieException("Invalid cookie name: '{$name}'"); } if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) { throw new InvalidCookieException("Invalid cookie value: '{$value}'"); } $this->name = $name; $this->value = $value; } /** * @return string Name of the cookie. */ public function getName(): string { return $this->name; } public function withName(string $name): self { if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++$)', $name)) { throw new InvalidCookieException("Invalid cookie name: '{$name}'"); } $clone = clone $this; $clone->name = $name; return $clone; } /** * @return string Value of the cookie. */ public function getValue(): string { return $this->value; } public function withValue(string $value): self { if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) { throw new InvalidCookieException("Invalid cookie value: '{$value}'"); } $clone = clone $this; $clone->value = $value; return $clone; } /** * @return string Representation of the cookie as in a 'cookie' header. */ public function __toString(): string { return $this->name . '=' . $this->value; } } <?php namespace Amp\Http\Cookie; final class InvalidCookieException extends \Exception { public function __construct(string $message) { parent::__construct($message); } } <?php namespace Amp\Http\Cookie; /** * Cookie attributes as defined in https://tools.ietf.org/html/rfc6265. * * @link https://tools.ietf.org/html/rfc6265 */ final class CookieAttributes { /** @var string */ private $path = ''; /** @var string */ private $domain = ''; /** @var int|null */ private $maxAge; /** @var \DateTimeImmutable */ private $expiry; /** @var bool */ private $secure = false; /** @var bool */ private $httpOnly = true; /** * @return CookieAttributes No cookie attributes. * * @see self::default() */ public static function empty(): self { $new = new self; $new->httpOnly = false; return $new; } /** * @return CookieAttributes Default cookie attributes, which means httpOnly is enabled by default. * * @see self::empty() */ public static function default(): self { return new self; } private function __construct() { // only allow creation via named constructors } /** * @param string $path Cookie path. * * @return self Cloned instance with the specified operation applied. Cloned instance with the specified operation applied. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.4 */ public function withPath(string $path): self { $new = clone $this; $new->path = $path; return $new; } /** * @param string $domain Cookie domain. * * @return self Cloned instance with the specified operation applied. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.3 */ public function withDomain(string $domain): self { $new = clone $this; $new->domain = $domain; return $new; } /** * Applies the given maximum age to the cookie. * * @param int $maxAge Cookie maximum age. * * @return self Cloned instance with the specified operation applied. * * @see self::withoutMaxAge() * @see self::withExpiry() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.2 */ public function withMaxAge(int $maxAge): self { $new = clone $this; $new->maxAge = $maxAge; return $new; } /** * Removes any max-age information. * * @return self Cloned instance with the specified operation applied. * * @see self::withMaxAge() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.2 */ public function withoutMaxAge(): self { $new = clone $this; $new->maxAge = null; return $new; } /** * Applies the given expiry to the cookie. * * @param \DateTimeInterface $date * * @return self Cloned instance with the specified operation applied. * * @see self::withMaxAge() * @see self::withoutExpiry() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.1 */ public function withExpiry(\DateTimeInterface $date): self { $new = clone $this; if ($date instanceof \DateTimeImmutable) { $new->expiry = $date; } elseif ($date instanceof \DateTime) { $new->expiry = \DateTimeImmutable::createFromMutable($date); } else { $new->expiry = new \DateTimeImmutable("@" . $date->getTimestamp()); } return $new; } /** * Removes any expiry information. * * @return self Cloned instance with the specified operation applied. * * @see self::withExpiry() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.1 */ public function withoutExpiry(): self { $new = clone $this; $new->expiry = null; return $new; } /** * @return self Cloned instance with the specified operation applied. * * @see self::withoutSecure() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.5 */ public function withSecure(): self { $new = clone $this; $new->secure = true; return $new; } /** * @return self Cloned instance with the specified operation applied. * * @see self::withSecure() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.5 */ public function withoutSecure(): self { $new = clone $this; $new->secure = false; return $new; } /** * @return self Cloned instance with the specified operation applied. * * @see self::withoutHttpOnly() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.6 */ public function withHttpOnly(): self { $new = clone $this; $new->httpOnly = true; return $new; } /** * @return self Cloned instance with the specified operation applied. * * @see self::withHttpOnly() * * @link https://tools.ietf.org/html/rfc6265#section-5.2.6 */ public function withoutHttpOnly(): self { $new = clone $this; $new->httpOnly = false; return $new; } /** * @return string Cookie path. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.4 */ public function getPath(): string { return $this->path; } /** * @return string Cookie domain. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.3 */ public function getDomain(): string { return $this->domain; } /** * @return int|null Cookie maximum age in seconds or `null` if no value is set. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.2 */ public function getMaxAge() { /* : ?int */ return $this->maxAge; } /** * @return \DateTimeImmutable|null Cookie expiry or `null` if no value is set. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.2 */ public function getExpiry() { /* : ?\DateTimeImmutable */ return $this->expiry; } /** * @return bool Whether the secure flag is enabled or not. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.5 */ public function isSecure(): bool { return $this->secure; } /** * @return bool Whether the httpOnly flag is enabled or not. * * @link https://tools.ietf.org/html/rfc6265#section-5.2.6 */ public function isHttpOnly(): bool { return $this->httpOnly; } /** * @return string Representation of the cookie attributes appended to key=value in a 'set-cookie' header. */ public function __toString(): string { $string = ''; if ($this->expiry) { $string .= '; Expires=' . \gmdate('D, j M Y G:i:s T', $this->expiry->getTimestamp()); } if ($this->maxAge) { $string .= '; Max-Age=' . $this->maxAge; } if ('' !== $this->path) { $string .= '; Path=' . $this->path; } if ('' !== $this->domain) { $string .= '; Domain=' . $this->domain; } if ($this->secure) { $string .= '; Secure'; } if ($this->httpOnly) { $string .= '; HttpOnly'; } return $string; } } <?php namespace Amp\Http; /** * @link https://tools.ietf.org/html/rfc7230 * @link https://tools.ietf.org/html/rfc2616 * @link https://tools.ietf.org/html/rfc5234 */ final class Rfc7230 { // We make use of possessive modifiers, which gives a slight performance boost const HEADER_NAME_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++)$)"; const HEADER_VALUE_REGEX = "(^[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+$)"; const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r\n)m"; const HEADER_FOLD_REGEX = "(\r\n[ \t]++)"; /** * Parses headers according to RFC 7230 and 2616. * * Allows empty header values, as HTTP/1.0 allows that. * * @param string $rawHeaders * * @return array Associative array mapping header names to arrays of values. * * @throws InvalidHeaderException If invalid headers have been passed. */ public static function parseHeaders(string $rawHeaders): array { // Ensure that the last line also ends with a newline, this is important. \assert(\substr($rawHeaders, -2) === "\r\n", "Argument 1 must end with CRLF"); /** @var array[] $matches */ $count = \preg_match_all(self::HEADER_REGEX, $rawHeaders, $matches, \PREG_SET_ORDER); // If these aren't the same, then one line didn't match and there's an invalid header. if ($count !== \substr_count($rawHeaders, "\n")) { // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4 if (\preg_match(self::HEADER_FOLD_REGEX, $rawHeaders)) { throw new InvalidHeaderException("Invalid header syntax: Obsolete line folding"); } throw new InvalidHeaderException("Invalid header syntax"); } $headers = []; foreach ($matches as $match) { // We avoid a call to \trim() here due to the regex. // Unfortunately, we can't avoid the \strtolower() calls due to \array_change_key_case() behavior // when equal headers are present with different casing, e.g. 'set-cookie' and 'Set-Cookie'. // Accessing matches directly instead of using foreach (... as list(...)) is slightly faster. $headers[\strtolower($match[1])][] = $match[2]; } return $headers; } /** * Format headers in to their on-the-wire format. * * Headers are always validated syntactically. This protects against response splitting and header injection * attacks. * * @param array $headers Headers in a format as returned by {@see parseHeaders()}. * * @return string Formatted headers. * * @throws InvalidHeaderException If header names or values are invalid. */ public static function formatHeaders(array $headers): string { $buffer = ""; $lines = 0; foreach ($headers as $name => $values) { // PHP casts integer-like keys to integers $name = (string) $name; // Ignore any HTTP/2 pseudo headers if ($name[0] === ":") { continue; } /** @var array $values */ foreach ($values as $value) { $buffer .= "{$name}: {$value}\r\n"; $lines++; } } $count = \preg_match_all(self::HEADER_REGEX, $buffer); if ($lines !== $count || $lines !== \substr_count($buffer, "\n")) { throw new InvalidHeaderException("Invalid headers"); } return $buffer; } } <?php namespace Amp\Http; /** * @link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml */ final class Status { const CONTINUE = 100; const SWITCHING_PROTOCOLS = 101; const PROCESSING = 102; const EARLY_HINTS = 103; const OK = 200; const CREATED = 201; const ACCEPTED = 202; const NON_AUTHORITATIVE_INFORMATION = 203; const NO_CONTENT = 204; const RESET_CONTENT = 205; const PARTIAL_CONTENT = 206; const MULTI_STATUS = 207; const ALREADY_REPORTED = 208; const IM_USED = 226; const MULTIPLE_CHOICES = 300; const MOVED_PERMANENTLY = 301; const FOUND = 302; const SEE_OTHER = 303; const NOT_MODIFIED = 304; const USE_PROXY = 305; const TEMPORARY_REDIRECT = 307; const PERMANENT_REDIRECT = 308; const BAD_REQUEST = 400; const UNAUTHORIZED = 401; const PAYMENT_REQUIRED = 402; const FORBIDDEN = 403; const NOT_FOUND = 404; const METHOD_NOT_ALLOWED = 405; const NOT_ACCEPTABLE = 406; const PROXY_AUTHENTICATION_REQUIRED = 407; const REQUEST_TIMEOUT = 408; const CONFLICT = 409; const GONE = 410; const LENGTH_REQUIRED = 411; const PRECONDITION_FAILED = 412; const PAYLOAD_TOO_LARGE = 413; const URI_TOO_LONG = 414; const UNSUPPORTED_MEDIA_TYPE = 415; const RANGE_NOT_SATISFIABLE = 416; const EXPECTATION_FAILED = 417; const MISDIRECTED_REQUEST = 421; const UNPROCESSABLE_ENTITY = 422; const LOCKED = 423; const FAILED_DEPENDENCY = 424; const UPGRADE_REQUIRED = 426; const PRECONDITION_REQUIRED = 428; const TOO_MANY_REQUESTS = 429; const REQUEST_HEADER_FIELDS_TOO_LARGE = 431; const UNAVAILABLE_FOR_LEGAL_REASONS = 451; const INTERNAL_SERVER_ERROR = 500; const NOT_IMPLEMENTED = 501; const BAD_GATEWAY = 502; const SERVICE_UNAVAILABLE = 503; const GATEWAY_TIMEOUT = 504; const HTTP_VERSION_NOT_SUPPORTED = 505; const VARIANT_ALSO_NEGOTIATES = 506; const INSUFFICIENT_STORAGE = 507; const LOOP_DETECTED = 508; const NOT_EXTENDED = 510; const NETWORK_AUTHENTICATION_REQUIRED = 511; // @codeCoverageIgnoreStart private function __construct() { // forbid instances } // @codeCoverageIgnoreEnd public static function getReason(int $code): string { return [ 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 103 => 'Early Hints', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 208 => 'Already Reported', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Payload Too Large', 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 421 => 'Misdirected Request', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 510 => 'Not Extended', 511 => 'Network Authentication Required', ][$code] ?? ''; } } <?php namespace Amp\Http; /** * Base class for HTTP request and response messages. */ abstract class Message { /** @var string[][] */ private $headers = []; /** * Returns the headers as a string-indexed array of arrays of strings or an empty array if no headers * have been set. * * @return string[][] */ public function getHeaders(): array { return $this->headers; } /** * Returns the array of values for the given header or an empty array if the header does not exist. * * @param string $name * * @return string[] */ public function getHeaderArray(string $name): array { return $this->headers[\strtolower($name)] ?? []; } /** * Returns the value of the given header. If multiple headers are present for the named header, only the first * header value will be returned. Use getHeaderArray() to return an array of all values for the particular header. * Returns null if the header does not exist. * * @param string $name * * @return string|null */ public function getHeader(string $name) { return $this->headers[\strtolower($name)][0] ?? null; } /** * Sets the headers from the given array. * * @param string[]|string[][] $headers */ protected function setHeaders(array $headers) { // Ensure this is an atomic operation, either all headers are set or none. $before = $this->headers; try { foreach ($headers as $name => $value) { $this->setHeader($name, $value); } } catch (\Throwable $e) { $this->headers = $before; throw $e; } } /** * Sets the named header to the given value. * * @param string $name * @param string|string[] $value * * @throws \Error If the header name or value is invalid. */ protected function setHeader(string $name, $value) { \assert($this->isNameValid($name), "Invalid header name"); if (\is_array($value)) { if (!$value) { $this->removeHeader($name); return; } $value = \array_values(\array_map("strval", $value)); } else { $value = [(string) $value]; } \assert($this->isValueValid($value), "Invalid header value"); $name = \strtolower($name); $this->headers[$name] = $value; } /** * Adds the value to the named header, or creates the header with the given value if it did not exist. * * @param string $name * @param string|string[] $value * * @throws \Error If the header name or value is invalid. */ protected function addHeader(string $name, $value) { \assert($this->isNameValid($name), "Invalid header name"); if (\is_array($value)) { if (!$value) { return; } $value = \array_values(\array_map("strval", $value)); } else { $value = [(string) $value]; } \assert($this->isValueValid($value), "Invalid header value"); $name = \strtolower($name); if (isset($this->headers[$name])) { $this->headers[$name] = \array_merge($this->headers[$name], $value); } else { $this->headers[$name] = $value; } } /** * Removes the given header if it exists. * * @param string $name */ protected function removeHeader(string $name) { unset($this->headers[\strtolower($name)]); } /** * Checks if given header exists. * * @param string $name * * @return bool */ public function hasHeader(string $name): bool { return isset($this->headers[\strtolower($name)]); } /** * @param string $name * * @return bool */ private function isNameValid(string $name): bool { return (bool) \preg_match('/^[A-Za-z0-9`~!#$%^&_|\'\-:]+$/', $name); } /** * Determines if the given value is a valid header value. * * @param string[] $values * * @return bool * * @throws \Error If the given value cannot be converted to a string and is not an array of values that can be * converted to strings. */ private function isValueValid(array $values): bool { foreach ($values as $value) { if (\preg_match("/[^\t\r\n\x20-\x7e\x80-\xfe]|\r\n/", $value)) { return false; } } return true; } } <?php namespace Amp\Http; final class InvalidHeaderException extends \Exception { /** * Thrown on header injection attempts. * * @param string $reason Reason that can be used as HTTP response reason. */ public function __construct(string $reason) { parent::__construct($reason); } } <?php use Amp\Artax\Response; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () { $uris = [ "https://google.com/", "https://github.com/", "https://stackoverflow.com/", ]; // Instantiate the HTTP client $client = new Amp\Artax\DefaultClient; $requestHandler = function (string $uri) use ($client) { /** @var Response $response */ $response = yield $client->request($uri); return $response->getBody(); }; try { $promises = []; foreach ($uris as $uri) { $promises[$uri] = Amp\call($requestHandler, $uri); } $bodies = yield $promises; foreach ($bodies as $uri => $body) { print $uri . " - " . \strlen($body) . " bytes" . PHP_EOL; } } catch (Amp\Artax\HttpException $error) { // If something goes wrong Amp will throw the exception where the promise was yielded. // The Client::request() method itself will never throw directly, but returns a promise. echo $error; } }); <?php use Amp\Artax\Request; use Amp\Artax\Response; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () { try { // Instantiate the HTTP client $client = new Amp\Artax\DefaultClient; // Here we create a custom request object instead of simply passing an URL to request(). $request = (new Request('https://httpbin.org/headers')) ->withHeader('X-Hello-World', 'Awesome \o/'); // Make an asynchronous HTTP request $promise = $client->request($request); // Client::request() is asynchronous! It doesn't return a response. Instead, it returns a promise to resolve the // response at some point in the future when we've received the headers of the response. Here we use yield which // pauses the execution of the current coroutine until the promise resolves. Amp will automatically continue the // coroutine then. /** @var Response $response */ $response = yield $promise; // Output the results printf( "HTTP/%s %d %s\n", $response->getProtocolVersion(), $response->getStatus(), $response->getReason() ); foreach ($response->getHeaders() as $field => $values) { foreach ($values as $value) { print "$field: $value\n"; } } print "\n"; // The response body is an instance of Message, which allows buffering or streaming by the consumers choice. // Simply yielding a Message buffers the complete response body. $body = yield $response->getBody(); print $body . "\n"; } catch (Amp\Artax\HttpException $error) { // If something goes wrong Amp will throw the exception where the promise was yielded. // The Client::request() method itself will never throw directly, but returns a promise. echo $error; } }); <?php use Amp\Artax\Response; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () use ($argv) { try { // Instantiate the HTTP client $client = new Amp\Artax\DefaultClient; // Make an asynchronous HTTP request $promise = $client->request($argv[1] ?? 'https://httpbin.org/user-agent'); // Client::request() is asynchronous! It doesn't return a response. Instead, it returns a promise to resolve the // response at some point in the future when we've received the headers of the response. Here we use yield which // pauses the execution of the current coroutine until the promise resolves. Amp will automatically continue the // coroutine then. /** @var Response $response */ $response = yield $promise; // Output the results printf( "HTTP/%s %d %s\n\n", $response->getProtocolVersion(), $response->getStatus(), $response->getReason() ); // The response body is an instance of Message, which allows buffering or streaming by the consumers choice. // Simply yielding a Message buffers the complete response body. $body = yield $response->getBody(); print $body . "\n"; } catch (Amp\Artax\HttpException $error) { // If something goes wrong Amp will throw the exception where the promise was yielded. // The Client::request() method itself will never throw directly, but returns a promise. echo $error; } }); <?php use Amp\Artax\Client; use Amp\Artax\Response; use Amp\File\Handle; use Amp\File\StatCache; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () { try { $start = microtime(1); // Instantiate the HTTP client $client = new Amp\Artax\DefaultClient; // Make an asynchronous HTTP request $promise = $client->request('http://speed.hetzner.de/100MB.bin', [ Client::OP_MAX_BODY_BYTES => 120 * 1024 * 1024 ]); // Client::request() is asynchronous! It doesn't return a response. Instead, it returns a promise to resolve the // response at some point in the future when we've received the headers of the response. Here we use yield which // pauses the execution of the current coroutine until the promise resolves. Amp will automatically continue the // coroutine then. /** @var Response $response */ $response = yield $promise; // Output the results printf( "HTTP/%s %d %s\n%s\n\n", $response->getProtocolVersion(), $response->getStatus(), $response->getReason(), $response->getRequest()->getUri() ); foreach ($response->getHeaders() as $field => $values) { foreach ($values as $value) { print "$field: $value\n"; } } print "\n"; $path = tempnam(sys_get_temp_dir(), "artax-streaming-"); /** @var Handle $file */ $file = yield Amp\File\open($path, "w"); // The response body is an instance of Message, which allows buffering or streaming by the consumers choice. // Pipe streams the body into the file, which is an instance of OutputStream. yield Amp\ByteStream\pipe($response->getBody(), $file); yield $file->close(); print sprintf( "Done in %.2f with peak memory usage of %.2fMB.\n", microtime(1) - $start, (float) memory_get_peak_usage(true) / 1024 / 1024 ); // We need to clear the stat cache, as we have just written to the file StatCache::clear($path); $size = yield Amp\File\size($path); print sprintf("%s has a size of %.2fMB\n", $path, (float) $size / 1024 / 1024); } catch (Amp\Artax\HttpException $error) { // If something goes wrong Amp will throw the exception where the promise was yielded. // The Client::request() method itself will never throw directly, but returns a promise. echo $error; } }); <?php use Amp\Artax\HttpSocketPool; use Amp\Artax\Request; use Amp\Artax\Response; use Amp\Loop; use Amp\Socket\StaticSocketPool; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () { try { // Unix sockets require a socket pool that changes all URLs to a fixed one. $socketPool = new StaticSocketPool("unix:///var/run/docker.sock"); $client = new Amp\Artax\DefaultClient(null, new HttpSocketPool($socketPool)); // Artax currently requires a host, so just use a dummy one. $request = new Request('http://docker/info'); $promise = $client->request($request); /** @var Response $response */ $response = yield $promise; printf( "HTTP/%s %d %s\n\n", $response->getProtocolVersion(), $response->getStatus(), $response->getReason() ); $body = yield $response->getBody(); print $body . "\n"; } catch (Amp\Artax\HttpException $error) { echo $error; } }); <?php // Usage ----------------------------------------------- // Default (10 x 100 requests): php examples/8-benchmark.php // Infinite (10 x 100 requests): php examples/8-benchmark.php 0 // Custom (10 x $count requests): php examples/8-benchmark.php $count use Amp\Artax\Client; use Amp\Artax\Response; use Amp\Loop; use function Amp\coroutine; require __DIR__ . '/../vendor/autoload.php'; $count = (int) ($argv[1] ?? "1000"); Loop::run(function () use ($count) { $client = new Amp\Artax\DefaultClient; $client->setOption(Client::OP_TRANSFER_TIMEOUT, 50000); $handler = coroutine(function (int $count) use ($client) { for ($i = 0; $i < $count; $i++) { /** @var Response $response */ $response = yield $client->request('http://localhost:1337/'); yield $response->getBody(); } }); do { $promises = []; for ($i = 0; $i < 10; $i++) { $promises[] = $handler($count === 0 ? 100 : $count); } yield $promises; gc_collect_cycles(); gc_mem_caches(); print "Memory: " . (memory_get_usage(true) / 1000) . PHP_EOL; } while ($count === 0); }); <?php use Amp\Artax\FormBody; use Amp\Artax\Request; use Amp\Artax\Response; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () { try { // Instantiate the HTTP client $client = new Amp\Artax\DefaultClient; // Here we create a custom request object instead of simply passing an URL to request(). // We set the method to POST and add a FormBody to submit a form. $body = new FormBody; $body->addField("search", "foobar"); $body->addField("submit", "ok"); $body->addFile("foo", __DIR__ . "/small-file.txt"); $request = (new Request('https://httpbin.org/post', 'POST')) ->withBody($body); // Make an asynchronous HTTP request $promise = $client->request($request); // Client::request() is asynchronous! It doesn't return a response. Instead, it returns a promise to resolve the // response at some point in the future when we've received the headers of the response. Here we use yield which // pauses the execution of the current coroutine until the promise resolves. Amp will automatically continue the // coroutine then. /** @var Response $response */ $response = yield $promise; // Output the results printf( "HTTP/%s %d %s\n\n", $response->getProtocolVersion(), $response->getStatus(), $response->getReason() ); // The response body is an instance of Message, which allows buffering or streaming by the consumers choice. // Simply yielding a Message buffers the complete response body. $body = yield $response->getBody(); print $body . "\n"; } catch (Amp\Artax\HttpException $error) { // If something goes wrong Amp will throw the exception where the promise was yielded. // The Client::request() method itself will never throw directly, but returns a promise. echo $error; } }); <?php use Amp\Artax\Request; use Amp\Artax\Response; use Amp\Loop; require __DIR__ . '/../vendor/autoload.php'; Loop::run(function () { try { // Instantiate the HTTP client $client = new Amp\Artax\DefaultClient; // Here we create a custom request object instead of simply passing an URL to request(). // We set the method to POST now and add a request body. $request = (new Request('https://httpbin.org/post', 'POST')) ->withBody('woot \o/'); // Make an asynchronous HTTP request $promise = $client->request($request); // Client::request() is asynchronous! It doesn't return a response. Instead, it returns a promise to resolve the // response at some point in the future when we've received the headers of the response. Here we use yield which // pauses the execution of the current coroutine until the promise resolves. Amp will automatically continue the // coroutine then. /** @var Response $response */ $response = yield $promise; // Output the results printf( "HTTP/%s %d %s\n\n", $response->getProtocolVersion(), $response->getStatus(), $response->getReason() ); // The response body is an instance of Message, which allows buffering or streaming by the consumers choice. // Simply yielding a Message buffers the complete response body. $body = yield $response->getBody(); print $body . "\n"; } catch (Amp\Artax\HttpException $error) { // If something goes wrong Amp will throw the exception where the promise was yielded. // The Client::request() method itself will never throw directly, but returns a promise. echo $error; } }); { "name": "amphp/artax", "homepage": "https://github.com/amphp/artax", "description": "Asynchronous parallel HTTP/1.1 client built on the Amp concurrency framework", "keywords": [ "http", "rest", "client", "parallel", "async", "non-blocking" ], "license": "MIT", "authors": [ { "name": "Daniel Lowrey", "email": "rdlowrey@gmail.com" }, { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "require": { "php": ">=7.0", "amphp/amp": "^2", "amphp/byte-stream": "^1.1.6", "amphp/socket": "^0.10.5", "amphp/uri": "^0.1", "amphp/file": "^0.2 || ^0.3", "kelunik/certificate": "^1.1" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "friendsofphp/php-cs-fixer": "^2.3", "amphp/http-server": "^1" }, "autoload": { "psr-4": { "Amp\\Artax\\": "lib" } }, "autoload-dev": { "psr-4": { "Amp\\Test\\Artax\\": "test" } }, "config": { "platform": { "php": "7.0.0" } } } <?php namespace Amp\Test\Artax\Cookie; use Amp\Artax\Cookie\ArrayCookieJar; use Amp\Artax\Cookie\Cookie; use Amp\Artax\Cookie\CookieJar; use PHPUnit\Framework\TestCase; class ArrayCookieJarTest extends TestCase { /** @var CookieJar */ private $jar; public function setUp() { $this->jar = new ArrayCookieJar; } /** @dataProvider provideCookieDomainMatchData */ public function testCookieDomainMatching(Cookie $cookie, $domain, $returned) { $this->jar->store($cookie); if ($returned) { $this->assertSame([$cookie], $this->jar->get($domain)); } else { $this->assertSame([], $this->jar->get($domain)); } } public function provideCookieDomainMatchData() { // See http://stackoverflow.com/a/1063760/2373138 for cases return [ [new Cookie("foo", "bar", null, "/", ".foo.bar.example.com"), "foo.bar", false], /* previous security issue */ [new Cookie("foo", "bar", null, "/", ".example.com"), "example.com", true], [new Cookie("foo", "bar", null, "/", ".example.com"), "www.example.com", true], [new Cookie("foo", "bar", null, "/", "example.com"), "example.com", true], [new Cookie("foo", "bar", null, "/", "example.com"), "www.example.com", false], [new Cookie("foo", "bar", null, "/", "example.com"), "anotherexample.com", false], [new Cookie("foo", "bar", null, "/", "anotherexample.com"), "example.com", false], ]; } } <?php namespace Amp\Test\Artax\Cookie; use Amp\Artax\Cookie\Cookie; use Amp\Artax\Cookie\CookieFormatException; use PHPUnit\Framework\TestCase; class CookieTest extends TestCase { public function testGetters() { $cookie = new Cookie("name", "value", null, null, "example.com", true, false); $this->assertSame("name", $cookie->getName()); $this->assertSame("value", $cookie->getValue()); $this->assertNull(null, $cookie->getExpirationTime()); $this->assertSame("/", $cookie->getPath()); $this->assertSame("example.com", $cookie->getDomain()); $this->assertTrue($cookie->isSecure()); $this->assertFalse($cookie->isHttpOnly()); } public function testSetters() { $cookie = new Cookie("name", "value", null, null, "example.com", true, false); $new = $cookie->withName("name2"); $this->assertSame("name", $cookie->getName()); $this->assertSame("name2", $new->getName()); $new = $cookie->withValue("value2"); $this->assertSame("value", $cookie->getValue()); $this->assertSame("value2", $new->getValue()); $new = $cookie->withExpirationTime(42); $this->assertNull($cookie->getExpirationTime()); $this->assertSame(42, $new->getExpirationTime()); $new = $cookie->withPath("/foobar"); $this->assertSame("/", $cookie->getPath()); $this->assertSame("/foobar", $new->getPath()); $new = $cookie->withDomain("example.net"); $this->assertSame("example.com", $cookie->getDomain()); $this->assertSame("example.net", $new->getDomain()); $new = $cookie->withSecure(false); $this->assertTrue($cookie->isSecure()); $this->assertFalse($new->isSecure()); $new = $cookie->withHttpOnly(true); $this->assertFalse($cookie->isHttpOnly()); $this->assertTrue($new->isHttpOnly()); } public function testEmptyCookieStringThrows() { $this->expectException(CookieFormatException::class); $this->expectExceptionMessage("Empty cookie string"); Cookie::fromString(""); } public function testMissingEqualsSignThrows() { $this->expectException(CookieFormatException::class); $this->expectExceptionMessage("Missing '=' to separate name and value"); Cookie::fromString("name"); } public function testEmptyNameThrows() { $this->expectException(CookieFormatException::class); $this->expectExceptionMessage("Empty name"); Cookie::fromString("=value"); } public function testValidCookieParse() { $cookie = Cookie::fromString("cookie_name2=cookie_value2; expires=Sun, 16 Jul 3567 06:23:41 GMT"); $this->assertSame("cookie_name2", $cookie->getName()); $this->assertSame("cookie_value2", $cookie->getValue()); $this->assertNotNull($cookie->getExpirationTime()); $this->assertFalse($cookie->isHttpOnly()); $this->assertFalse($cookie->isSecure()); $this->assertSame("/", $cookie->getPath()); $this->assertSame("", $cookie->getDomain()); $this->assertFalse($cookie->isExpired()); } public function testValidCookieParseAndStringify() { $cookie1 = Cookie::fromString("cookie_name2=cookie_value2; expires=Sun, 16 Jul 3567 06:23:41 GMT; secure; hTTPonly; unknown; domain=example.com"); $cookie2 = Cookie::fromString((string) $cookie1); foreach ([$cookie1, $cookie2] as $cookie) { $this->assertSame("cookie_name2", $cookie->getName()); $this->assertSame("cookie_value2", $cookie->getValue()); $this->assertNotNull($cookie->getExpirationTime()); $this->assertTrue($cookie->isHttpOnly()); $this->assertTrue($cookie->isSecure()); $this->assertSame("/", $cookie->getPath()); $this->assertSame("example.com", $cookie->getDomain()); $this->assertFalse($cookie->isExpired()); } } public function testMaxAge() { $cookie = Cookie::fromString("cookie_name2=cookie_value2; max-age=1"); $this->assertFalse($cookie->isExpired()); // TODO: Don't sleep here, test differently sleep(2); $this->assertTrue($cookie->isExpired()); } public function testInvalidDate() { $this->expectException(CookieFormatException::class); Cookie::fromString("cookie_name2=cookie_value2; expires=1"); } } <?php namespace Amp\Test\Artax\Cookie; use Amp\Artax\Cookie\ArrayCookieJar; use Amp\Artax\Cookie\Cookie; use Amp\Artax\Cookie\CookieJar; use Amp\Artax\DefaultClient; use PHPUnit\Framework\TestCase; class ClientCookieTest extends TestCase { /** @var DefaultClient */ private $client; /** @var CookieJar */ private $jar; public function setUp() { $this->jar = new ArrayCookieJar; $this->client = new DefaultClient($this->jar); } /** @dataProvider provideCookieDomainMatchData */ public function testCookieAccepting(Cookie $cookie, string $requestDomain, bool $accept) { $method = (new \ReflectionClass($this->client))->getMethod("storeResponseCookie"); $method->setAccessible(true); $method->invoke($this->client, $requestDomain, (string) $cookie); if ($accept) { $this->assertCount(1, $this->jar->getAll()); } else { $this->assertSame([], $this->jar->getAll()); } } public function provideCookieDomainMatchData() { return [ [new Cookie("foo", "bar", null, "/", ".foo.bar.example.com"), "foo.bar", false], [new Cookie("foo", "bar", null, "/", ".example.com"), "example.com", true], [new Cookie("foo", "bar", null, "/", ".example.com"), "www.example.com", true], [new Cookie("foo", "bar", null, "/", "example.com"), "example.com", true], [new Cookie("foo", "bar", null, "/", "example.com"), "www.example.com", true], [new Cookie("foo", "bar", null, "/", "example.com"), "anotherexample.com", false], [new Cookie("foo", "bar", null, "/", "anotherexample.com"), "example.com", false], [new Cookie("foo", "bar", null, "/", "com"), "anotherexample.com", false], [new Cookie("foo", "bar", null, "/", ".com"), "anotherexample.com", false], [new Cookie("foo", "bar", null, "/", ""), "example.com", true], ]; } } <?php namespace Amp\Artax\Test; use Amp\Artax\Request; use Amp\Artax\StringBody; use Amp\PHPUnit\TestCase; class RequestTest extends TestCase { public function provideInvalidProtocolVersions() { return [ ["HTTP/1.0"], ["HTTP/1.1"], ["HTTP 1.0"], ["3.0"], ["1.2"], ]; } /** @dataProvider provideInvalidProtocolVersions */ public function testProtocolVersionsAcceptsNoInvalidValues($invalidVersion) { $this->expectException(\Error::class); $this->expectExceptionMessage("Invalid HTTP protocol version"); (new Request("http://127.0.0.1/"))->withProtocolVersions([$invalidVersion]); } public function testProtocolVersionsAcceptsNoEmptyArray() { $this->expectException(\Error::class); $this->expectExceptionMessage("Empty array of protocol versions provided, must not be empty."); (new Request("http://127.0.0.1/"))->withProtocolVersions([]); } public function testProtocolVersionsAcceptsValidInput() { $request = (new Request("http://127.0.0.1/"))->withProtocolVersions(["1.0"]); $this->assertSame(["1.0"], $request->getProtocolVersions()); $request = (new Request("http://127.0.0.1/"))->withProtocolVersions(["1.0", "2.0"]); $this->assertSame(["1.0", "2.0"], $request->getProtocolVersions()); } public function testProtocolVersionsReturnsSameInstanceWithoutChange() { $request1 = (new Request("http://127.0.0.1/"))->withProtocolVersions(["1.0"]); $request2 = $request1->withProtocolVersions(["1.0"]); $this->assertSame($request1, $request2); } public function testMethodReturnsSameInstanceWithoutChange() { $request1 = new Request("http://127.0.0.1/"); $request2 = $request1->withMethod("GET"); $this->assertSame($request1, $request2); } public function testHeader() { /** @var Request $request */ $request = new Request("http://127.0.0.1/"); $this->assertNull($request->getHeader("X-Foo")); $this->assertSame([], $request->getHeaderArray("X-Foo")); $request = $request->withHeader("x-FOO", "bar"); $this->assertSame("bar", $request->getHeader("X-Foo")); $this->assertSame(["bar"], $request->getHeaderArray("X-Foo")); $request = $request->withAddedHeader("x-FOO", "baz"); $this->assertSame("bar", $request->getHeader("X-Foo")); $this->assertSame(["bar", "baz"], $request->getHeaderArray("X-Foo")); $request = $request->withHeader("x-FOO", "bar"); $this->assertSame("bar", $request->getHeader("X-Foo")); $this->assertSame(["bar"], $request->getHeaderArray("X-Foo")); $this->assertSame([ "x-foo" => ["bar"] ], $request->getHeaders()); $request = $request->withHeaders([ "x-hello-world" => "xx", "x-goodbye" => ["yy", "zzz"], ]); $this->assertSame([ "x-foo" => ["bar"], "x-hello-world" => ["xx"], "x-goodbye" => ["yy", "zzz"], ], $request->getHeaders()); // Empty array deletes $request = $request->withHeaders([ "x-hello-world" => [], ]); $this->assertSame([ "x-foo" => ["bar"], "x-goodbye" => ["yy", "zzz"], ], $request->getHeaders()); $this->assertSame([ "x-FOO" => ["bar"], "x-goodbye" => ["yy", "zzz"], ], $request->getHeaders(true)); } public function provideBadAllHeaderInput() { return [ [[ "text" => [null], ]], [[ "text" => null, ]] ]; } /** @dataProvider provideBadAllHeaderInput */ public function testAllHeaders($input) { $this->expectException(\TypeError::class); (new Request("http://127.0.0.1/"))->withHeaders($input); } public function testBody() { /** @var Request $request */ $request = new Request("http://127.0.0.1/"); $this->assertInstanceOf(StringBody::class, $request->getBody()); $request = $request->withBody(null); $this->assertInstanceOf(StringBody::class, $request->getBody()); $request = $request->withBody("foobar"); $this->assertInstanceOf(StringBody::class, $request->getBody()); $this->expectException(\TypeError::class); $request->withBody(new \stdClass); } } <?php namespace Amp\Artax\Test; use Amp\Artax\Internal\Parser; use PHPUnit\Framework\TestCase; class ParserTest extends TestCase { /** * @dataProvider provideParseExpectations */ public function testParse($msg, $method, $uri, $protocol, $headers, $body) { $actualBody = ""; $msgParser = new Parser(static function ($chunk) use (&$actualBody) { $actualBody .= $chunk; }, Parser::MODE_REQUEST); $parsedRequestArr = $msgParser->parse($msg); if ($parsedRequestArr["headersOnly"]) { $msgParser->parse(); } $this->assertEquals($method, $parsedRequestArr['method']); $this->assertEquals($uri, $parsedRequestArr['uri']); $this->assertEquals($protocol, $parsedRequestArr['protocol']); $this->assertEquals($headers, $parsedRequestArr['headers']); $this->assertEquals($body, $actualBody); } public function testKeepAliveHeadResponseParse() { $request = "HTTP/1.1 200 OK\n\n"; $msgParser = new Parser(null, Parser::MODE_RESPONSE); $msgParser->enqueueResponseMethodMatch('HEAD'); $parsedResponseArr = $msgParser->parse($request); $this->assertEquals(200, $parsedResponseArr['status']); } /** * @dataProvider provideParseExpectations */ public function testIncrementalParse($msg, $method, $uri, $protocol, $headers, $body) { $actualBody = ""; $msgParser = new Parser(static function ($chunk) use (&$actualBody) { $actualBody .= $chunk; }, Parser::MODE_REQUEST); $byteIncrement = 1; $msgLen = strlen($msg); $headers = null; for ($i = 0; $i < $msgLen; $i += $byteIncrement) { $msgPart = $msg[$i]; $parsedRequestArr = $msgParser->parse($msgPart); if (is_array($parsedRequestArr)) { if ($headers === null) { $headers = $parsedRequestArr["headers"]; } if (!$parsedRequestArr["headersOnly"]) { break; } } } $parsedRequestArr["headers"] = $headers; /** @var array $parsedRequestArr */ $this->assertInternalType("array", $parsedRequestArr); $this->assertEquals($method, $parsedRequestArr['method']); $this->assertEquals($uri, $parsedRequestArr['uri']); $this->assertEquals($protocol, $parsedRequestArr['protocol']); $this->assertEquals($headers, $parsedRequestArr['headers']); $this->assertEquals($body, $actualBody); } public function provideParseExpectations() { $return = []; // 0 --------------------------------------------------------------------------------------> $msg = "" . "GET / HTTP/1.1" . "\r\n" . "Host: localhost:80" . "\r\n" . "\r\n"; $method = 'GET'; $uri = '/'; $protocol = '1.1'; $headers = ['Host' => ['localhost:80']]; $body = null; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // 1 --------------------------------------------------------------------------------------> $msg = "" . "POST /post-endpoint HTTP/1.0" . "\r\n" . "Host: localhost" . "\r\n" . "Cookie: cookie1" . "\r\n" . "Cookie: cookie2" . "\r\n" . "Content-Length: 3" . "\r\n" . "\r\n" . "123"; $method = 'POST'; $uri = '/post-endpoint'; $protocol = '1.0'; $headers = [ 'Host' => ['localhost'], 'Cookie' => ['cookie1', 'cookie2'], 'Content-Length' => [3], ]; $body = '123'; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // 2 --------------------------------------------------------------------------------------> $msg = "" . "OPTIONS * HTTP/1.0" . "\r\n" . "\r\n"; $method = 'OPTIONS'; $uri = '*'; $protocol = '1.0'; $headers = []; $body = null; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // 3 --------------------------------------------------------------------------------------> $msg = "" . "GET /test HTTP/1.1\r\n" . "Host: localhost\r\n" . "Transfer-Encoding: chunked\r\n" . "\r\n" . "00000\r\n\r\n"; $method = 'GET'; $uri = '/test'; $protocol = '1.1'; $headers = [ 'Host' => ['localhost'], 'Transfer-Encoding' => ['chunked'], ]; $body = null; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // 4 --------------------------------------------------------------------------------------> $len = 1992; $body = str_repeat('x', $len); $msg = '' . "GET /test HTTP/1.1\r\n" . "Host: localhost\r\n" . "Connection: keep-alive\r\n" . "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11\r\n" . "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" . "Accept-Encoding: gzip,deflate,sdch\r\n" . "Accept-Language: en-US,en;q=0.8\r\n" . "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n" . "Content-Length: {$len}\r\n" . "\r\n" . "{$body}"; $method = 'GET'; $uri = '/test'; $protocol = '1.1'; $headers = [ 'Host' => ['localhost'], 'Connection' => ['keep-alive'], 'User-Agent' => ['Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11'], 'Accept' => ['text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'], 'Accept-Encoding' => ['gzip,deflate,sdch'], 'Accept-Language' => ['en-US,en;q=0.8'], 'Accept-Charset' => ['ISO-8859-1,utf-8;q=0.7,*;q=0.3'], 'Content-Length' => [$len], ]; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // 5 --------------------------------------------------------------------------------------> $msg = "" . "GET /test HTTP/1.1\r\n" . "Host: localhost\r\n" . "Header-Lws-Split: line1\r\n" . "\t\x20line2\r\n" . "\x20\x20line3\n" . "\x20line4\r\n" . "\tline5\r\n" . "\r\n"; $method = 'GET'; $uri = '/test'; $protocol = '1.1'; $headers = [ 'Host' => ['localhost'], 'Header-Lws-Split' => ['line1 line2 line3 line4 line5'], ]; $body = null; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // 6 --------------------------------------------------------------------------------------> $msg = "" . "GET /test HTTP/1.1\r\n" . "Host: localhost\r\n" . "Transfer-Encoding: chunked\r\n" . "\r\n" . "5\r\n" . "woot!\r\n" . "4\r\n" . "test\r\n" . "0\r\n" . "My-Trailer: testval\r\n" . "\r\n"; $method = 'GET'; $uri = '/test'; $protocol = '1.1'; $headers = [ 'Host' => ['localhost'], 'Transfer-Encoding' => ['chunked'], /* Trailers are ignored: 'My-Trailer' => ['testval'], */ ]; $body = 'woot!test'; $return[] = [$msg, $method, $uri, $protocol, $headers, $body]; // x --------------------------------------------------------------------------------------> return $return; } } <?php namespace Amp\Test\Artax\Cookie; use Amp\Artax\Internal\PublicSuffixList; use PHPUnit\Framework\TestCase; class PublicSuffixListTest extends TestCase { /** * @dataProvider provideTestData * @requires extension intl */ public function testWithData($domain, $expectation) { $this->assertSame($expectation, PublicSuffixList::isPublicSuffix($domain)); } public function provideTestData() { $lines = \file(__DIR__ . "/fixture/public_suffix_list_tests.txt", \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); $lines = \array_filter($lines, function ($line) { return \substr($line, 0, 2) !== "//"; }); return \array_map(function ($line) { $parts = \explode(" ", $line); return [ $parts[0], (bool) $parts[1], ]; }, $lines); } } <?php namespace Amp\Test\Artax; use Amp\Artax\Client; use Amp\Artax\DefaultClient; use Amp\Artax\HttpSocketPool; use Amp\Artax\Response; use Amp\Artax\TimeoutException; use Amp\CancellationToken; use Amp\Deferred; use Amp\Loop; use Amp\PHPUnit\TestCase; use Amp\Promise; use Amp\Socket; use Amp\Socket\ClientSocket; use function Amp\asyncCall; use function Amp\Promise\wait; class TimeoutTest extends TestCase { /** @var DefaultClient */ private $client; public function setUp() { $this->client = new DefaultClient; } public function testTimeoutDuringBody() { $server = Socket\listen("tcp://127.0.0.1:0"); asyncCall(function () use ($server) { /** @var Socket\ClientSocket $client */ while ($client = yield $server->accept()) { yield $client->write("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\n."); Loop::delay(3000, function () use ($client) { $client->close(); }); } }); try { $uri = "http://" . $server->getAddress() . "/"; $start = \microtime(true); $promise = $this->client->request($uri, [Client::OP_TRANSFER_TIMEOUT => 100]); /** @var Response $response */ $response = wait($promise); $this->expectException(TimeoutException::class); $this->expectExceptionMessage("Allowed transfer timeout exceeded: 100 ms"); wait($response->getBody()); } finally { $this->assertLessThan(0.6, \microtime(true) - $start); $server->close(); } } public function testTimeoutDuringConnect() { Loop::repeat(1000, function () { /* dummy watcher, because socket pool doesn't do anything */ }); $this->client = new DefaultClient(null, new HttpSocketPool(new class implements Socket\SocketPool { public function checkout(string $uri, CancellationToken $token = null): Promise { $deferred = new Deferred; if ($token) { $token->subscribe(function ($error) use ($deferred) { $deferred->fail($error); }); } return $deferred->promise(); // never resolve } public function checkin(ClientSocket $socket) { // ignore } public function clear(ClientSocket $socket) { // ignore } })); $this->expectException(TimeoutException::class); $this->expectExceptionMessage("Allowed transfer timeout exceeded: 100 ms"); $this->assertRunTimeLessThan(function () { wait($this->client->request("http://localhost:1337/", [Client::OP_TRANSFER_TIMEOUT => 100])); }, 600); } public function testTimeoutDuringTlsEnable() { $tlsContext = (new Socket\ServerTlsContext) ->withDefaultCertificate(new Socket\Certificate(__DIR__ . "/tls/amphp.org.pem")); $server = Socket\listen("tcp://127.0.0.1:0", null, $tlsContext); asyncCall(function () use ($server) { /** @var Socket\ClientSocket $client */ while ($client = yield $server->accept()) { Loop::delay(3000, function () use ($client) { $client->close(); }); } }); try { $uri = "http://" . $server->getAddress() . "/"; $start = \microtime(true); $promise = $this->client->request($uri, [Client::OP_TRANSFER_TIMEOUT => 100]); $this->expectException(TimeoutException::class); $this->expectExceptionMessage("Allowed transfer timeout exceeded: 100 ms"); wait($promise); } finally { $this->assertLessThan(0.6, \microtime(true) - $start); $server->close(); } } } <?php namespace Amp\Artax\Test; use Amp\Artax\Client; use Amp\Artax\DefaultClient; use Amp\Artax\FileBody; use Amp\Artax\FormBody; use Amp\Artax\HttpException; use Amp\Artax\Request; use Amp\Artax\RequestBody; use Amp\Artax\Response; use Amp\Artax\SocketException; use Amp\Artax\TooManyRedirectsException; use Amp\ByteStream\InMemoryStream; use Amp\ByteStream\InputStream; use Amp\ByteStream\IteratorStream; use Amp\CancellationTokenSource; use Amp\CancelledException; use Amp\Delayed; use Amp\Http\Server\RequestHandler\CallableRequestHandler; use Amp\Http\Server\Server; use Amp\Http\Status; use Amp\Producer; use Amp\Promise; use Amp\Socket; use Amp\Success; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; use function Amp\asyncCall; use function Amp\Iterator\fromIterable; use function Amp\Promise\wait; class ClientHttpBinIntegrationTest extends TestCase { /** @var Socket\Server */ private $socket; private $server; public function testHttp10Response() { $client = new DefaultClient; $server = Socket\listen("tcp://127.0.0.1:0/"); asyncCall(function () use ($server) { $client = yield $server->accept(); yield $client->end("HTTP/1.0 200 OK\r\n\r\n"); }); $uri = "http://" . $server->getAddress(); $promise = $client->request((new Request($uri))->withProtocolVersions(["1.0"])); $response = wait($promise); $this->assertInstanceOf(Response::class, $response); $this->assertSame("", wait($response->getBody())); } public function testCloseAfterConnect() { $client = new DefaultClient; $server = Socket\listen("tcp://127.0.0.1:0"); asyncCall(function () use ($server) { while ($client = yield $server->accept()) { $client->close(); } }); try { $uri = "http://" . $server->getAddress() . "/"; $promise = $client->request((new Request($uri))->withProtocolVersions(["1.0"])); $this->expectException(SocketException::class); $this->expectExceptionMessage("Failed to read response from server"); wait($promise); } finally { $server->close(); } } public function testIncompleteHttpResponseWithContentLength() { $client = new DefaultClient; $server = Socket\listen("tcp://127.0.0.1:0"); asyncCall(function () use ($server) { while ($client = yield $server->accept()) { yield $client->end("HTTP/1.0 200 OK\r\nContent-Length: 2\r\n\r\n."); } }); try { $uri = "http://" . $server->getAddress() . "/"; $promise = $client->request((new Request($uri))->withProtocolVersions(["1.0"])); $this->expectException(SocketException::class); $this->expectExceptionMessage("Socket disconnected prior to response completion (Parser state: 1)"); $response = wait($promise); wait($response->getBody()); } finally { $server->close(); } } public function testIncompleteHttpResponseWithChunkedEncoding() { $client = new DefaultClient; $server = Socket\listen("tcp://127.0.0.1:0"); asyncCall(function () use ($server) { while ($client = yield $server->accept()) { yield $client->end("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r"); // missing \n } }); try { $uri = "http://" . $server->getAddress() . "/"; $promise = $client->request((new Request($uri))->withProtocolVersions(["1.0"])); $this->expectException(SocketException::class); $this->expectExceptionMessage("Socket disconnected prior to response completion (Parser state: 3)"); $response = wait($promise); wait($response->getBody()); } finally { $server->close(); } } public function testIncompleteHttpResponseWithoutChunkedEncodingAndWithoutContentLength() { $client = new DefaultClient; $server = Socket\listen("tcp://127.0.0.1:0"); asyncCall(function () use ($server) { while ($client = yield $server->accept()) { yield $client->end("HTTP/1.1 200 OK\r\n\r\n00000000000"); } }); try { $uri = "http://" . $server->getAddress() . "/"; $promise = $client->request((new Request($uri))->withProtocolVersions(["1.0"])); $response = wait($promise); $this->assertSame("00000000000", wait($response->getBody())); } finally { $server->close(); } } public function testDefaultUserAgentSent() { $uri = 'http://httpbin.org/user-agent'; $client = new DefaultClient; $promise = $client->request($uri); $response = wait($promise); $this->assertInstanceOf(Response::class, $response); $body = wait($response->getBody()); $result = json_decode($body); $this->assertSame(DefaultClient::DEFAULT_USER_AGENT, $result->{'user-agent'}); } public function testCustomUserAgentSentIfAssigned() { $uri = 'http://httpbin.org/user-agent'; $client = new DefaultClient; $customUserAgent = 'test-user-agent'; $request = (new Request($uri))->withHeader('User-Agent', $customUserAgent); $promise = $client->request($request); $response = wait($promise); $this->assertInstanceOf(Response::class, $response); $body = wait($response->getBody()); $result = json_decode($body); $this->assertSame($customUserAgent, $result->{'user-agent'}); } public function testCustomUserAgentSentIfAssignedViaDefaultHeaders() { $customUserAgent = 'test-user-agent'; $uri = 'http://httpbin.org/user-agent'; $client = new DefaultClient; $client->setOption(Client::OP_DEFAULT_HEADERS, [ "user-agent" => $customUserAgent, ]); $promise = $client->request($uri); $response = wait($promise); $this->assertInstanceOf(Response::class, $response); $body = wait($response->getBody()); $result = json_decode($body); $this->assertSame($customUserAgent, $result->{'user-agent'}); } public function testPostStringBody() { $client = new DefaultClient; $body = 'zanzibar'; $request = (new Request('http://httpbin.org/post'))->withMethod('POST')->withBody($body); $response = wait($client->request($request)); $this->assertInstanceOf(Response::class, $response); $result = json_decode(wait($response->getBody())); $this->assertEquals($body, $result->data); } public function testPutStringBody() { $uri = 'http://httpbin.org/put'; $client = new DefaultClient; $body = 'zanzibar'; $request = (new Request($uri, "PUT"))->withBody($body); $response = wait($client->request($request)); $this->assertInstanceOf(Response::class, $response); $result = json_decode(wait($response->getBody())); $this->assertEquals($body, $result->data); } /** * @dataProvider provideStatusCodes */ public function testStatusCodeResponses($statusCode) { $client = new DefaultClient; $response = wait($client->request("http://httpbin.org/status/{$statusCode}")); $this->assertInstanceOf(Response::class, $response); $this->assertEquals($statusCode, $response->getStatus()); } public function provideStatusCodes(): array { return [ [200], [400], [404], [500], ]; } public function testReason() { $client = new DefaultClient; $response = wait($client->request("http://httpbin.org/status/418")); $this->assertInstanceOf(Response::class, $response); $expectedReason = "I'M A TEAPOT"; $actualReason = $response->getReason(); $this->assertSame($expectedReason, $actualReason); } public function testRedirect() { $statusCode = 299; $redirectTo = "/status/{$statusCode}"; $uri = "http://httpbin.org/redirect-to?url=" . \rawurlencode($redirectTo); $client = new DefaultClient; $response = wait($client->request($uri)); $this->assertInstanceOf(Response::class, $response); $this->assertEquals($statusCode, $response->getStatus()); $originalUri = $response->getOriginalRequest()->getUri(); $this->assertSame($uri, $originalUri); } public function testClientAddsZeroContentLengthHeaderForEmptyBodiesOnPost() { $uri = 'http://httpbin.org/post'; $client = new DefaultClient; $request = (new Request($uri))->withMethod('POST'); $promise = $client->request($request); $response = wait($promise); $this->assertInstanceOf(Response::class, $response); $body = wait($response->getBody()); $result = json_decode($body); $this->assertEquals('0', $result->headers->{'Content-Length'}); } public function testFormEncodedBodyRequest() { $client = new DefaultClient; $body = new FormBody; $field1 = 'test val'; $field2 = 'val2'; $body->addField('field1', $field1); $body->addField('field2', $field2); $request = (new Request('http://httpbin.org/post', "POST"))->withBody($body); $response = wait($client->request($request)); $this->assertInstanceOf(Response::class, $response); $result = json_decode(wait($response->getBody()), true); $this->assertEquals($field1, $result['form']['field1']); $this->assertEquals($field2, $result['form']['field2']); $this->assertEquals('application/x-www-form-urlencoded', $result['headers']['Content-Type']); } public function testFileBodyRequest() { $uri = 'http://httpbin.org/post'; $client = new DefaultClient; $bodyPath = __DIR__ . '/fixture/answer.txt'; $body = new FileBody($bodyPath); $request = (new Request($uri, "POST"))->withBody($body); $response = wait($client->request($request)); $this->assertInstanceOf(Response::class, $response); $result = json_decode(wait($response->getBody()), true); $this->assertEquals(file_get_contents($bodyPath), $result['data']); } public function testMultipartBodyRequest() { $client = new DefaultClient; $field1 = 'test val'; $file1 = __DIR__ . '/fixture/lorem.txt'; $file2 = __DIR__ . '/fixture/answer.txt'; $boundary = 'AaB03x'; $body = new FormBody($boundary); $body->addFields(['field1' => $field1]); $body->addFiles(['file1' => $file1, 'file2' => $file2]); $request = (new Request('http://httpbin.org/post', "POST"))->withBody($body); $response = wait($client->request($request)); $this->assertEquals(200, $response->getStatus()); $result = json_decode(wait($response->getBody()), true); $this->assertEquals($field1, $result['form']['field1']); $this->assertEquals(file_get_contents($file1), $result['files']['file1']); $this->assertEquals(file_get_contents($file2), $result['files']['file2']); $this->assertEquals('multipart/form-data; boundary=' . $boundary, $result['headers']['Content-Type']); } /** * @requires extension zlib */ public function testGzipResponse() { $client = new DefaultClient; $response = wait($client->request('http://httpbin.org/gzip')); $this->assertEquals(200, $response->getStatus()); $result = json_decode(wait($response->getBody()), true); $this->assertTrue($result['gzipped']); } /** * @requires extension zlib */ public function testDeflateResponse() { $client = new DefaultClient; $response = wait($client->request('http://httpbin.org/deflate')); $this->assertEquals(200, $response->getStatus()); $result = json_decode(wait($response->getBody()), true); $this->assertTrue($result['deflated']); } public function testInfiniteRedirect() { $this->expectException(TooManyRedirectsException::class); wait((new DefaultClient)->request("http://httpbin.org/redirect/11")); } public function testConnectionInfo() { /** @var Response $response */ $response = wait((new DefaultClient)->request("https://httpbin.org/get")); $connectionInfo = $response->getMetaInfo()->getConnectionInfo(); $this->assertContains(":", $connectionInfo->getLocalAddress()); $this->assertContains(":", $connectionInfo->getRemoteAddress()); $this->assertNotNull($connectionInfo->getTlsInfo()); $this->assertSame("TLSv1.2", $connectionInfo->getTlsInfo()->getProtocol()); $this->assertNotEmpty($connectionInfo->getTlsInfo()->getPeerCertificates()); $this->assertContains("httpbin.org", $connectionInfo->getTlsInfo()->getPeerCertificates()[0]->getNames()); foreach ($connectionInfo->getTlsInfo()->getPeerCertificates() as $certificate) { $this->assertGreaterThanOrEqual($certificate->getValidFrom(), time(), "Failed for " . $certificate->getSubject()->getCommonName()); $this->assertLessThanOrEqual($certificate->getValidTo(), time(), "Failed for " . $certificate->getSubject()->getCommonName()); } } public function testRequestCancellation() { $cancellationTokenSource = new CancellationTokenSource; $response = wait((new DefaultClient)->request("http://" . $this->socket->getAddress() . "/", [], $cancellationTokenSource->getToken())); $this->assertInstanceOf(Response::class, $response); $cancellationTokenSource->cancel(); $this->expectException(CancelledException::class); wait($response->getBody()); } public function testContentLengthBodyMismatchWithTooManyBytesSimple() { $this->expectException(HttpException::class); $this->expectExceptionMessage("Body contained more bytes than specified in Content-Length, aborting request"); $request = (new Request("http://httpbin.org/post", "POST")) ->withBody(new class implements RequestBody { public function getHeaders(): Promise { return new Success([]); } public function createBodyStream(): InputStream { return new InMemoryStream("foo"); } public function getBodyLength(): Promise { return new Success(1); } }); wait((new DefaultClient)->request($request)); } public function testContentLengthBodyMismatchWithTooManyBytesWith3ByteChunksAndLength2() { $this->expectException(HttpException::class); $this->expectExceptionMessage("Body contained more bytes than specified in Content-Length, aborting request"); $request = (new Request("http://httpbin.org/post", "POST")) ->withBody(new class implements RequestBody { public function getHeaders(): Promise { return new Success([]); } public function createBodyStream(): InputStream { return new IteratorStream(fromIterable(["a", "b", "c"], 500)); } public function getBodyLength(): Promise { return new Success(2); } }); wait((new DefaultClient)->request($request)); } public function testContentLengthBodyMismatchWithTooFewBytes() { $this->expectException(HttpException::class); $this->expectExceptionMessage("Body contained fewer bytes than specified in Content-Length, aborting request"); $request = (new Request("http://httpbin.org/post", "POST")) ->withBody(new class implements RequestBody { public function getHeaders(): Promise { return new Success([]); } public function createBodyStream(): InputStream { return new InMemoryStream("foo"); } public function getBodyLength(): Promise { return new Success(42); } }); wait((new DefaultClient)->request($request)); } protected function setUp() { parent::setUp(); if ($this->socket) { $this->socket->close(); } $this->socket = Socket\listen('127.0.0.1:0'); $this->server = new Server([$this->socket], new CallableRequestHandler(static function () { return new \Amp\Http\Server\Response(Status::OK, [], new IteratorStream(new Producer(static function ($emit) { yield $emit("."); yield new Delayed(5000); yield $emit("."); }))); }), new NullLogger); wait($this->server->start()); } } <?php namespace Amp\Artax\Test; use Amp\Artax\FileBody; use Amp\Artax\FormBody; use Amp\ByteStream\Message; use Amp\PHPUnit\TestCase; use function Amp\Promise\wait; class FormBodyTest extends TestCase { public function testUrlEncoded() { $body = new FormBody(); $body->addFields([ 'a' => 'a', ], 'application/json'); $body->addField('b', 'b', 'application/json'); $body->addField('c', 'c', ''); $body->addField('d', 'd'); $body->addFields([ 'e' => 'e', ], ''); $body->addFields([ 'f' => 'f' ]); $this->assertSame([ ['a', 'a', 'application/json', null], ['b', 'b', 'application/json', null], ['c', 'c', '', null], ['d', 'd', 'text/plain', null], ['e', 'e', '', null], ['f', 'f', 'text/plain', null], ], $body->getFields()); $content = wait(new Message($body->createBodyStream())); $this->assertEquals("a=a&b=b&c=c&d=d&e=e&f=f", $content); } public function testMultiPartFields() { $body = new FormBody('ea4ba2aa9af22673bc01ae7a64c95440'); $body->addFields([ 'a' => 'a', ], 'application/json'); $body->addField('b', 'b', 'application/json'); $body->addField('c', 'c', ''); $body->addField('d', 'd'); $body->addFields([ 'e' => 'e', ], ''); $body->addFields([ 'f' => 'f' ]); $file = __DIR__.'/fixture/lorem.txt'; $body->addFile('file', $file); $fields = $body->getFields(); list($fieldName, $fileBody, $contentType, $fileName) = \end($fields); $this->assertSame('file', $fieldName); $this->assertInstanceOf(FileBody::class, $fileBody); $this->assertSame('application/octet-stream', $contentType); $this->assertSame('lorem.txt', $fileName); $content = wait(new Message($body->createBodyStream())); $this->assertEquals("--ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"a\"\r Content-Type: application/json\r \r a\r --ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"b\"\r Content-Type: application/json\r \r b\r --ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"c\"\r \r c\r --ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"d\"\r Content-Type: text/plain\r \r d\r --ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"e\"\r \r e\r --ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"f\"\r Content-Type: text/plain\r \r f\r --ea4ba2aa9af22673bc01ae7a64c95440\r Content-Disposition: form-data; name=\"file\"; filename=\"lorem.txt\"\r Content-Type: application/octet-stream\r Content-Transfer-Encoding: binary\r \r Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r --ea4ba2aa9af22673bc01ae7a64c95440--\r\n", $content); } } <?php namespace Amp\Artax; use Amp\ByteStream\InputStream; use Amp\Promise; /** * An interface for generating HTTP message bodies + headers. */ interface RequestBody { /** * Retrieve a key-value array of headers to add to the outbound request. * * The resolved promise value must be a key-value array mapping header fields to values. * * @return Promise */ public function getHeaders(): Promise; /** * Create the HTTP message body to be sent. * * Further calls MUST return a new stream to make it possible to resend bodies on redirects. * * @return InputStream */ public function createBodyStream(): InputStream; /** * Retrieve the HTTP message body length. If not available, return -1. * * @return Promise */ public function getBodyLength(): Promise; } <?php namespace Amp\Artax; class TimeoutException extends HttpException { } <?php namespace Amp\Artax; use Amp\ByteStream\Message; /** * An HTTP response. * * This interface allows mocking responses and allows custom implementations. * * `DefaultClient` uses an anonymous class to implement this interface. */ interface Response { /** * Retrieve the requests's HTTP protocol version. * * @return string */ public function getProtocolVersion(): string; /** * Retrieve the response's three-digit HTTP status code. * * @return int */ public function getStatus(): int; /** * Retrieve the response's (possibly empty) reason phrase. * * @return string */ public function getReason(): string; /** * Retrieve the Request instance that resulted in this Response instance. * * @return Request */ public function getRequest(): Request; /** * Retrieve the original Request instance associated with this Response instance. * * A given Response may be the result of one or more redirects. This method is a shortcut to * access information from the original Request that led to this response. * * @return Request */ public function getOriginalRequest(): Request; /** * If this Response is the result of a redirect traverse up the redirect history. * * @return Response|null */ public function getPreviousResponse(); /** * Does the message contain the specified header field (case-insensitive)? * * @param string $field Header name. * * @return bool */ public function hasHeader(string $field): bool; /** * Retrieve the first occurrence of the specified header in the message. * * If multiple headers exist for the specified field only the value of the first header is returned. Applications * may use `getHeaderArray()` to retrieve a list of all header values received for a given field. * * A `null` return indicates the requested header field was not present. * * @param string $field Header name. * * @return string|null Header value or `null` if no header with name `$field` exists. */ public function getHeader(string $field); /** * Retrieve all occurrences of the specified header in the message. * * Applications may use `getHeader()` to access only the first occurrence. * * @param string $field Header name. * * @return array Header values. */ public function getHeaderArray(string $field): array; /** * Retrieve an associative array of headers matching field names to an array of field values. * * **Format** * * ```php * [ * "header-1" => [ * "value-1", * "value-2", * ], * "header-2" => [ * "value-1", * ], * ] * ``` * * @return array */ public function getHeaders(): array; /** * Retrieve the response body. * * Note: If you stream a Message, you can't consume the payload twice. * * @return Message */ public function getBody(): Message; /** * @return MetaInfo */ public function getMetaInfo(): MetaInfo; } <?php namespace Amp\Artax; class DnsException extends HttpException { } <?php namespace Amp\Artax\Internal; use Amp\Artax\Request; use Amp\Artax\Response; use Amp\CancellationToken; use Amp\Deferred; use Amp\Emitter; use Amp\Socket\ClientSocket; use Amp\Struct; use Amp\Uri\Uri; class RequestCycle { use Struct; /** @var string */ public $protocolVersion; /** @var Request */ public $request; /** @var Uri */ public $uri; /** @var array */ public $options; /** @var Response|null */ public $previousResponse; /** @var Deferred */ public $deferred; /** @var Deferred */ public $bodyDeferred; /** @var Emitter */ public $body; /** @var ClientSocket */ public $socket; /** @var CancellationToken */ public $cancellation; /** @var int */ public $retryCount = 0; /** @var bool */ public $bodyTooLarge = false; } <?php namespace Amp\Artax\Internal; use Amp\CancellationToken; use Amp\CancellationTokenSource; /** @internal */ class CombinedCancellationToken implements CancellationToken { private $token; private $tokens = []; public function __construct(...$tokens) { $tokenSource = new CancellationTokenSource; $this->token = $tokenSource->getToken(); foreach ($tokens as $token) { $id = $token->subscribe(static function ($error) use ($tokenSource) { $tokenSource->cancel($error); }); $this->tokens[] = [$token, $id]; } } public function __destruct() { foreach ($this->tokens as list($token, $id)) { /** @var CancellationToken $token */ $token->unsubscribe($id); } } /** @inheritdoc */ public function subscribe(callable $callback): string { return $this->token->subscribe($callback); } /** @inheritdoc */ public function unsubscribe(string $id) { $this->token->unsubscribe($id); } /** @inheritdoc */ public function isRequested(): bool { return $this->token->isRequested(); } /** @inheritdoc */ public function throwIfRequested() { $this->token->throwIfRequested(); } } <?php namespace Amp\Artax\Internal; use Amp\Artax\ParseException; /** @internal */ final class Parser { const STATUS_LINE_PATTERN = "#^ HTTP/(?P<protocol>\d+\.\d+)[\x20\x09]+ (?P<status>[1-5]\d\d)[\x20\x09]* (?P<reason>[^\x01-\x08\x10-\x19]*) $#ix"; const HEADERS_PATTERN = "/ (?P<field>[^\(\)<>@,;:\\\"\/\[\]\?\={}\x20\x09\x01-\x1F\x7F]+):[\x20\x09]* (?P<value>[^\x01-\x08\x0A-\x1F\x7F]*)[\x0D]?[\x20\x09]*[\r]?[\n] /x"; const MODE_REQUEST = 1; const MODE_RESPONSE = 2; const AWAITING_HEADERS = 0; const BODY_IDENTITY = 1; const BODY_IDENTITY_EOF = 2; const BODY_CHUNKS = 3; const TRAILERS_START = 4; const TRAILERS = 5; const OP_MAX_HEADER_BYTES = "amp.artax.parser.max-header-bytes"; const OP_MAX_BODY_BYTES = "amp.artax.parser.max-body-bytes"; const DEFAULT_MAX_HEADER_BYTES = 8192; const DEFAULT_MAX_BODY_BYTES = 10485760; private $mode; private $state = self::AWAITING_HEADERS; private $buffer = ''; private $traceBuffer; private $protocol; private $requestMethod; private $requestUri; private $responseCode; private $responseReason; private $headers = []; private $remainingBodyBytes; private $bodyBytesConsumed = 0; private $chunkLenRemaining = null; private $responseMethodMatch = []; private $parseFlowHeaders = [ 'TRANSFER-ENCODING' => null, 'CONTENT-LENGTH' => null, ]; private $maxHeaderBytes = self::DEFAULT_MAX_HEADER_BYTES; private $maxBodyBytes = self::DEFAULT_MAX_BODY_BYTES; private $bodyDataCallback; public function __construct(callable $bodyDataCallback = null, $mode = self::MODE_RESPONSE) { $this->bodyDataCallback = $bodyDataCallback; $this->mode = $mode; } public function setAllOptions(array $options) { foreach ($options as $option => $value) { $this->setOption($option, $value); } } public function setOption(string $option, $value) { switch ($option) { case self::OP_MAX_HEADER_BYTES: $this->maxHeaderBytes = (int) $value; break; case self::OP_MAX_BODY_BYTES: $this->maxBodyBytes = (int) $value; break; default: throw new \Error( sprintf('Unknown parser option: %s', $option) ); } } public function enqueueResponseMethodMatch(string $method) { $this->responseMethodMatch[] = $method; } /** * @return string|null */ public function getBuffer() { return $this->buffer; } public function getState(): int { return $this->state; } public function buffer(string $data) { $this->buffer .= $data; } public function parse(string $data = null) { if ($data !== null) { $this->buffer .= $data; } if ($this->buffer == '') { goto more_data_needed; } switch ($this->state) { case self::AWAITING_HEADERS: goto awaiting_headers; case self::BODY_IDENTITY: goto body_identity; case self::BODY_IDENTITY_EOF: goto body_identity_eof; case self::BODY_CHUNKS: goto body_chunks; case self::TRAILERS_START: goto trailers_start; case self::TRAILERS: goto trailers; } awaiting_headers: { if (!$startLineAndHeaders = $this->shiftHeadersFromMessageBuffer()) { goto more_data_needed; } goto start_line; } start_line: { $startLineEndPos = strpos($startLineAndHeaders, "\n"); $startLine = substr($startLineAndHeaders, 0, $startLineEndPos); $rawHeaders = substr($startLineAndHeaders, $startLineEndPos + 1); $this->traceBuffer = $startLineAndHeaders; if ($this->mode === self::MODE_REQUEST) { goto request_line_and_headers; } goto status_line_and_headers; } request_line_and_headers: { $parts = explode(' ', trim($startLine)); if (isset($parts[0]) && ($method = trim($parts[0]))) { $this->requestMethod = $method; } else { throw new ParseException($this->getParsedMessageArray(), 'Invalid request line', 400); } if (isset($parts[1]) && ($uri = trim($parts[1]))) { $this->requestUri = $uri; } else { throw new ParseException($this->getParsedMessageArray(), 'Invalid request line', 400); } if (isset($parts[2]) && ($protocol = str_ireplace('HTTP/', '', trim($parts[2])))) { $this->protocol = $protocol; } else { throw new ParseException($this->getParsedMessageArray(), 'Invalid request line', 400); } if (!($protocol === '1.0' || '1.1' === $protocol)) { throw new ParseException($this->getParsedMessageArray(), "Protocol not supported: {$protocol}", 505); } if ($rawHeaders) { $this->headers = $this->parseHeadersFromRaw($rawHeaders); } goto transition_from_request_headers_to_body; } status_line_and_headers: { if (preg_match(self::STATUS_LINE_PATTERN, $startLine, $matches)) { $this->protocol = $matches['protocol']; $this->responseCode = (int) $matches['status']; $this->responseReason = trim($matches['reason']); } else { throw new ParseException($this->getParsedMessageArray(), 'Invalid status line', 400); } if ($rawHeaders) { $this->headers = $this->parseHeadersFromRaw($rawHeaders); } goto transition_from_response_headers_to_body; } transition_from_request_headers_to_body: { if ($this->requestMethod == 'HEAD' || $this->requestMethod == 'TRACE' || $this->requestMethod == 'OPTIONS') { goto complete; } elseif ($this->parseFlowHeaders['TRANSFER-ENCODING']) { $this->state = self::BODY_CHUNKS; goto before_body; } elseif ($this->parseFlowHeaders['CONTENT-LENGTH']) { $this->remainingBodyBytes = $this->parseFlowHeaders['CONTENT-LENGTH']; $this->state = self::BODY_IDENTITY; goto before_body; } goto complete; } transition_from_response_headers_to_body: { $requestMethod = array_shift($this->responseMethodMatch); if ($this->responseCode == 204 || $this->responseCode == 304 || $this->responseCode < 200 || $requestMethod === 'HEAD' || $requestMethod === 'CONNECT' ) { goto complete; } elseif ($this->parseFlowHeaders['TRANSFER-ENCODING']) { $this->state = self::BODY_CHUNKS; goto before_body; } elseif ($this->parseFlowHeaders['CONTENT-LENGTH'] === null) { $this->state = self::BODY_IDENTITY_EOF; goto before_body; } elseif ($this->parseFlowHeaders['CONTENT-LENGTH'] > 0) { $this->remainingBodyBytes = $this->parseFlowHeaders['CONTENT-LENGTH']; $this->state = self::BODY_IDENTITY; goto before_body; } goto complete; } before_body: { if ($this->remainingBodyBytes === 0) { goto complete; } $parsedMsgArr = $this->getParsedMessageArray(); $parsedMsgArr['headersOnly'] = true; return $parsedMsgArr; } body_identity: { $bufferDataSize = strlen($this->buffer); if ($bufferDataSize < $this->remainingBodyBytes) { $this->addToBody($this->buffer); $this->buffer = null; $this->remainingBodyBytes -= $bufferDataSize; goto more_data_needed; } elseif ($bufferDataSize == $this->remainingBodyBytes) { $this->addToBody($this->buffer); $this->buffer = null; $this->remainingBodyBytes = 0; goto complete; } $bodyData = substr($this->buffer, 0, $this->remainingBodyBytes); $this->addToBody($bodyData); $this->buffer = substr($this->buffer, $this->remainingBodyBytes); $this->remainingBodyBytes = 0; goto complete; } body_identity_eof: { $this->addToBody($this->buffer); $this->buffer = ''; goto more_data_needed; } body_chunks: { if ($this->dechunk()) { $this->state = self::TRAILERS_START; goto trailers_start; } goto more_data_needed; } trailers_start: { $firstTwoBytes = substr($this->buffer, 0, 2); if ($firstTwoBytes == "" || $firstTwoBytes === "\r") { goto more_data_needed; } elseif ($firstTwoBytes === "\r\n") { $this->buffer = substr($this->buffer, 2); goto complete; } $this->state = self::TRAILERS; goto trailers; } trailers: { if ($trailers = $this->shiftHeadersFromMessageBuffer()) { $this->parseTrailers($trailers); goto complete; } goto more_data_needed; } complete: { $parsedMsgArr = $this->getParsedMessageArray(); $parsedMsgArr['headersOnly'] = false; $this->state = self::AWAITING_HEADERS; $this->traceBuffer = null; $this->headers = []; $this->bodyBytesConsumed = 0; $this->remainingBodyBytes = null; $this->chunkLenRemaining = null; $this->protocol = null; $this->requestUri = null; $this->requestMethod = null; $this->responseCode = null; $this->responseReason = null; $this->parseFlowHeaders = [ 'TRANSFER-ENCODING' => null, 'CONTENT-LENGTH' => null, ]; return $parsedMsgArr; } more_data_needed: { return null; } } private function shiftHeadersFromMessageBuffer() { $this->buffer = ltrim($this->buffer, "\r\n"); if ($headersSize = strpos($this->buffer, "\r\n\r\n")) { $headers = substr($this->buffer, 0, $headersSize + 2); $this->buffer = substr($this->buffer, $headersSize + 4); } elseif ($headersSize = strpos($this->buffer, "\n\n")) { $headers = substr($this->buffer, 0, $headersSize + 1); $this->buffer = substr($this->buffer, $headersSize + 2); } else { $headersSize = strlen($this->buffer); $headers = null; } if ($this->maxHeaderBytes > 0 && $headersSize > $this->maxHeaderBytes) { throw new ParseException($this->getParsedMessageArray(), "Maximum allowable header size exceeded: {$this->maxHeaderBytes}", 431); } return $headers; } private function parseHeadersFromRaw($rawHeaders) { if (strpos($rawHeaders, "\n\x20") || strpos($rawHeaders, "\n\t")) { $rawHeaders = preg_replace("/(?:\r\n|\n)[\x20\t]+/", ' ', $rawHeaders); } if (!preg_match_all(self::HEADERS_PATTERN, $rawHeaders, $matches)) { throw new ParseException( $this->getParsedMessageArray(), $msg = 'Invalid headers', $code = 400, $previousException = null ); } $headers = []; $aggregateMatchedHeaders = ''; for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { $aggregateMatchedHeaders .= $matches[0][$i]; $field = $matches['field'][$i]; $headers[$field][] = $matches['value'][$i]; } if (strlen($rawHeaders) !== strlen($aggregateMatchedHeaders)) { throw new ParseException( $this->getParsedMessageArray(), $msg = 'Invalid headers', $code = 400, $previousException = null ); } $ucKeyHeaders = array_change_key_case($headers, CASE_UPPER); if (isset($ucKeyHeaders['TRANSFER-ENCODING']) && strcasecmp('identity', $ucKeyHeaders['TRANSFER-ENCODING'][0]) ) { $this->parseFlowHeaders['TRANSFER-ENCODING'] = true; } elseif (isset($ucKeyHeaders['CONTENT-LENGTH'])) { $this->parseFlowHeaders['CONTENT-LENGTH'] = (int) $ucKeyHeaders['CONTENT-LENGTH'][0]; } return $headers; } private function dechunk() { if ($this->chunkLenRemaining !== null) { goto dechunk; } determine_chunk_size: { if (false === ($lineEndPos = strpos($this->buffer, "\r\n"))) { goto more_data_needed; } elseif ($lineEndPos === 0) { throw new ParseException( $this->getParsedMessageArray(), $msg = 'Invalid new line; hexadecimal chunk size expected', $code = 400, $previousException = null ); } $line = substr($this->buffer, 0, $lineEndPos); $hex = strtolower(trim(ltrim($line, '0'))) ?: 0; $dec = hexdec($hex); if ($hex == dechex($dec)) { $this->chunkLenRemaining = $dec; } else { throw new ParseException( $this->getParsedMessageArray(), $msg = 'Invalid hexadecimal chunk size', $code = 400, $previousException = null ); } $this->buffer = substr($this->buffer, $lineEndPos + 2); if (!$dec) { return true; } } dechunk: { $bufferLen = strlen($this->buffer); // These first two (extreme) edge cases prevent errors where the packet boundary ends after // the \r and before the \n at the end of a chunk. if ($bufferLen === $this->chunkLenRemaining) { goto more_data_needed; } elseif ($bufferLen === $this->chunkLenRemaining + 1) { goto more_data_needed; } elseif ($bufferLen >= $this->chunkLenRemaining + 2) { $chunk = substr($this->buffer, 0, $this->chunkLenRemaining); $this->buffer = substr($this->buffer, $this->chunkLenRemaining + 2); $this->chunkLenRemaining = null; $this->addToBody($chunk); goto determine_chunk_size; } $this->addToBody($this->buffer); $this->buffer = ''; $this->chunkLenRemaining -= $bufferLen; goto more_data_needed; } more_data_needed: { return false; } } private function parseTrailers($trailers) { $trailerHeaders = $this->parseHeadersFromRaw($trailers); $ucKeyTrailerHeaders = array_change_key_case($trailerHeaders, CASE_UPPER); $ucKeyHeaders = array_change_key_case($this->headers, CASE_UPPER); unset( $ucKeyTrailerHeaders['TRANSFER-ENCODING'], $ucKeyTrailerHeaders['CONTENT-LENGTH'], $ucKeyTrailerHeaders['TRAILER'] ); foreach (array_keys($this->headers) as $key) { $ucKey = strtoupper($key); if (isset($ucKeyTrailerHeaders[$ucKey])) { $this->headers[$key] = $ucKeyTrailerHeaders[$ucKey]; } } foreach (array_keys($trailerHeaders) as $key) { $ucKey = strtoupper($key); if (!isset($ucKeyHeaders[$ucKey])) { $this->headers[$key] = $trailerHeaders[$key]; } } } public function getParsedMessageArray(): array { $result = [ 'protocol' => $this->protocol, 'headers' => $this->headers, 'trace' => $this->traceBuffer, 'buffer' => $this->buffer, 'headersOnly' => false, ]; if ($this->mode === self::MODE_REQUEST) { $result['method'] = $this->requestMethod; $result['uri'] = $this->requestUri; } else { $result['status'] = $this->responseCode; $result['reason'] = $this->responseReason; } return $result; } private function addToBody(string $data) { $this->bodyBytesConsumed += strlen($data); if ($this->maxBodyBytes > 0 && $this->bodyBytesConsumed > $this->maxBodyBytes) { throw new ParseException($this->getParsedMessageArray(), "Maximum allowable body size exceeded: {$this->maxBodyBytes}", 413); } if ($this->bodyDataCallback) { ($this->bodyDataCallback)($data); } } } <?php namespace Amp\Artax\Internal; use Amp\Uri\InvalidDnsNameException; use function Amp\Uri\normalizeDnsName; /** @internal */ final class PublicSuffixList { private static $initialized = false; private static $suffixPatterns; private static $exceptionPatterns; public static function isPublicSuffix(string $domain) { if (!self::$initialized) { self::readList(); self::$initialized = true; } $domain = normalizeDnsName($domain); $domain = \implode(".", \array_reverse(\explode(".", \trim($domain, ".")))); foreach (self::$exceptionPatterns as $pattern) { if (\preg_match($pattern, $domain)) { return false; } } foreach (self::$suffixPatterns as $pattern) { if (\preg_match($pattern, $domain)) { return true; } } return false; } private static function readList() { $lines = \file(__DIR__ . "/../../res/public_suffix_list.dat", \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES); $exceptions = []; $rules = []; foreach ($lines as $line) { if (\trim($line) === "") { continue; } if (\substr($line, 0, 2) === "//") { continue; } $rule = \strtok($line, " \t"); try { if ($rule[0] === "!") { $exceptions[] = self::toRegex(\substr($rule, 1), true); } else { $rules[] = self::toRegex($rule, false); } } catch (InvalidDnsNameException $e) { // ignore IDN rules if no IDN support is available // requests with IDNs will fail anyway then } } self::$exceptionPatterns = \array_map(function ($list) { return "(^(?:" . \implode("|", $list) . ")$)i"; }, \array_chunk($exceptions, 256)); self::$suffixPatterns = \array_map(function ($list) { return "(^(?:" . \implode("|", $list) . ")$)i"; }, \array_chunk($rules, 256)); } private static function toRegex($rule, $exception) { $labels = \explode(".", $rule); foreach ($labels as $key => $label) { if ($label !== "*") { $labels[$key] = normalizeDnsName($label); } } $rule = \implode(".", $labels); $regexParts = []; foreach (\explode(".", $rule) as $part) { if ($part === "*") { $regexParts[] = "[^.]+"; } else { $regexParts[] = \preg_quote($part); } } $regex = \array_reduce($regexParts, function ($carry, $item) use ($exception) { if ($carry === "") { return $item; } return $item . "(?:\\." . $carry . ")" . ($exception ? "" : "?"); }, ""); return $regex; } } <?php namespace Amp\Artax; class HttpException extends \Exception { } <?php namespace Amp\Artax; use Kelunik\Certificate\Certificate; /** * Exposes a connection's negotiated TLS parameters. */ final class TlsInfo { private $protocol; private $cipherName; private $cipherBits; private $cipherVersion; private $certificates; private $parsedCertificates; private function __construct(string $protocol, string $cipherName, int $cipherBits, string $cipherVersion, array $certificates) { $this->protocol = $protocol; $this->cipherName = $cipherName; $this->cipherBits = $cipherBits; $this->cipherVersion = $cipherVersion; $this->certificates = $certificates; } /** * Constructs a new instance from PHP's internal info. * * Always pass the info as obtained from PHP as this method might extract additional fields in the future. * * @param array $cryptoInfo Crypto info obtained via `stream_get_meta_data($socket->getResource())["crypto"]`. * @param array $tlsContext Context obtained via `stream_context_get_options($socket->getResource())["ssl"])`. * * @return TlsInfo */ public static function fromMetaData(array $cryptoInfo, array $tlsContext): TlsInfo { return new self( $cryptoInfo["protocol"], $cryptoInfo["cipher_name"], $cryptoInfo["cipher_bits"], $cryptoInfo["cipher_version"], array_merge([$tlsContext["peer_certificate"]] ?: [], $tlsContext["peer_certificate_chain"] ?? []) ); } public function getProtocol(): string { return $this->protocol; } public function getCipherName(): string { return $this->cipherName; } public function getCipherBits(): int { return $this->cipherBits; } public function getCipherVersion(): string { return $this->cipherVersion; } /** @return Certificate[] */ public function getPeerCertificates(): array { if ($this->parsedCertificates === null) { $this->parsedCertificates = array_map(function ($resource) { return new Certificate($resource); }, $this->certificates); } return $this->parsedCertificates; } } <?php namespace Amp\Artax\Cookie; class NullCookieJar implements CookieJar { public function get(string $domain, string $path = '', string $name = null): array { return []; } public function getAll(): array { return []; } public function store(Cookie $cookie) { return null; } public function remove(Cookie $cookie) { return null; } public function removeAll() { return null; } } <?php namespace Amp\Artax\Cookie; class ArrayCookieJar implements CookieJar { private $cookies = []; /** * Store a cookie. * * @param Cookie $cookie * * @return void */ public function store(Cookie $cookie) { $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie; } /** * Remove a specific cookie from the storage. * * @param Cookie $cookie */ public function remove(Cookie $cookie) { unset($this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()]); } /** * Remove all stored cookies. */ public function removeAll() { $this->cookies = []; } /** * Retrieve all stored cookies. * * @return array Returns array in the format `$array[$domain][$path][$cookieName]`. */ public function getAll(): array { return $this->cookies; } /** * Retrieve all cookies matching the specified constraints. * * @param string $domain * @param string $path * @param string $name * * @return array Returns an array (possibly empty) of all cookie matches. */ public function get(string $domain, string $path = '', string $name = null): array { $this->clearExpiredCookies(); $path = $path === "" ? "/" : $path; $domain = \strtolower($domain); $matches = []; foreach ($this->cookies as $cookieDomain => $domainCookies) { if (!$this->matchesDomain($domain, $cookieDomain)) { continue; } foreach ($domainCookies as $cookiePath => $pathCookies) { if (!$this->matchesPath($path, $cookiePath)) { continue; } foreach ($pathCookies as $cookieName => $cookie) { if (!isset($name) || $name === $cookieName) { $matches[] = $cookie; } } } } return $matches; } private function clearExpiredCookies() { foreach ($this->cookies as $domain => $domainCookies) { foreach ($domainCookies as $path => $pathCookies) { foreach ($pathCookies as $name => $cookie) { /** @var Cookie $cookie */ if ($cookie->isExpired()) { unset($this->cookies[$domain][$path][$name]); } } } } } /** * @param string $requestDomain * @param string $cookieDomain * * @return bool * * @link http://tools.ietf.org/html/rfc6265#section-5.1.3 */ private function matchesDomain(string $requestDomain, string $cookieDomain): bool { if ($requestDomain === \ltrim($cookieDomain, ".")) { return true; } if (!($isWildcardCookieDomain = ($cookieDomain[0] === '.'))) { return false; } if (filter_var($requestDomain, FILTER_VALIDATE_IP)) { return false; } if (substr($requestDomain, 0, -\strlen($cookieDomain)) . $cookieDomain === $requestDomain) { return true; } return false; } /** * @link http://tools.ietf.org/html/rfc6265#section-5.1.4 */ private function matchesPath($requestPath, $cookiePath) { if ($requestPath === $cookiePath) { $isMatch = true; } elseif (strpos($requestPath, $cookiePath) === 0 && (substr($cookiePath, -1) === '/' || $requestPath[strlen($cookiePath)] === '/') ) { $isMatch = true; } else { $isMatch = false; } return $isMatch; } } <?php namespace Amp\Artax\Cookie; class FileCookieJar extends ArrayCookieJar { private $storagePath; public function __construct(string $storagePath) { if (!file_exists($storagePath)) { $cookieFileHandle = $this->createStorageFile($storagePath); } elseif (false === ($cookieFileHandle = @fopen($storagePath, 'r+'))) { throw new \RuntimeException( 'Failed opening cookie storage file for reading: ' . $storagePath ); } while (!feof($cookieFileHandle)) { if ($line = fgets($cookieFileHandle)) { $cookie = Cookie::fromString($line); $this->store($cookie); } } $this->storagePath = $storagePath; } private function createStorageFile($storagePath) { $dir = dirname($storagePath); if (!is_dir($dir)) { $this->createStorageDirectory($dir); } if (!$cookieFileHandle = @fopen($storagePath, 'w+')) { throw new \RuntimeException( 'Failed reading cookie storage file: ' . $storagePath ); } return $cookieFileHandle; } private function createStorageDirectory($dir) { if (!@mkdir($dir, 0777, true)) { throw new \RuntimeException( 'Failed creating cookie storage directory: ' . $dir ); } } public function __destruct() { $cookieData = ''; foreach ($this->getAll() as $pathArr) { foreach ($pathArr as $cookieArr) { /** * @var $cookie \Amp\Artax\Cookie\Cookie */ foreach ($cookieArr as $cookie) { if (!$cookie->isExpired()) { $cookieData .= $cookie . PHP_EOL; } } } } file_put_contents($this->storagePath, $cookieData); } } <?php namespace Amp\Artax\Cookie; use Amp\Artax\HttpException; class CookieFormatException extends HttpException { public function __construct(string $cookieString, string $reason = "") { parent::__construct("Invalid cookie string: '{$cookieString}', reason: '{$reason}'", 0, null); } } <?php namespace Amp\Artax\Cookie; interface CookieJar { public function get(string $domain, string $path = '', string $name = null): array; public function getAll(): array; public function store(Cookie $cookie); public function remove(Cookie $cookie); public function removeAll(); } <?php namespace Amp\Artax\Cookie; final class Cookie { private $name; private $value; private $expires; private $path; private $domain; private $secure; private $httpOnly; private static $dateFormats = [ 'D, d M Y H:i:s T', 'D, d-M-y H:i:s T', 'D, d-M-Y H:i:s T', 'D, d-m-y H:i:s T', 'D, d-m-Y H:i:s T', 'D M j G:i:s Y', 'D M d H:i:s Y T' ]; public function __construct( string $name, string $value, int $expires = null, string $path = null, string $domain = '', bool $secure = false, bool $httpOnly = true ) { $this->name = $name; $this->value = $value; $this->expires = $expires; $this->path = $path ?: '/'; $this->domain = \strtolower($domain); $this->secure = $secure; $this->httpOnly = $httpOnly; } public function getName(): string { return $this->name; } public function getValue(): string { return $this->value; } public function getExpirationTime() { return $this->expires; } public function isExpired(): bool { return $this->expires && $this->expires < time(); } public function getPath(): string { return $this->path; } public function getDomain(): string { return $this->domain; } public function isSecure(): bool { return $this->secure; } public function isHttpOnly(): bool { return $this->httpOnly; } public function withName(string $name): self { $clone = clone $this; $clone->name = $name; return $clone; } public function withValue(string $value): self { $clone = clone $this; $clone->value = $value; return $clone; } public function withExpirationTime(int $value = null): self { $clone = clone $this; $clone->expires = $value; return $clone; } public function withPath(string $path): self { $clone = clone $this; $clone->path = $path; return $clone; } public function withDomain(string $domain): self { $clone = clone $this; $clone->domain = $domain; return $clone; } public function withSecure(bool $secure): self { $clone = clone $this; $clone->secure = $secure; return $clone; } public function withHttpOnly(bool $httpOnly): self { $clone = clone $this; $clone->httpOnly = $httpOnly; return $clone; } public function __toString(): string { $cookieStr = $this->name . '=' . $this->value; if ($this->expires !== null) { $expiryDate = \DateTime::createFromFormat('U', $this->expires, new \DateTimeZone('GMT')); $cookieStr .= '; expires=' . $expiryDate->format(self::$dateFormats[0]); } if ($this->domain !== '') { $cookieStr .= '; domain=' . $this->domain; } if ($this->path) { $cookieStr .= '; path=' . $this->path; } if ($this->secure) { $cookieStr .= '; secure'; } if ($this->httpOnly) { $cookieStr .= '; httpOnly'; } return $cookieStr; } /** * @param string $rawCookieStr * * @return self * * @link https://tools.ietf.org/html/rfc6265#section-5.2 */ public static function fromString(string $rawCookieStr): self { if ($rawCookieStr === "") { throw new CookieFormatException( $rawCookieStr, "Empty cookie string" ); } $parts = explode(';', trim($rawCookieStr)); $nvPair = array_shift($parts); if (strpos($nvPair, '=') === false) { throw new CookieFormatException( $rawCookieStr, "Missing '=' to separate name and value" ); } list($name, $value) = explode('=', $nvPair, 2); if (\trim($name) === "") { throw new CookieFormatException($rawCookieStr, "Empty name"); } $attrStruct = [ 'expires' => null, 'path' => '', 'domain' => "", 'secure' => false, 'httponly' => false, 'max-age' => null ]; foreach ($parts as $part) { $part = \trim($part); if (0 === \stripos($part, 'secure')) { $attrStruct['secure'] = true; continue; } elseif (0 === \stripos($part, 'httponly')) { $attrStruct['httponly'] = true; continue; } if (\strpos($part, '=') === false) { $attr = $part; $attrValue = "1"; } else { list($attr, $attrValue) = explode('=', $part, 2); } $attr = strtolower($attr); if (array_key_exists($attr, $attrStruct)) { $attrStruct[$attr] = trim($attrValue, "\"\t\n\r\0\x0B\x20"); } } $attrStruct['httponly'] = (bool) $attrStruct['httponly']; $attrStruct['secure'] = (bool) $attrStruct['secure']; if (isset($attrStruct['max-age']) && intval($attrStruct['max-age']) == $attrStruct['max-age']) { $attrStruct['expires'] = time() + $attrStruct['max-age']; } elseif ($attrStruct['expires']) { $attrStruct['expires'] = self::parseDate($attrStruct['expires']); } return new self( \trim($name), \trim($value), $attrStruct['expires'], $attrStruct['path'], $attrStruct['domain'], $attrStruct['secure'], $attrStruct['httponly'] ); } private static function parseDate($dateStr) { foreach (self::$dateFormats as $dateFormat) { if ($date = \DateTime::createFromFormat($dateFormat, $dateStr, new \DateTimeZone('GMT'))) { return $date->getTimestamp(); } } throw new CookieFormatException( $dateStr, 'Invalid expires attribute' ); } } <?php namespace Amp\Artax; final class ConnectionInfo { private $localAddress; private $remoteAddress; private $tlsInfo; public function __construct(string $localAddress, string $remoteAddress, TlsInfo $tlsInfo = null) { $this->localAddress = $localAddress; $this->remoteAddress = $remoteAddress; $this->tlsInfo = $tlsInfo; } /** * @return string */ public function getLocalAddress(): string { return $this->localAddress; } /** * @return string */ public function getRemoteAddress(): string { return $this->remoteAddress; } /** * @return TlsInfo|null */ public function getTlsInfo() { return $this->tlsInfo; } } <?php namespace Amp\Artax; use Amp\Artax\Internal\Parser; use Amp\CancellationToken; use Amp\Promise; /** * Interface definition for an HTTP client. */ interface Client { /** Whether to automatically apply compression to requests and responses. */ const OP_AUTO_ENCODING = 'amp.artax.client.auto-encoding'; /** Transfer timeout in milliseconds until an HTTP request is automatically aborted, use 0 to disable. */ const OP_TRANSFER_TIMEOUT = 'amp.artax.client.transfer-timeout'; /** How many redirects to follow, might be 0 to not follow any redirects. */ const OP_MAX_REDIRECTS = 'amp.artax.client.max-redirects'; /** Whether to automatically add a "Referer" header on redirects. */ const OP_AUTO_REFERER = 'amp.artax.client.auto-referer'; /** Whether to directly discard the HTTP response body or not. */ const OP_DISCARD_BODY = 'amp.artax.client.discard-body'; /** Default headers to use. */ const OP_DEFAULT_HEADERS = 'amp.artax.client.default-headers'; /** Maximum header size, usually doesn't have to be adjusted. */ const OP_MAX_HEADER_BYTES = Parser::OP_MAX_HEADER_BYTES; /** Maximum body size. Needs to be adjusted for streaming large responses, e.g. Streaming APIs. */ const OP_MAX_BODY_BYTES = Parser::OP_MAX_BODY_BYTES; /** * Asynchronously request an HTTP resource. * * @param Request|string $uriOrRequest An HTTP URI string or a Request instance. * @param array $options An array specifying options applicable only for this request. * @param CancellationToken $cancellation A cancellation token to optionally cancel requests. * * @return Promise A promise to resolve to a response object as soon as its headers are received. */ public function request($uriOrRequest, array $options = [], CancellationToken $cancellation = null): Promise; } <?php namespace Amp\Artax; class ParseException extends HttpException { private $parserResult; /** * Adds an array of parsed message values to the standard exception. * * @param array $parserResult * @param string $message * @param int $code * @param \Throwable|null $previousException */ public function __construct(array $parserResult, string $message, int $code, \Throwable $previousException = null) { parent::__construct($message, $code, $previousException); $this->parserResult = $parserResult; } /** * Retrieve message values parsed prior to the error. * * @return array Message values parsed prior to the error */ public function getParserResult(): array { return $this->parserResult; } } <?php namespace Amp\Artax; /** * Contains generic meta information about a response, currently only ConnectionInfo, but might be extended later. */ final class MetaInfo { private $connectionInfo; public function __construct(ConnectionInfo $connectionInfo) { $this->connectionInfo = $connectionInfo; } public function getConnectionInfo(): ConnectionInfo { return $this->connectionInfo; } } <?php namespace Amp\Artax; use Amp\Artax\Cookie\Cookie; use Amp\Artax\Cookie\CookieFormatException; use Amp\Artax\Cookie\CookieJar; use Amp\Artax\Cookie\NullCookieJar; use Amp\Artax\Internal\CombinedCancellationToken; use Amp\Artax\Internal\Parser; use Amp\Artax\Internal\PublicSuffixList; use Amp\Artax\Internal\RequestCycle; use Amp\ByteStream\InputStream; use Amp\ByteStream\IteratorStream; use Amp\ByteStream\Message; use Amp\ByteStream\StreamException; use Amp\ByteStream\ZlibInputStream; use Amp\CancellationToken; use Amp\CancelledException; use Amp\Deferred; use Amp\Delayed; use Amp\Dns\ResolutionException; use Amp\Emitter; use Amp\Failure; use Amp\Loop; use Amp\NullCancellationToken; use Amp\Promise; use Amp\Socket\ClientSocket; use Amp\Socket\ClientTlsContext; use Amp\Socket\ConnectException; use Amp\Success; use Amp\TimeoutCancellationToken; use Amp\Uri\InvalidUriException; use Amp\Uri\Uri; use function Amp\asyncCall; use function Amp\call; /** * Standard client implementation. * * Use the `Client` interface for your type declarations so people can use composition to add layers like caching. * * @see Client */ final class DefaultClient implements Client { const DEFAULT_USER_AGENT = 'Mozilla/5.0 (compatible; Artax)'; private $cookieJar; private $socketPool; private $tlsContext; private $hasZlib; private $options = [ self::OP_AUTO_ENCODING => true, self::OP_TRANSFER_TIMEOUT => 15000, self::OP_MAX_REDIRECTS => 5, self::OP_AUTO_REFERER => true, self::OP_DISCARD_BODY => false, self::OP_DEFAULT_HEADERS => [], self::OP_MAX_HEADER_BYTES => Parser::DEFAULT_MAX_HEADER_BYTES, self::OP_MAX_BODY_BYTES => Parser::DEFAULT_MAX_BODY_BYTES, ]; public function __construct( CookieJar $cookieJar = null, HttpSocketPool $socketPool = null, ClientTlsContext $tlsContext = null ) { $this->cookieJar = $cookieJar ?? new NullCookieJar; $this->tlsContext = $tlsContext ?? new ClientTlsContext; $this->socketPool = $socketPool ?? new HttpSocketPool; $this->hasZlib = extension_loaded('zlib'); } /** @inheritdoc */ public function request($uriOrRequest, array $options = [], CancellationToken $cancellation = null): Promise { return call(function () use ($uriOrRequest, $options, $cancellation) { $cancellation = $cancellation ?? new NullCancellationToken; foreach ($options as $option => $value) { $this->validateOption($option, $value); } /** @var Request $request */ list($request, $uri) = $this->generateRequestFromUri($uriOrRequest); $options = $options ? array_merge($this->options, $options) : $this->options; foreach ($this->options[self::OP_DEFAULT_HEADERS] as $name => $header) { if (!$request->hasHeader($name)) { $request = $request->withHeaders([$name => $header]); } } /** @var array $headers */ $headers = yield $request->getBody()->getHeaders(); foreach ($headers as $name => $header) { if (!$request->hasHeader($name)) { $request = $request->withHeaders([$name => $header]); } } $originalUri = $uri; $previousResponse = null; $maxRedirects = $options[self::OP_MAX_REDIRECTS]; $requestNr = 1; do { /** @var Request $request */ $request = yield from $this->normalizeRequestBodyHeaders($request); $request = $this->normalizeRequestHeaders($request, $uri, $options); // Always normalize this as last item, because we need to strip sensitive headers $request = $this->normalizeTraceRequest($request); /** @var Response $response */ $response = yield $this->doRequest($request, $uri, $options, $previousResponse, $cancellation); // Explicit $maxRedirects !== 0 check to not consume redirect bodies if redirect following is disabled if ($maxRedirects !== 0 && $redirectUri = $this->getRedirectUri($response)) { // Discard response body of redirect responses $body = $response->getBody(); while (null !== yield $body->read()) ; /** * If this is a 302/303 we need to follow the location with a GET if the original request wasn't * GET. Otherwise we need to send the body again. * * We won't resend the body nor any headers on redirects to other hosts for security reasons. * * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3 */ $method = $request->getMethod(); $status = $response->getStatus(); $isSameHost = $redirectUri->getAuthority(false) === $originalUri->getAuthority(false); if ($isSameHost) { $request = $request->withUri($redirectUri); if ($status >= 300 && $status <= 303 && $method !== 'GET') { $request = $request->withMethod('GET'); $request = $request->withoutHeader('Transfer-Encoding'); $request = $request->withoutHeader('Content-Length'); $request = $request->withoutHeader('Content-Type'); $request = $request->withBody(null); } } else { // We ALWAYS follow with a GET and without any set headers or body for redirects to other hosts. $optionsWithoutHeaders = $options; unset($optionsWithoutHeaders[self::OP_DEFAULT_HEADERS]); $request = new Request((string) $redirectUri); $request = $this->normalizeRequestHeaders($request, $redirectUri, $optionsWithoutHeaders); } if ($options[self::OP_AUTO_REFERER]) { $request = $this->assignRedirectRefererHeader($request, $originalUri, $redirectUri); } $previousResponse = $response; $originalUri = $redirectUri; $uri = $redirectUri; } else { break; } } while (++$requestNr <= $maxRedirects + 1); if ($maxRedirects !== 0 && $redirectUri = $this->getRedirectUri($response)) { throw new TooManyRedirectsException($response); } return $response; }); } private function doRequest(Request $request, Uri $uri, array $options, Response $previousResponse = null, CancellationToken $cancellation): Promise { $deferred = new Deferred; $requestCycle = new RequestCycle; $requestCycle->request = $request; $requestCycle->uri = $uri; $requestCycle->options = $options; $requestCycle->previousResponse = $previousResponse; $requestCycle->deferred = $deferred; $requestCycle->bodyDeferred = new Deferred; $requestCycle->body = new Emitter; $requestCycle->cancellation = $cancellation; $protocolVersions = $request->getProtocolVersions(); if (\in_array("1.1", $protocolVersions, true)) { $requestCycle->protocolVersion = "1.1"; } elseif (\in_array("1.0", $protocolVersions, true)) { $requestCycle->protocolVersion = "1.0"; } else { return new Failure(new HttpException( "None of the requested protocol versions are supported: " . \implode(", ", $protocolVersions) )); } asyncCall(function () use ($requestCycle) { try { yield from $this->doWrite($requestCycle); } catch (\Throwable $e) { $this->fail($requestCycle, $e); } }); return $deferred->promise(); } private function generateRequestFromUri($uriOrRequest) { if (is_string($uriOrRequest)) { $uri = $this->buildUriFromString($uriOrRequest); $request = new Request($uri); } elseif ($uriOrRequest instanceof Request) { $uri = $this->buildUriFromString($uriOrRequest->getUri()); $request = $uriOrRequest; } else { throw new HttpException( 'Request must be a valid HTTP URI or Amp\Artax\Request instance' ); } return [$request, $uri]; } private function doRead(RequestCycle $requestCycle, ClientSocket $socket, ConnectionInfo $connectionInfo): \Generator { try { $backpressure = new Success; $bodyCallback = $requestCycle->options[self::OP_DISCARD_BODY] ? null : static function ($data) use ($requestCycle, &$backpressure) { $backpressure = $requestCycle->body->emit($data); }; $parser = new Parser($bodyCallback); $parser->enqueueResponseMethodMatch($requestCycle->request->getMethod()); $parser->setAllOptions([ Parser::OP_MAX_HEADER_BYTES => $requestCycle->options[self::OP_MAX_HEADER_BYTES], Parser::OP_MAX_BODY_BYTES => $requestCycle->options[self::OP_MAX_BODY_BYTES], ]); while (null !== $chunk = yield $socket->read()) { $requestCycle->cancellation->throwIfRequested(); $parseResult = $parser->parse($chunk); if (!$parseResult) { continue; } $parseResult["headers"] = \array_change_key_case($parseResult["headers"], \CASE_LOWER); $response = $this->finalizeResponse($requestCycle, $parseResult, $connectionInfo); $shouldCloseSocketAfterResponse = $this->shouldCloseSocketAfterResponse($response); $ignoreIncompleteBodyCheck = false; $responseHeaders = $response->getHeaders(); if ($requestCycle->deferred) { $deferred = $requestCycle->deferred; $requestCycle->deferred = null; $deferred->resolve($response); $response = null; // clear references $deferred = null; // there's also a reference in the deferred } else { return; } // Required, otherwise responses without body hang if ($parseResult["headersOnly"]) { // Directly parse again in case we already have the full body but aborted parsing // to resolve promise with headers. $chunk = null; do { try { $parseResult = $parser->parse($chunk); } catch (ParseException $e) { $this->fail($requestCycle, $e); throw $e; } if ($parseResult) { break; } if (!$backpressure instanceof Success) { yield $this->withCancellation($backpressure, $requestCycle->cancellation); } if ($requestCycle->bodyTooLarge) { throw new HttpException("Response body exceeded the specified size limit"); } } while (null !== $chunk = yield $socket->read()); $parserState = $parser->getState(); if ($parserState !== Parser::AWAITING_HEADERS) { // Ignore check if neither content-length nor chunked encoding are given. $ignoreIncompleteBodyCheck = $parserState === Parser::BODY_IDENTITY_EOF && !isset($responseHeaders["content-length"]) && strcasecmp('identity', $responseHeaders['transfer-encoding'][0] ?? ""); if (!$ignoreIncompleteBodyCheck) { throw new SocketException(sprintf( 'Socket disconnected prior to response completion (Parser state: %s)', $parserState )); } } } if ($shouldCloseSocketAfterResponse || $ignoreIncompleteBodyCheck) { $this->socketPool->clear($socket); $socket->close(); } else { $this->socketPool->checkin($socket); } $requestCycle->socket = null; // Complete body AFTER socket checkin, so the socket can be reused for a potential redirect $body = $requestCycle->body; $requestCycle->body = null; $bodyDeferred = $requestCycle->bodyDeferred; $requestCycle->bodyDeferred = null; $body->complete(); $bodyDeferred->resolve(); return; } } catch (\Throwable $e) { $this->fail($requestCycle, $e); return; } if ($socket->getResource() !== null) { $requestCycle->socket = null; $this->socketPool->clear($socket); $socket->close(); } // Required, because if the write fails, the read() call immediately resolves. yield new Delayed(0); if ($requestCycle->deferred === null) { return; } $parserState = $parser->getState(); if ($parserState === Parser::AWAITING_HEADERS && $requestCycle->retryCount < 1) { $requestCycle->retryCount++; yield from $this->doWrite($requestCycle); } else { $this->fail($requestCycle, new SocketException(sprintf( 'Socket disconnected prior to response completion (Parser state: %s)', $parserState ))); } } private function withCancellation(Promise $promise, CancellationToken $cancellationToken): Promise { $deferred = new Deferred; $newPromise = $deferred->promise(); $promise->onResolve(function ($error, $value) use (&$deferred) { if ($deferred) { if ($error) { $deferred->fail($error); $deferred = null; } else { $deferred->resolve($value); $deferred = null; } } }); $cancellationSubscription = $cancellationToken->subscribe(function ($e) use (&$deferred) { if ($deferred) { $deferred->fail($e); $deferred = null; } }); $newPromise->onResolve(function () use ($cancellationToken, $cancellationSubscription) { $cancellationToken->unsubscribe($cancellationSubscription); }); return $newPromise; } private function doWrite(RequestCycle $requestCycle) { $timeout = $requestCycle->options[self::OP_TRANSFER_TIMEOUT]; $timeoutToken = new NullCancellationToken; if ($timeout > 0) { $transferTimeoutWatcher = Loop::delay($timeout, function () use ($requestCycle, $timeout) { $this->fail($requestCycle, new TimeoutException( sprintf('Allowed transfer timeout exceeded: %d ms', $timeout) )); }); $requestCycle->bodyDeferred->promise()->onResolve(static function () use ($transferTimeoutWatcher) { Loop::cancel($transferTimeoutWatcher); }); $timeoutToken = new TimeoutCancellationToken($timeout); } $authority = $this->generateAuthorityFromUri($requestCycle->uri); $socketCheckoutUri = $requestCycle->uri->getScheme() . "://{$authority}"; $connectTimeoutToken = new CombinedCancellationToken($requestCycle->cancellation, $timeoutToken); try { /** @var ClientSocket $socket */ $socket = yield $this->socketPool->checkout($socketCheckoutUri, $connectTimeoutToken); $requestCycle->socket = $socket; } catch (ResolutionException $dnsException) { throw new DnsException(\sprintf("Resolving the specified domain failed: '%s'", $requestCycle->uri->getHost()), 0, $dnsException); } catch (ConnectException $e) { throw new SocketException(\sprintf("Connection to '%s' failed", $authority), 0, $e); } catch (CancelledException $e) { // In case of a user cancellation request, throw the expected exception $requestCycle->cancellation->throwIfRequested(); // Otherwise we ran into a timeout of our TimeoutCancellationToken throw new SocketException(\sprintf("Connection to '%s' timed out", $authority), 0, $e); } $cancellation = $requestCycle->cancellation->subscribe(function ($error) use ($requestCycle) { $this->fail($requestCycle, $error); }); try { if ($requestCycle->uri->getScheme() === 'https') { $tlsContext = $this->tlsContext ->withPeerName($requestCycle->uri->getHost()) ->withPeerCapturing(); yield $socket->enableCrypto($tlsContext); } // Collect this here, because it fails in case the remote closes the connection directly. $connectionInfo = $this->collectConnectionInfo($socket); $rawHeaders = $this->generateRawRequestHeaders($requestCycle->request, $requestCycle->protocolVersion); yield $socket->write($rawHeaders); $body = $requestCycle->request->getBody()->createBodyStream(); $chunking = $requestCycle->request->getHeader("transfer-encoding") === "chunked"; $remainingBytes = $requestCycle->request->getHeader("content-length"); if ($chunking && $requestCycle->protocolVersion === "1.0") { throw new HttpException("Can't send chunked bodies over HTTP/1.0"); } // We always buffer the last chunk to make sure we don't write $contentLength bytes if the body is too long. $buffer = ""; while (null !== $chunk = yield $body->read()) { $requestCycle->cancellation->throwIfRequested(); if ($chunk === "") { continue; } if ($chunking) { $chunk = \dechex(\strlen($chunk)) . "\r\n" . $chunk . "\r\n"; } elseif ($remainingBytes !== null) { $remainingBytes -= \strlen($chunk); if ($remainingBytes < 0) { throw new HttpException("Body contained more bytes than specified in Content-Length, aborting request"); } } yield $socket->write($buffer); $buffer = $chunk; } // Flush last buffered chunk. yield $socket->write($buffer); if ($chunking) { yield $socket->write("0\r\n\r\n"); } elseif ($remainingBytes !== null && $remainingBytes > 0) { throw new HttpException("Body contained fewer bytes than specified in Content-Length, aborting request"); } yield from $this->doRead($requestCycle, $socket, $connectionInfo); } catch (StreamException $e) { throw new SocketException("Failed to read response from server", 0, $e); } finally { $requestCycle->cancellation->unsubscribe($cancellation); } } private function fail(RequestCycle $requestCycle, \Throwable $error) { $toFails = []; $socket = null; if ($requestCycle->deferred) { $toFails[] = $requestCycle->deferred; $requestCycle->deferred = null; } if ($requestCycle->body) { $toFails[] = $requestCycle->body; $requestCycle->body = null; } if ($requestCycle->bodyDeferred) { $toFails[] = $requestCycle->bodyDeferred; $requestCycle->bodyDeferred = null; } if ($requestCycle->socket) { $this->socketPool->clear($requestCycle->socket); $socket = $requestCycle->socket; $requestCycle->socket = null; $socket->close(); } foreach ($toFails as $toFail) { $toFail->fail($error); } } private function buildUriFromString($str): Uri { try { $uri = new Uri($str); $scheme = $uri->getScheme(); if (($scheme === "http" || $scheme === "https") && $uri->getHost()) { return $uri; } throw new HttpException("Request must specify a valid HTTP URI"); } catch (InvalidUriException $e) { throw new HttpException("Request must specify a valid HTTP URI", 0, $e); } } private function normalizeRequestBodyHeaders(Request $request): \Generator { if ($request->hasHeader("Transfer-Encoding")) { return $request->withoutHeader("Content-Length"); } if ($request->hasHeader("Content-Length")) { return $request; } /** @var RequestBody $body */ $body = $request->getBody(); $bodyLength = yield $body->getBodyLength(); if ($bodyLength === 0) { $request = $request->withHeader('Content-Length', '0'); $request = $request->withoutHeader('Transfer-Encoding'); } else { if ($bodyLength > 0) { $request = $request->withHeader("Content-Length", $bodyLength); $request = $request->withoutHeader("Transfer-Encoding"); } else { $request = $request->withHeader("Transfer-Encoding", "chunked"); } } return $request; } private function normalizeRequestHeaders($request, $uri, $options) { $request = $this->normalizeRequestEncodingHeaderForZlib($request, $options); $request = $this->normalizeRequestHostHeader($request, $uri); $request = $this->normalizeRequestUserAgent($request); $request = $this->normalizeRequestAcceptHeader($request); $request = $this->assignApplicableRequestCookies($request); return $request; } private function normalizeTraceRequest(Request $request): Request { $method = $request->getMethod(); if ($method !== 'TRACE') { return $request; } // https://tools.ietf.org/html/rfc7231#section-4.3.8 /** @var Request $request */ $request = $request->withBody(null); // Remove all body and sensitive headers $request = $request->withHeaders([ "Transfer-Encoding" => [], "Content-Length" => [], "Authorization" => [], "Proxy-Authorization" => [], "Cookie" => [], ]); return $request; } private function normalizeRequestEncodingHeaderForZlib(Request $request, array $options): Request { $autoEncoding = $options[self::OP_AUTO_ENCODING]; if (!$autoEncoding) { return $request; } if ($this->hasZlib) { return $request->withHeader('Accept-Encoding', 'gzip, deflate, identity'); } return $request->withoutHeader('Accept-Encoding'); } private function normalizeRequestHostHeader(Request $request, Uri $uri): Request { if ($request->hasHeader('Host')) { return $request; } $authority = $this->generateAuthorityFromUri($uri); $request = $request->withHeader('Host', $this->normalizeHostHeader($authority)); return $request; } private function normalizeHostHeader(string $host): string { // Though servers are supposed to be able to handle standard port names on the end of the // Host header some fail to do this correctly. As a result, we strip the port from the end // if it's a standard 80 or 443 if (strpos($host, ':80') === strlen($host) - 3) { return substr($host, 0, -3); } elseif (strpos($host, ':443') === strlen($host) - 4) { return substr($host, 0, -4); } return $host; } private function normalizeRequestUserAgent(Request $request): Request { if ($request->hasHeader('User-Agent')) { return $request; } return $request->withHeader('User-Agent', self::DEFAULT_USER_AGENT); } private function normalizeRequestAcceptHeader(Request $request): Request { if ($request->hasHeader('Accept')) { return $request; } return $request->withHeader('Accept', '*/*'); } private function assignApplicableRequestCookies(Request $request): Request { $uri = new Uri($request->getUri()); $domain = $uri->getHost(); $path = $uri->getPath(); if (!$applicableCookies = $this->cookieJar->get($domain, $path)) { // No cookies matched our request; we're finished. return $request->withoutHeader("Cookie"); } $isRequestSecure = strcasecmp($uri->getScheme(), "https") === 0; $cookiePairs = []; /** @var Cookie $cookie */ foreach ($applicableCookies as $cookie) { if (!$cookie->isSecure() || $isRequestSecure) { $cookiePairs[] = $cookie->getName() . "=" . $cookie->getValue(); } } if ($cookiePairs) { return $request->withHeader("Cookie", \implode("; ", $cookiePairs)); } return $request->withoutHeader("Cookie"); } private function generateAuthorityFromUri(Uri $uri): string { $host = $uri->getHost(); $port = $uri->getPort(); return "{$host}:{$port}"; } private function finalizeResponse(RequestCycle $requestCycle, array $parserResult, ConnectionInfo $connectionInfo) { $body = new IteratorStream($requestCycle->body->iterate()); if ($encoding = $this->determineCompressionEncoding($parserResult["headers"])) { $body = new ZlibInputStream($body, $encoding); } // Wrap the input stream so we can discard the body in case it's destructed but hasn't been consumed. // This allows reusing the connection for further requests. It's important to have __destruct in InputStream and // not in Message, because an InputStream might be pulled out of Message and used separately. $body = new class($body, $requestCycle, $this->socketPool) implements InputStream { private $body; private $bodySize = 0; private $requestCycle; private $socketPool; private $successfulEnd = false; public function __construct(InputStream $body, RequestCycle $requestCycle, HttpSocketPool $socketPool) { $this->body = $body; $this->requestCycle = $requestCycle; $this->socketPool = $socketPool; } public function read(): Promise { $promise = $this->body->read(); $promise->onResolve(function ($error, $value) { if ($value !== null) { $this->bodySize += \strlen($value); $maxBytes = $this->requestCycle->options[Client::OP_MAX_BODY_BYTES]; if ($maxBytes !== 0 && $this->bodySize >= $maxBytes) { $this->requestCycle->bodyTooLarge = true; } } elseif ($error === null) { $this->successfulEnd = true; } }); return $promise; } public function __destruct() { if (!$this->successfulEnd && $this->requestCycle->socket) { $this->socketPool->clear($this->requestCycle->socket); $socket = $this->requestCycle->socket; $this->requestCycle->socket = null; $socket->close(); } } }; $response = new class($parserResult["protocol"], $parserResult["status"], $parserResult["reason"], $parserResult["headers"], $body, $requestCycle->request, $requestCycle->previousResponse, new MetaInfo($connectionInfo)) implements Response { private $protocolVersion; private $status; private $reason; private $request; private $previousResponse; private $headers; private $body; private $metaInfo; public function __construct( string $protocolVersion, int $status, string $reason, array $headers, InputStream $body, Request $request, Response $previousResponse = null, MetaInfo $metaInfo ) { $this->protocolVersion = $protocolVersion; $this->status = $status; $this->reason = $reason; $this->headers = $headers; $this->body = new Message($body); $this->request = $request; $this->previousResponse = $previousResponse; $this->metaInfo = $metaInfo; } public function getProtocolVersion(): string { return $this->protocolVersion; } public function getStatus(): int { return $this->status; } public function getReason(): string { return $this->reason; } public function getRequest(): Request { return $this->request; } public function getOriginalRequest(): Request { if (empty($this->previousResponse)) { return $this->request; } return $this->previousResponse->getOriginalRequest(); } public function getPreviousResponse() { return $this->previousResponse; } public function hasHeader(string $field): bool { return isset($this->headers[\strtolower($field)]); } public function getHeader(string $field) { return $this->headers[\strtolower($field)][0] ?? null; } public function getHeaderArray(string $field): array { return $this->headers[\strtolower($field)] ?? []; } public function getHeaders(): array { return $this->headers; } public function getBody(): Message { return $this->body; } public function getMetaInfo(): MetaInfo { return $this->metaInfo; } }; if ($response->hasHeader('Set-Cookie')) { $requestDomain = $requestCycle->uri->getHost(); $cookies = $response->getHeaderArray('Set-Cookie'); foreach ($cookies as $rawCookieStr) { $this->storeResponseCookie($requestDomain, $rawCookieStr); } } return $response; } private function shouldCloseSocketAfterResponse(Response $response) { $request = $response->getRequest(); $requestConnHeader = $request->getHeader('Connection'); $responseConnHeader = $response->getHeader('Connection'); if ($requestConnHeader && !strcasecmp($requestConnHeader, 'close')) { return true; } elseif ($responseConnHeader && !strcasecmp($responseConnHeader, 'close')) { return true; } elseif ($response->getProtocolVersion() === '1.0' && !$responseConnHeader) { return true; } return false; } private function determineCompressionEncoding(array $responseHeaders): int { if (!$this->hasZlib) { return 0; } if (!isset($responseHeaders["content-encoding"])) { return 0; } $contentEncodingHeader = \trim(\current($responseHeaders["content-encoding"])); if (strcasecmp($contentEncodingHeader, 'gzip') === 0) { return \ZLIB_ENCODING_GZIP; } if (strcasecmp($contentEncodingHeader, 'deflate') === 0) { return \ZLIB_ENCODING_DEFLATE; } return 0; } private function storeResponseCookie(string $requestDomain, string $rawCookieStr) { try { $cookie = Cookie::fromString($rawCookieStr); if (!$cookie->getDomain()) { $cookie = $cookie->withDomain($requestDomain); } else { // https://tools.ietf.org/html/rfc6265#section-4.1.2.3 $cookieDomain = $cookie->getDomain(); // If a domain is set, left dots are ignored and it's always a wildcard $cookieDomain = \ltrim($cookieDomain, "."); if ($cookieDomain !== $requestDomain) { // ignore cookies on domains that are public suffixes if (PublicSuffixList::isPublicSuffix($cookieDomain)) { return; } // cookie origin would not be included when sending the cookie if (\substr($requestDomain, 0, -\strlen($cookieDomain) - 1) . "." . $cookieDomain !== $requestDomain) { return; } } // always add the dot, it's used internally for wildcard matching when an explicit domain is sent $cookie = $cookie->withDomain("." . $cookieDomain); } $this->cookieJar->store($cookie); } catch (CookieFormatException $e) { // Ignore malformed Set-Cookie headers } } private function getRedirectUri(Response $response) { if (!$response->hasHeader('Location')) { return null; } $request = $response->getRequest(); $status = $response->getStatus(); $method = $request->getMethod(); if ($status < 300 || $status > 399 || $method === 'HEAD') { return null; } $requestUri = new Uri($request->getUri()); $redirectLocation = $response->getHeader('Location'); try { return $requestUri->resolve($redirectLocation); } catch (InvalidUriException $e) { return null; } } /** * Clients must not add a Referer header when leaving an unencrypted resource and redirecting to an encrypted * resource. * * @param Request $request * @param string $refererUri * @param string $newUri * * @return Request * * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3 */ private function assignRedirectRefererHeader(Request $request, string $refererUri, string $newUri): Request { $refererIsEncrypted = (\stripos($refererUri, 'https') === 0); $destinationIsEncrypted = (\stripos($newUri, 'https') === 0); if (!$refererIsEncrypted || $destinationIsEncrypted) { return $request->withHeader('Referer', $refererUri); } return $request->withoutHeader('Referer'); } /** * @param Request $request * @param string $protocolVersion * * @return string * * @TODO Send absolute URIs in the request line when using a proxy server * Right now this doesn't matter because all proxy requests use a CONNECT * tunnel but this likely will not always be the case. */ private function generateRawRequestHeaders(Request $request, string $protocolVersion): string { $uri = $request->getUri(); $uri = new Uri($uri); $requestUri = $uri->getPath() ?: '/'; if ($query = $uri->getQuery()) { $requestUri .= '?' . $query; } $head = $request->getMethod() . ' ' . $requestUri . ' HTTP/' . $protocolVersion . "\r\n"; foreach ($request->getHeaders(true) as $field => $values) { if (\strcspn($field, "\r\n") !== \strlen($field)) { throw new HttpException("Blocked header injection attempt for header '{$field}'"); } foreach ($values as $value) { if (\strcspn($value, "\r\n") !== \strlen($value)) { throw new HttpException("Blocked header injection attempt for header '{$field}' with value '{$value}'"); } $head .= "{$field}: {$value}\r\n"; } } $head .= "\r\n"; return $head; } /** * Set multiple options at once. * * @param array $options An array of the form [OP_CONSTANT => $value] * * @throws \Error On unknown option key or invalid value. */ public function setOptions(array $options) { foreach ($options as $option => $value) { $this->setOption($option, $value); } } /** * Set an option. * * @param string $option A Client option constant * @param mixed $value The option value to assign * * @throws \Error On unknown option key or invalid value. */ public function setOption(string $option, $value) { $this->validateOption($option, $value); $this->options[$option] = $value; } private function validateOption(string $option, $value) { switch ($option) { case self::OP_AUTO_ENCODING: if (!\is_bool($value)) { throw new \TypeError("Invalid value for OP_AUTO_ENCODING, bool expected"); } break; case self::OP_TRANSFER_TIMEOUT: if (!\is_int($value) || $value < 0) { throw new \Error("Invalid value for OP_TRANSFER_TIMEOUT, int >= 0 expected"); } break; case self::OP_MAX_REDIRECTS: if (!\is_int($value) || $value < 0) { throw new \Error("Invalid value for OP_MAX_REDIRECTS, int >= 0 expected"); } break; case self::OP_AUTO_REFERER: if (!\is_bool($value)) { throw new \TypeError("Invalid value for OP_AUTO_REFERER, bool expected"); } break; case self::OP_DISCARD_BODY: if (!\is_bool($value)) { throw new \TypeError("Invalid value for OP_DISCARD_BODY, bool expected"); } break; case self::OP_DEFAULT_HEADERS: // We attempt to set the headers here, because they're automatically validated then. (new Request("https://example.com/"))->withHeaders($value); break; case self::OP_MAX_HEADER_BYTES: if (!\is_int($value) || $value < 0) { throw new \Error("Invalid value for OP_MAX_HEADER_BYTES, int >= 0 expected"); } break; case self::OP_MAX_BODY_BYTES: if (!\is_int($value) || $value < 0) { throw new \Error("Invalid value for OP_MAX_BODY_BYTES, int >= 0 expected"); } break; default: throw new \Error( sprintf("Unknown option: %s", $option) ); } } private function collectConnectionInfo(ClientSocket $socket): ConnectionInfo { $stream = $socket->getResource(); if ($stream === null) { throw new SocketException("Socket closed before connection information could be collected"); } $crypto = \stream_get_meta_data($stream)["crypto"] ?? null; return new ConnectionInfo( $socket->getLocalAddress(), $socket->getRemoteAddress(), $crypto ? TlsInfo::fromMetaData($crypto, \stream_context_get_options($stream)["ssl"]) : null ); } } <?php namespace Amp\Artax; use Amp\CancellationToken; use Amp\Failure; use Amp\Promise; use Amp\Socket\BasicSocketPool; use Amp\Socket\ClientSocket; use Amp\Socket\SocketPool; use Amp\Success; use Amp\Uri\Uri; use function Amp\call; class HttpSocketPool implements SocketPool { const OP_PROXY_HTTP = 'amp.artax.httpsocketpool.proxy-http'; const OP_PROXY_HTTPS = 'amp.artax.httpsocketpool.proxy-https'; private $socketPool; private $tunneler; private $options = [ self::OP_PROXY_HTTP => null, self::OP_PROXY_HTTPS => null, ]; public function __construct(SocketPool $sockPool = null, HttpTunneler $tunneler = null) { $this->socketPool = $sockPool ?? new BasicSocketPool; $this->tunneler = $tunneler ?? new HttpTunneler; $this->autoDetectProxySettings(); } private function autoDetectProxySettings() { // See CVE-2016-5385, due to (emulation of) header copying with PHP web SAPIs into HTTP_* variables, // HTTP_PROXY can be set by an user to any value he wants by setting the Proxy header. // Mitigate the vulnerability by only allowing CLI SAPIs to use HTTP(S)_PROXY environment variables. if (PHP_SAPI !== "cli" && PHP_SAPI !== "phpdbg" && PHP_SAPI !== "embed") { return; } if (($httpProxy = \getenv('http_proxy')) || ($httpProxy = \getenv('HTTP_PROXY'))) { $this->options[self::OP_PROXY_HTTP] = $this->getUriAuthority($httpProxy); } if (($httpsProxy = \getenv('https_proxy')) || ($httpsProxy = \getenv('HTTPS_PROXY'))) { $this->options[self::OP_PROXY_HTTPS] = $this->getUriAuthority($httpsProxy); } } private function getUriAuthority(string $uri): string { $parsedUri = new Uri($uri); return $parsedUri->getHost() . ":" . $parsedUri->getPort(); } /** @inheritdoc */ public function checkout(string $uri, CancellationToken $cancellationToken = null): Promise { $parsedUri = new Uri($uri); $scheme = $parsedUri->getScheme(); if ($scheme === 'tcp' || $scheme === 'http') { $proxy = $this->options[self::OP_PROXY_HTTP]; } elseif ($scheme === 'tls' || $scheme === 'https') { $proxy = $this->options[self::OP_PROXY_HTTPS]; } else { return new Failure(new \Error( 'Either tcp://, tls://, http:// or https:// URI scheme required for HTTP socket checkout' )); } // The underlying TCP pool will ignore the URI fragment when connecting but retain it in the // name when tracking hostname connection counts. This allows us to expose host connection // limits transparently even when connecting through a proxy. $authority = $parsedUri->getHost() . ":" . $parsedUri->getPort(); if (!$proxy) { return $this->socketPool->checkout("tcp://{$authority}", $cancellationToken); } return call(function () use ($proxy, $authority, $cancellationToken) { $socket = yield $this->socketPool->checkout("tcp://{$proxy}#{$authority}", $cancellationToken); yield $this->tunnelThroughProxy($socket, $authority); return $socket; }); } private function tunnelThroughProxy(ClientSocket $socket, $authority): Promise { if (empty(stream_context_get_options($socket->getResource())['artax*']['is_tunneled'])) { return $this->tunneler->tunnel($socket, $authority); } return new Success; } /** @inheritdoc */ public function checkin(ClientSocket $socket) { $this->socketPool->checkin($socket); } /** @inheritdoc */ public function clear(ClientSocket $socket) { $this->socketPool->clear($socket); } /** @inheritdoc */ public function setOption(string $option, $value) { switch ($option) { case self::OP_PROXY_HTTP: $this->options[self::OP_PROXY_HTTP] = (string) $value; break; case self::OP_PROXY_HTTPS: $this->options[self::OP_PROXY_HTTPS] = (string) $value; break; default: throw new \Error("Invalid option: $option"); } } } <?php namespace Amp\Artax; class TooManyRedirectsException extends HttpException { private $response; public function __construct(Response $response) { parent::__construct("There were too many redirects"); $this->response = $response; } public function getResponse(): Response { return $this->response; } } <?php namespace Amp\Artax; use Amp\ByteStream\InMemoryStream; use Amp\ByteStream\InputStream; use Amp\Promise; use Amp\Success; final class StringBody implements RequestBody { private $body; public function __construct(string $body) { $this->body = $body; } public function createBodyStream(): InputStream { return new InMemoryStream($this->body); } public function getHeaders(): Promise { return new Success([]); } public function getBodyLength(): Promise { return new Success(\strlen($this->body)); } } <?php namespace Amp\Artax; use Amp\ByteStream\InMemoryStream; use Amp\ByteStream\InputStream; use Amp\ByteStream\IteratorStream; use Amp\Producer; use Amp\Promise; use Amp\Success; use function Amp\call; final class FormBody implements RequestBody { private $fields = []; private $boundary; private $isMultipart = false; private $cachedBody; private $cachedLength; private $cachedFields; /** * @param string $boundary An optional multipart boundary string */ public function __construct(string $boundary = null) { $this->boundary = $boundary ?? \bin2hex(\random_bytes(16)); } /** * Add a data field to the form entity body. * * @param string $name * @param string $value * @param string $contentType */ public function addField(string $name, string $value, string $contentType = 'text/plain') { $this->fields[] = [$name, $value, $contentType, null]; $this->resetCache(); } /** * Add each element of a associative array as a data field to the form entity body. * * @param array $data * @param string $contentType */ public function addFields(array $data, string $contentType = 'text/plain') { foreach ($data as $key => $value) { $this->addField($key, $value, $contentType); } } /** * Add a file field to the form entity body. * * @param string $name * @param string $filePath * @param string $contentType */ public function addFile(string $name, string $filePath, string $contentType = 'application/octet-stream') { $fileName = \basename($filePath); $this->fields[] = [$name, new FileBody($filePath), $contentType, $fileName]; $this->isMultipart = true; $this->resetCache(); } /** * Add each element of a associative array as a file field to the form entity body. * * @param array $data * @param string $contentType */ public function addFiles(array $data, string $contentType = 'application/octet-stream') { foreach ($data as $key => $value) { $this->addFile($key, $value, $contentType); } } /** * Returns an array of fields, each being an array of [name, value, content-type, file-name|null]. * Both fields and files are returned in the array. Files use a FileBody object as the value. The file-name is * always null for fields. * * @return array */ public function getFields(): array { return $this->fields; } private function resetCache() { $this->cachedBody = null; $this->cachedLength = null; $this->cachedFields = null; } public function createBodyStream(): InputStream { if ($this->isMultipart) { return $this->generateMultipartStreamFromFields($this->getMultipartFieldArray()); } return new InMemoryStream($this->getFormEncodedBodyString()); } private function getMultipartFieldArray(): array { if (isset($this->cachedFields)) { return $this->cachedFields; } $fields = []; foreach ($this->fields as $fieldArr) { list($name, $field, $contentType, $fileName) = $fieldArr; $fields[] = "--{$this->boundary}\r\n"; $fields[] = $field instanceof FileBody ? $this->generateMultipartFileHeader($name, $fileName, $contentType) : $this->generateMultipartFieldHeader($name, $contentType); $fields[] = $field; $fields[] = "\r\n"; } $fields[] = "--{$this->boundary}--\r\n"; return $this->cachedFields = $fields; } private function generateMultipartFileHeader(string $name, string $fileName, string $contentType): string { $header = "Content-Disposition: form-data; name=\"{$name}\"; filename=\"{$fileName}\"\r\n"; $header .= "Content-Type: {$contentType}\r\n"; $header .= "Content-Transfer-Encoding: binary\r\n\r\n"; return $header; } private function generateMultipartFieldHeader(string $name, string $contentType): string { $header = "Content-Disposition: form-data; name=\"{$name}\"\r\n"; if ($contentType !== "") { $header .= "Content-Type: {$contentType}\r\n\r\n"; } else { $header .= "\r\n"; } return $header; } private function generateMultipartStreamFromFields(array $fields): InputStream { foreach ($fields as $key => $field) { $fields[$key] = $field instanceof FileBody ? $field->createBodyStream() : new InMemoryStream($field); } return new IteratorStream(new Producer(function (callable $emit) use ($fields) { foreach ($fields as $key => $stream) { while (($chunk = yield $stream->read()) !== null) { yield $emit($chunk); } } })); } private function getFormEncodedBodyString(): string { if ($this->cachedBody) { return $this->cachedBody; } $fields = []; foreach ($this->fields as $fieldArr) { list($name, $value) = $fieldArr; $fields[$name][] = $value; } foreach ($fields as $key => $value) { $fields[$key] = isset($value[1]) ? $value : $value[0]; } return $this->cachedBody = \http_build_query($fields); } public function getHeaders(): Promise { return new Success([ 'Content-Type' => $this->determineContentType(), ]); } private function determineContentType() { return $this->isMultipart ? "multipart/form-data; boundary={$this->boundary}" : 'application/x-www-form-urlencoded'; } public function getBodyLength(): Promise { if ($this->cachedLength) { return $this->cachedLength; } if (!$this->isMultipart) { return $this->cachedLength = new Success(\strlen($this->getFormEncodedBodyString())); } return $this->cachedLength = call(function () { $fields = $this->getMultipartFieldArray(); $length = 0; foreach ($fields as $field) { if (\is_string($field)) { $length += \strlen($field); } else { $length += yield $field->getBodyLength(); } } return $length; }); } } <?php namespace Amp\Artax; class SocketException extends HttpException { } <?php namespace Amp\Artax; /** * An HTTP request. */ final class Request { /** @var string[] */ private $protocolVersions = ["1.1", "2.0"]; /** @var string */ private $method; /** @var string */ private $uri; /** @var array headers with lowercase keys */ private $headers = []; /** @var array lowercase header to actual case map */ private $headerCaseMap = []; /** @var RequestBody */ private $body; public function __construct(string $uri, string $method = "GET") { $this->uri = $uri; $this->method = $method; $this->body = new StringBody(""); } /** * Retrieve the requests's acceptable HTTP protocol versions. * * @return string[] */ public function getProtocolVersions(): array { return $this->protocolVersions; } /** * Assign the requests's acceptable HTTP protocol versions. * * The HTTP client might choose any of these. * * @param string[] $versions * * @return Request */ public function withProtocolVersions(array $versions): self { $versions = \array_unique($versions); if (empty($versions)) { throw new \Error("Empty array of protocol versions provided, must not be empty."); } foreach ($versions as $version) { if (!\in_array($version, ["1.0", "1.1", "2.0"], true)) { throw new \Error( "Invalid HTTP protocol version: " . $version ); } } if ($this->protocolVersions === $versions) { return $this; } $clone = clone $this; $clone->protocolVersions = $versions; return $clone; } /** * Retrieve the request's HTTP method verb. * * @return string */ public function getMethod(): string { return $this->method; } /** * Specify the request's HTTP method verb. * * @param string $method * * @return Request */ public function withMethod(string $method): self { if ($this->method === $method) { return $this; } $clone = clone $this; $clone->method = $method; return $clone; } /** * Retrieve the request's URI. * * @return string */ public function getUri(): string { return $this->uri; } /** * Specify the request's HTTP URI. * * @param string * * @return Request */ public function withUri(string $uri): self { $clone = clone $this; $clone->uri = $uri; return $clone; } /** * Does the message contain the specified header field (case-insensitive)? * * @param string $field Header name. * * @return bool */ public function hasHeader(string $field): bool { return isset($this->headers[\strtolower($field)]); } /** * Retrieve the first occurrence of the specified header in the message. * * If multiple headers exist for the specified field only the value of the first header is returned. Applications * may use `getHeaderArray()` to retrieve a list of all header values received for a given field. * * A `null` return indicates the requested header field was not present. * * @param string $field Header name. * * @return string|null Header value or `null` if no header with name `$field` exists. */ public function getHeader(string $field) { return $this->headers[\strtolower($field)][0] ?? null; } /** * Retrieve all occurrences of the specified header in the message. * * Applications may use `getHeader()` to access only the first occurrence. * * @param string $field Header name. * * @return array Header values. */ public function getHeaderArray(string $field): array { return $this->headers[\strtolower($field)] ?? []; } /** * Assign a value for the specified header field by replacing any existing values for that field. * * @param string $field Header name. * @param string $value Header value. * * @return Request */ public function withHeader(string $field, string $value): self { $field = \trim($field); $lower = \strtolower($field); $clone = clone $this; $clone->headers[$lower] = [\trim($value)]; $clone->headerCaseMap[$lower] = $field; return $clone; } /** * Assign a value for the specified header field by adding an additional header line. * * @param string $field Header name. * @param string $value Header value. * * @return Request */ public function withAddedHeader(string $field, string $value): self { $field = \trim($field); $lower = \strtolower($field); $clone = clone $this; $headers = $clone->headers[$lower] ?? []; $headers[] = \trim($value); $clone->headers[$lower] = $headers; $clone->headerCaseMap[$lower] = $field; return $clone; } public function withHeaders(array $headers): self { $clone = clone $this; foreach ($headers as $field => $values) { if (!\is_string($field) && !\is_int($field)) { // PHP converts integer strings automatically to integers. // Later versions of PHP might allow other key types. // @codeCoverageIgnoreStart throw new \TypeError("All array keys for withHeaders must be strings"); // @codeCoverageIgnoreEnd } $field = \trim($field); $lower = \strtolower($field); if (!\is_array($values)) { $values = [$values]; } $clone->headers[$lower] = []; foreach ($values as $value) { if (!\is_string($value) && !\is_int($value) && !\is_float($value) && !(is_object($value) && method_exists($value, '__toString')) ) { throw new \TypeError("All values for withHeaders must be string or an array of strings"); } $clone->headers[$lower][] = \trim($value); } $clone->headerCaseMap[$lower] = $field; if (empty($clone->headers[$lower])) { unset($clone->headers[$lower], $clone->headerCaseMap[$lower]); } } return $clone; } /** * Retrieve an associative array of headers matching field names to an array of field values. * * @param bool $originalCase If true, headers are returned in the case of the last set header with that name. * * @return array */ public function getHeaders(bool $originalCase = false): array { if (!$originalCase) { return $this->headers; } $headers = []; foreach ($this->headers as $header => $values) { $headers[$this->headerCaseMap[$header]] = $values; } return $headers; } /** * Remove the specified header field from the message. * * @param string $field Header name. * * @return Request */ public function withoutHeader(string $field): self { $lower = \strtolower($field); $clone = clone $this; unset( $clone->headerCaseMap[$lower], $clone->headers[$lower] ); return $clone; } /** * Retrieve the message entity body. * * @return mixed */ public function getBody(): RequestBody { return $this->body; } /** * Assign the message entity body. * * @param mixed $body * * @return Request */ public function withBody($body): self { $clone = clone $this; if ($body === null) { $clone->body = new StringBody(""); } elseif (\is_scalar($body)) { $clone->body = new StringBody((string) $body); } elseif ($body instanceof RequestBody) { $clone->body = $body; } else { throw new \TypeError("Invalid body type: " . gettype($body)); } return $clone; } } <?php namespace Amp\Artax; use Amp\Artax\Internal\Parser; use Amp\ByteStream\StreamException; use Amp\Promise; use Amp\Socket\ClientSocket; use function Amp\call; class HttpTunneler { /** * Establish an HTTP tunnel to the specified authority over this socket. * * @param ClientSocket $socket * @param string $authority * * @return Promise */ public function tunnel(ClientSocket $socket, string $authority): Promise { return call(function () use ($socket, $authority) { $parser = new Parser(null); $parser->enqueueResponseMethodMatch("CONNECT"); try { yield $socket->write("CONNECT {$authority} HTTP/1.1\r\n\r\n"); } catch (StreamException $e) { new SocketException( 'Proxy CONNECT failed: Socket went away while writing tunneling request', 0, $e ); } try { while (null !== $chunk = yield $socket->read()) { if (!$response = $parser->parse($chunk)) { continue; } if ($response["status"] === 200) { // Tunnel connected! We're finished \o/ #WinningAtLife #DealWithIt \stream_context_set_option($socket->getResource(), 'artax*', 'is_tunneled', true); return $socket->getResource(); } throw new HttpException(\sprintf( 'Proxy CONNECT failed: Unexpected response status received from proxy: %d', $response["status"] )); } } catch (ParseException $e) { throw new HttpException( 'Proxy CONNECT failed: Malformed HTTP response received from proxy while establishing tunnel', 0, $e ); } catch (StreamException $e) { // fall through } throw new SocketException( 'Proxy CONNECT failed: Socket went away while awaiting tunneling response', 0, $e ?? null ); }); } } <?php namespace Amp\Artax; use Amp\ByteStream\InputStream; use Amp\Promise; use Amp\Success; use function Amp\call; use function Amp\File\open; use function Amp\File\size; final class FileBody implements RequestBody { /** @var string */ private $path; /** * @param string $path The filesystem path for the file we wish to send */ public function __construct(string $path) { $this->path = $path; } public function createBodyStream(): InputStream { $handlePromise = open($this->path, "r"); return new class($handlePromise) implements InputStream { /** @var Promise */ private $promise; /** @var InputStream */ private $stream; public function __construct(Promise $promise) { $this->promise = $promise; $this->promise->onResolve(function ($error, $stream) { if ($error) { return; } $this->stream = $stream; }); } public function read(): Promise { if (!$this->stream) { return call(function () { /** @var InputStream $stream */ $stream = yield $this->promise; return $stream->read(); }); } return $this->stream->read(); } }; } public function getHeaders(): Promise { return new Success([]); } public function getBodyLength(): Promise { return size($this->path); } } // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. // Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, // rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. // Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. // ===BEGIN ICANN DOMAINS=== // ac : https://en.wikipedia.org/wiki/.ac ac com.ac edu.ac gov.ac net.ac mil.ac org.ac // ad : https://en.wikipedia.org/wiki/.ad ad nom.ad // ae : https://en.wikipedia.org/wiki/.ae // see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php ae co.ae net.ae org.ae sch.ae ac.ae gov.ae mil.ae // aero : see https://www.information.aero/index.php?id=66 aero accident-investigation.aero accident-prevention.aero aerobatic.aero aeroclub.aero aerodrome.aero agents.aero aircraft.aero airline.aero airport.aero air-surveillance.aero airtraffic.aero air-traffic-control.aero ambulance.aero amusement.aero association.aero author.aero ballooning.aero broker.aero caa.aero cargo.aero catering.aero certification.aero championship.aero charter.aero civilaviation.aero club.aero conference.aero consultant.aero consulting.aero control.aero council.aero crew.aero design.aero dgca.aero educator.aero emergency.aero engine.aero engineer.aero entertainment.aero equipment.aero exchange.aero express.aero federation.aero flight.aero freight.aero fuel.aero gliding.aero government.aero groundhandling.aero group.aero hanggliding.aero homebuilt.aero insurance.aero journal.aero journalist.aero leasing.aero logistics.aero magazine.aero maintenance.aero media.aero microlight.aero modelling.aero navigation.aero parachuting.aero paragliding.aero passenger-association.aero pilot.aero press.aero production.aero recreation.aero repbody.aero res.aero research.aero rotorcraft.aero safety.aero scientist.aero services.aero show.aero skydiving.aero software.aero student.aero trader.aero trading.aero trainer.aero union.aero workinggroup.aero works.aero // af : http://www.nic.af/help.jsp af gov.af com.af org.af net.af edu.af // ag : http://www.nic.ag/prices.htm ag com.ag org.ag net.ag co.ag nom.ag // ai : http://nic.com.ai/ ai off.ai com.ai net.ai org.ai // al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 al com.al edu.al gov.al mil.al net.al org.al // am : https://en.wikipedia.org/wiki/.am am // ao : https://en.wikipedia.org/wiki/.ao // http://www.dns.ao/REGISTR.DOC ao ed.ao gv.ao og.ao co.ao pb.ao it.ao // aq : https://en.wikipedia.org/wiki/.aq aq // ar : https://nic.ar/nic-argentina/normativa-vigente ar com.ar edu.ar gob.ar gov.ar int.ar mil.ar musica.ar net.ar org.ar tur.ar // arpa : https://en.wikipedia.org/wiki/.arpa // Confirmed by registry <iana-questions@icann.org> 2008-06-18 arpa e164.arpa in-addr.arpa ip6.arpa iris.arpa uri.arpa urn.arpa // as : https://en.wikipedia.org/wiki/.as as gov.as // asia : https://en.wikipedia.org/wiki/.asia asia // at : https://en.wikipedia.org/wiki/.at // Confirmed by registry <it@nic.at> 2008-06-17 at ac.at co.at gv.at or.at // au : https://en.wikipedia.org/wiki/.au // http://www.auda.org.au/ au // 2LDs com.au net.au org.au edu.au gov.au asn.au id.au // Historic 2LDs (closed to new registration, but sites still exist) info.au conf.au oz.au // CGDNs - http://www.cgdn.org.au/ act.au nsw.au nt.au qld.au sa.au tas.au vic.au wa.au // 3LDs act.edu.au nsw.edu.au nt.edu.au qld.edu.au sa.edu.au tas.edu.au vic.edu.au wa.edu.au // act.gov.au Bug 984824 - Removed at request of Greg Tankard // nsw.gov.au Bug 547985 - Removed at request of <Shae.Donelan@services.nsw.gov.au> // nt.gov.au Bug 940478 - Removed at request of Greg Connors <Greg.Connors@nt.gov.au> qld.gov.au sa.gov.au tas.gov.au vic.gov.au wa.gov.au // aw : https://en.wikipedia.org/wiki/.aw aw com.aw // ax : https://en.wikipedia.org/wiki/.ax ax // az : https://en.wikipedia.org/wiki/.az az com.az net.az int.az gov.az org.az edu.az info.az pp.az mil.az name.az pro.az biz.az // ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf ba com.ba edu.ba gov.ba mil.ba net.ba org.ba // bb : https://en.wikipedia.org/wiki/.bb bb biz.bb co.bb com.bb edu.bb gov.bb info.bb net.bb org.bb store.bb tv.bb // bd : https://en.wikipedia.org/wiki/.bd *.bd // be : https://en.wikipedia.org/wiki/.be // Confirmed by registry <tech@dns.be> 2008-06-08 be ac.be // bf : https://en.wikipedia.org/wiki/.bf bf gov.bf // bg : https://en.wikipedia.org/wiki/.bg // https://www.register.bg/user/static/rules/en/index.html bg a.bg b.bg c.bg d.bg e.bg f.bg g.bg h.bg i.bg j.bg k.bg l.bg m.bg n.bg o.bg p.bg q.bg r.bg s.bg t.bg u.bg v.bg w.bg x.bg y.bg z.bg 0.bg 1.bg 2.bg 3.bg 4.bg 5.bg 6.bg 7.bg 8.bg 9.bg // bh : https://en.wikipedia.org/wiki/.bh bh com.bh edu.bh net.bh org.bh gov.bh // bi : https://en.wikipedia.org/wiki/.bi // http://whois.nic.bi/ bi co.bi com.bi edu.bi or.bi org.bi // biz : https://en.wikipedia.org/wiki/.biz biz // bj : https://en.wikipedia.org/wiki/.bj bj asso.bj barreau.bj gouv.bj // bm : http://www.bermudanic.bm/dnr-text.txt bm com.bm edu.bm gov.bm net.bm org.bm // bn : https://en.wikipedia.org/wiki/.bn *.bn // bo : http://www.nic.bo/ bo com.bo edu.bo gov.bo gob.bo int.bo org.bo net.bo mil.bo tv.bo // br : http://registro.br/dominio/categoria.html // Submitted by registry <fneves@registro.br> br adm.br adv.br agr.br am.br arq.br art.br ato.br b.br bio.br blog.br bmd.br cim.br cng.br cnt.br com.br coop.br ecn.br eco.br edu.br emp.br eng.br esp.br etc.br eti.br far.br flog.br fm.br fnd.br fot.br fst.br g12.br ggf.br gov.br imb.br ind.br inf.br jor.br jus.br leg.br lel.br mat.br med.br mil.br mp.br mus.br net.br *.nom.br not.br ntr.br odo.br org.br ppg.br pro.br psc.br psi.br qsl.br radio.br rec.br slg.br srv.br taxi.br teo.br tmp.br trd.br tur.br tv.br vet.br vlog.br wiki.br zlg.br // bs : http://www.nic.bs/rules.html bs com.bs net.bs org.bs edu.bs gov.bs // bt : https://en.wikipedia.org/wiki/.bt bt com.bt edu.bt gov.bt net.bt org.bt // bv : No registrations at this time. // Submitted by registry <jarle@uninett.no> bv // bw : https://en.wikipedia.org/wiki/.bw // http://www.gobin.info/domainname/bw.doc // list of other 2nd level tlds ? bw co.bw org.bw // by : https://en.wikipedia.org/wiki/.by // http://tld.by/rules_2006_en.html // list of other 2nd level tlds ? by gov.by mil.by // Official information does not indicate that com.by is a reserved // second-level domain, but it's being used as one (see www.google.com.by and // www.yahoo.com.by, for example), so we list it here for safety's sake. com.by // http://hoster.by/ of.by // bz : https://en.wikipedia.org/wiki/.bz // http://www.belizenic.bz/ bz com.bz net.bz org.bz edu.bz gov.bz // ca : https://en.wikipedia.org/wiki/.ca ca // ca geographical names ab.ca bc.ca mb.ca nb.ca nf.ca nl.ca ns.ca nt.ca nu.ca on.ca pe.ca qc.ca sk.ca yk.ca // gc.ca: https://en.wikipedia.org/wiki/.gc.ca // see also: http://registry.gc.ca/en/SubdomainFAQ gc.ca // cat : https://en.wikipedia.org/wiki/.cat cat // cc : https://en.wikipedia.org/wiki/.cc cc // cd : https://en.wikipedia.org/wiki/.cd // see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 cd gov.cd // cf : https://en.wikipedia.org/wiki/.cf cf // cg : https://en.wikipedia.org/wiki/.cg cg // ch : https://en.wikipedia.org/wiki/.ch ch // ci : https://en.wikipedia.org/wiki/.ci // http://www.nic.ci/index.php?page=charte ci org.ci or.ci com.ci co.ci edu.ci ed.ci ac.ci net.ci go.ci asso.ci aéroport.ci int.ci presse.ci md.ci gouv.ci // ck : https://en.wikipedia.org/wiki/.ck *.ck !www.ck // cl : https://en.wikipedia.org/wiki/.cl cl gov.cl gob.cl co.cl mil.cl // cm : https://en.wikipedia.org/wiki/.cm plus bug 981927 cm co.cm com.cm gov.cm net.cm // cn : https://en.wikipedia.org/wiki/.cn // Submitted by registry <tanyaling@cnnic.cn> cn ac.cn com.cn edu.cn gov.cn net.cn org.cn mil.cn 公司.cn 网络.cn 網絡.cn // cn geographic names ah.cn bj.cn cq.cn fj.cn gd.cn gs.cn gz.cn gx.cn ha.cn hb.cn he.cn hi.cn hl.cn hn.cn jl.cn js.cn jx.cn ln.cn nm.cn nx.cn qh.cn sc.cn sd.cn sh.cn sn.cn sx.cn tj.cn xj.cn xz.cn yn.cn zj.cn hk.cn mo.cn tw.cn // co : https://en.wikipedia.org/wiki/.co // Submitted by registry <tecnico@uniandes.edu.co> co arts.co com.co edu.co firm.co gov.co info.co int.co mil.co net.co nom.co org.co rec.co web.co // com : https://en.wikipedia.org/wiki/.com com // coop : https://en.wikipedia.org/wiki/.coop coop // cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do cr ac.cr co.cr ed.cr fi.cr go.cr or.cr sa.cr // cu : https://en.wikipedia.org/wiki/.cu cu com.cu edu.cu org.cu net.cu gov.cu inf.cu // cv : https://en.wikipedia.org/wiki/.cv cv // cw : http://www.una.cw/cw_registry/ // Confirmed by registry <registry@una.net> 2013-03-26 cw com.cw edu.cw net.cw org.cw // cx : https://en.wikipedia.org/wiki/.cx // list of other 2nd level tlds ? cx gov.cx // cy : http://www.nic.cy/ // Submitted by registry Panayiotou Fotia <cydns@ucy.ac.cy> cy ac.cy biz.cy com.cy ekloges.cy gov.cy ltd.cy name.cy net.cy org.cy parliament.cy press.cy pro.cy tm.cy // cz : https://en.wikipedia.org/wiki/.cz cz // de : https://en.wikipedia.org/wiki/.de // Confirmed by registry <ops@denic.de> (with technical // reservations) 2008-07-01 de // dj : https://en.wikipedia.org/wiki/.dj dj // dk : https://en.wikipedia.org/wiki/.dk // Confirmed by registry <robert@dk-hostmaster.dk> 2008-06-17 dk // dm : https://en.wikipedia.org/wiki/.dm dm com.dm net.dm org.dm edu.dm gov.dm // do : https://en.wikipedia.org/wiki/.do do art.do com.do edu.do gob.do gov.do mil.do net.do org.do sld.do web.do // dz : https://en.wikipedia.org/wiki/.dz dz com.dz org.dz net.dz gov.dz edu.dz asso.dz pol.dz art.dz // ec : http://www.nic.ec/reg/paso1.asp // Submitted by registry <vabboud@nic.ec> ec com.ec info.ec net.ec fin.ec k12.ec med.ec pro.ec org.ec edu.ec gov.ec gob.ec mil.ec // edu : https://en.wikipedia.org/wiki/.edu edu // ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B ee edu.ee gov.ee riik.ee lib.ee med.ee com.ee pri.ee aip.ee org.ee fie.ee // eg : https://en.wikipedia.org/wiki/.eg eg com.eg edu.eg eun.eg gov.eg mil.eg name.eg net.eg org.eg sci.eg // er : https://en.wikipedia.org/wiki/.er *.er // es : https://www.nic.es/site_ingles/ingles/dominios/index.html es com.es nom.es org.es gob.es edu.es // et : https://en.wikipedia.org/wiki/.et et com.et gov.et org.et edu.et biz.et name.et info.et net.et // eu : https://en.wikipedia.org/wiki/.eu eu // fi : https://en.wikipedia.org/wiki/.fi fi // aland.fi : https://en.wikipedia.org/wiki/.ax // This domain is being phased out in favor of .ax. As there are still many // domains under aland.fi, we still keep it on the list until aland.fi is // completely removed. // TODO: Check for updates (expected to be phased out around Q1/2009) aland.fi // fj : https://en.wikipedia.org/wiki/.fj *.fj // fk : https://en.wikipedia.org/wiki/.fk *.fk // fm : https://en.wikipedia.org/wiki/.fm fm // fo : https://en.wikipedia.org/wiki/.fo fo // fr : http://www.afnic.fr/ // domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs fr com.fr asso.fr nom.fr prd.fr presse.fr tm.fr // domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels aeroport.fr assedic.fr avocat.fr avoues.fr cci.fr chambagri.fr chirurgiens-dentistes.fr experts-comptables.fr geometre-expert.fr gouv.fr greta.fr huissier-justice.fr medecin.fr notaires.fr pharmacien.fr port.fr veterinaire.fr // ga : https://en.wikipedia.org/wiki/.ga ga // gb : This registry is effectively dormant // Submitted by registry <Damien.Shaw@ja.net> gb // gd : https://en.wikipedia.org/wiki/.gd gd // ge : http://www.nic.net.ge/policy_en.pdf ge com.ge edu.ge gov.ge org.ge mil.ge net.ge pvt.ge // gf : https://en.wikipedia.org/wiki/.gf gf // gg : http://www.channelisles.net/register-domains/ // Confirmed by registry <nigel@channelisles.net> 2013-11-28 gg co.gg net.gg org.gg // gh : https://en.wikipedia.org/wiki/.gh // see also: http://www.nic.gh/reg_now.php // Although domains directly at second level are not possible at the moment, // they have been possible for some time and may come back. gh com.gh edu.gh gov.gh org.gh mil.gh // gi : http://www.nic.gi/rules.html gi com.gi ltd.gi gov.gi mod.gi edu.gi org.gi // gl : https://en.wikipedia.org/wiki/.gl // http://nic.gl gl co.gl com.gl edu.gl net.gl org.gl // gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm gm // gn : http://psg.com/dns/gn/gn.txt // Submitted by registry <randy@psg.com> gn ac.gn com.gn edu.gn gov.gn org.gn net.gn // gov : https://en.wikipedia.org/wiki/.gov gov // gp : http://www.nic.gp/index.php?lang=en gp com.gp net.gp mobi.gp edu.gp org.gp asso.gp // gq : https://en.wikipedia.org/wiki/.gq gq // gr : https://grweb.ics.forth.gr/english/1617-B-2005.html // Submitted by registry <segred@ics.forth.gr> gr com.gr edu.gr net.gr org.gr gov.gr // gs : https://en.wikipedia.org/wiki/.gs gs // gt : http://www.gt/politicas_de_registro.html gt com.gt edu.gt gob.gt ind.gt mil.gt net.gt org.gt // gu : http://gadao.gov.gu/registration.txt *.gu // gw : https://en.wikipedia.org/wiki/.gw gw // gy : https://en.wikipedia.org/wiki/.gy // http://registry.gy/ gy co.gy com.gy edu.gy gov.gy net.gy org.gy // hk : https://www.hkdnr.hk // Submitted by registry <hk.tech@hkirc.hk> hk com.hk edu.hk gov.hk idv.hk net.hk org.hk 公司.hk 教育.hk 敎育.hk 政府.hk 個人.hk 个人.hk 箇人.hk 網络.hk 网络.hk 组織.hk 網絡.hk 网絡.hk 组织.hk 組織.hk 組织.hk // hm : https://en.wikipedia.org/wiki/.hm hm // hn : http://www.nic.hn/politicas/ps02,,05.html hn com.hn edu.hn org.hn net.hn mil.hn gob.hn // hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf hr iz.hr from.hr name.hr com.hr // ht : http://www.nic.ht/info/charte.cfm ht com.ht shop.ht firm.ht info.ht adult.ht net.ht pro.ht org.ht med.ht art.ht coop.ht pol.ht asso.ht edu.ht rel.ht gouv.ht perso.ht // hu : http://www.domain.hu/domain/English/sld.html // Confirmed by registry <pasztor@iszt.hu> 2008-06-12 hu co.hu info.hu org.hu priv.hu sport.hu tm.hu 2000.hu agrar.hu bolt.hu casino.hu city.hu erotica.hu erotika.hu film.hu forum.hu games.hu hotel.hu ingatlan.hu jogasz.hu konyvelo.hu lakas.hu media.hu news.hu reklam.hu sex.hu shop.hu suli.hu szex.hu tozsde.hu utazas.hu video.hu // id : https://register.pandi.or.id/ id ac.id biz.id co.id desa.id go.id mil.id my.id net.id or.id sch.id web.id // ie : https://en.wikipedia.org/wiki/.ie ie gov.ie // il : http://www.isoc.org.il/domains/ il ac.il co.il gov.il idf.il k12.il muni.il net.il org.il // im : https://www.nic.im/ // Submitted by registry <info@nic.im> im ac.im co.im com.im ltd.co.im net.im org.im plc.co.im tt.im tv.im // in : https://en.wikipedia.org/wiki/.in // see also: https://registry.in/Policies // Please note, that nic.in is not an official eTLD, but used by most // government institutions. in co.in firm.in net.in org.in gen.in ind.in nic.in ac.in edu.in res.in gov.in mil.in // info : https://en.wikipedia.org/wiki/.info info // int : https://en.wikipedia.org/wiki/.int // Confirmed by registry <iana-questions@icann.org> 2008-06-18 int eu.int // io : http://www.nic.io/rules.html // list of other 2nd level tlds ? io com.io // iq : http://www.cmc.iq/english/iq/iqregister1.htm iq gov.iq edu.iq mil.iq com.iq org.iq net.iq // ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules // Also see http://www.nic.ir/Internationalized_Domain_Names // Two <iran>.ir entries added at request of <tech-team@nic.ir>, 2010-04-16 ir ac.ir co.ir gov.ir id.ir net.ir org.ir sch.ir // xn--mgba3a4f16a.ir (<iran>.ir, Persian YEH) ایران.ir // xn--mgba3a4fra.ir (<iran>.ir, Arabic YEH) ايران.ir // is : http://www.isnic.is/domain/rules.php // Confirmed by registry <marius@isgate.is> 2008-12-06 is net.is com.is edu.is gov.is org.is int.is // it : https://en.wikipedia.org/wiki/.it it gov.it edu.it // Reserved geo-names: // http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf // There is also a list of reserved geo-names corresponding to Italian municipalities // http://www.nic.it/documenti/appendice-c.pdf, but it is not included here. // Regions abr.it abruzzo.it aosta-valley.it aostavalley.it bas.it basilicata.it cal.it calabria.it cam.it campania.it emilia-romagna.it emiliaromagna.it emr.it friuli-v-giulia.it friuli-ve-giulia.it friuli-vegiulia.it friuli-venezia-giulia.it friuli-veneziagiulia.it friuli-vgiulia.it friuliv-giulia.it friulive-giulia.it friulivegiulia.it friulivenezia-giulia.it friuliveneziagiulia.it friulivgiulia.it fvg.it laz.it lazio.it lig.it liguria.it lom.it lombardia.it lombardy.it lucania.it mar.it marche.it mol.it molise.it piedmont.it piemonte.it pmn.it pug.it puglia.it sar.it sardegna.it sardinia.it sic.it sicilia.it sicily.it taa.it tos.it toscana.it trentino-a-adige.it trentino-aadige.it trentino-alto-adige.it trentino-altoadige.it trentino-s-tirol.it trentino-stirol.it trentino-sud-tirol.it trentino-sudtirol.it trentino-sued-tirol.it trentino-suedtirol.it trentinoa-adige.it trentinoaadige.it trentinoalto-adige.it trentinoaltoadige.it trentinos-tirol.it trentinostirol.it trentinosud-tirol.it trentinosudtirol.it trentinosued-tirol.it trentinosuedtirol.it tuscany.it umb.it umbria.it val-d-aosta.it val-daosta.it vald-aosta.it valdaosta.it valle-aosta.it valle-d-aosta.it valle-daosta.it valleaosta.it valled-aosta.it valledaosta.it vallee-aoste.it valleeaoste.it vao.it vda.it ven.it veneto.it // Provinces ag.it agrigento.it al.it alessandria.it alto-adige.it altoadige.it an.it ancona.it andria-barletta-trani.it andria-trani-barletta.it andriabarlettatrani.it andriatranibarletta.it ao.it aosta.it aoste.it ap.it aq.it aquila.it ar.it arezzo.it ascoli-piceno.it ascolipiceno.it asti.it at.it av.it avellino.it ba.it balsan.it bari.it barletta-trani-andria.it barlettatraniandria.it belluno.it benevento.it bergamo.it bg.it bi.it biella.it bl.it bn.it bo.it bologna.it bolzano.it bozen.it br.it brescia.it brindisi.it bs.it bt.it bz.it ca.it cagliari.it caltanissetta.it campidano-medio.it campidanomedio.it campobasso.it carbonia-iglesias.it carboniaiglesias.it carrara-massa.it carraramassa.it caserta.it catania.it catanzaro.it cb.it ce.it cesena-forli.it cesenaforli.it ch.it chieti.it ci.it cl.it cn.it co.it como.it cosenza.it cr.it cremona.it crotone.it cs.it ct.it cuneo.it cz.it dell-ogliastra.it dellogliastra.it en.it enna.it fc.it fe.it fermo.it ferrara.it fg.it fi.it firenze.it florence.it fm.it foggia.it forli-cesena.it forlicesena.it fr.it frosinone.it ge.it genoa.it genova.it go.it gorizia.it gr.it grosseto.it iglesias-carbonia.it iglesiascarbonia.it im.it imperia.it is.it isernia.it kr.it la-spezia.it laquila.it laspezia.it latina.it lc.it le.it lecce.it lecco.it li.it livorno.it lo.it lodi.it lt.it lu.it lucca.it macerata.it mantova.it massa-carrara.it massacarrara.it matera.it mb.it mc.it me.it medio-campidano.it mediocampidano.it messina.it mi.it milan.it milano.it mn.it mo.it modena.it monza-brianza.it monza-e-della-brianza.it monza.it monzabrianza.it monzaebrianza.it monzaedellabrianza.it ms.it mt.it na.it naples.it napoli.it no.it novara.it nu.it nuoro.it og.it ogliastra.it olbia-tempio.it olbiatempio.it or.it oristano.it ot.it pa.it padova.it padua.it palermo.it parma.it pavia.it pc.it pd.it pe.it perugia.it pesaro-urbino.it pesarourbino.it pescara.it pg.it pi.it piacenza.it pisa.it pistoia.it pn.it po.it pordenone.it potenza.it pr.it prato.it pt.it pu.it pv.it pz.it ra.it ragusa.it ravenna.it rc.it re.it reggio-calabria.it reggio-emilia.it reggiocalabria.it reggioemilia.it rg.it ri.it rieti.it rimini.it rm.it rn.it ro.it roma.it rome.it rovigo.it sa.it salerno.it sassari.it savona.it si.it siena.it siracusa.it so.it sondrio.it sp.it sr.it ss.it suedtirol.it sv.it ta.it taranto.it te.it tempio-olbia.it tempioolbia.it teramo.it terni.it tn.it to.it torino.it tp.it tr.it trani-andria-barletta.it trani-barletta-andria.it traniandriabarletta.it tranibarlettaandria.it trapani.it trentino.it trento.it treviso.it trieste.it ts.it turin.it tv.it ud.it udine.it urbino-pesaro.it urbinopesaro.it va.it varese.it vb.it vc.it ve.it venezia.it venice.it verbania.it vercelli.it verona.it vi.it vibo-valentia.it vibovalentia.it vicenza.it viterbo.it vr.it vs.it vt.it vv.it // je : http://www.channelisles.net/register-domains/ // Confirmed by registry <nigel@channelisles.net> 2013-11-28 je co.je net.je org.je // jm : http://www.com.jm/register.html *.jm // jo : http://www.dns.jo/Registration_policy.aspx jo com.jo org.jo net.jo edu.jo sch.jo gov.jo mil.jo name.jo // jobs : https://en.wikipedia.org/wiki/.jobs jobs // jp : https://en.wikipedia.org/wiki/.jp // http://jprs.co.jp/en/jpdomain.html // Submitted by registry <info@jprs.jp> jp // jp organizational type names ac.jp ad.jp co.jp ed.jp go.jp gr.jp lg.jp ne.jp or.jp // jp prefecture type names aichi.jp akita.jp aomori.jp chiba.jp ehime.jp fukui.jp fukuoka.jp fukushima.jp gifu.jp gunma.jp hiroshima.jp hokkaido.jp hyogo.jp ibaraki.jp ishikawa.jp iwate.jp kagawa.jp kagoshima.jp kanagawa.jp kochi.jp kumamoto.jp kyoto.jp mie.jp miyagi.jp miyazaki.jp nagano.jp nagasaki.jp nara.jp niigata.jp oita.jp okayama.jp okinawa.jp osaka.jp saga.jp saitama.jp shiga.jp shimane.jp shizuoka.jp tochigi.jp tokushima.jp tokyo.jp tottori.jp toyama.jp wakayama.jp yamagata.jp yamaguchi.jp yamanashi.jp 栃木.jp 愛知.jp 愛媛.jp 兵庫.jp 熊本.jp 茨城.jp 北海道.jp 千葉.jp 和歌山.jp 長崎.jp 長野.jp 新潟.jp 青森.jp 静岡.jp 東京.jp 石川.jp 埼玉.jp 三重.jp 京都.jp 佐賀.jp 大分.jp 大阪.jp 奈良.jp 宮城.jp 宮崎.jp 富山.jp 山口.jp 山形.jp 山梨.jp 岩手.jp 岐阜.jp 岡山.jp 島根.jp 広島.jp 徳島.jp 沖縄.jp 滋賀.jp 神奈川.jp 福井.jp 福岡.jp 福島.jp 秋田.jp 群馬.jp 香川.jp 高知.jp 鳥取.jp 鹿児島.jp // jp geographic type names // http://jprs.jp/doc/rule/saisoku-1.html *.kawasaki.jp *.kitakyushu.jp *.kobe.jp *.nagoya.jp *.sapporo.jp *.sendai.jp *.yokohama.jp !city.kawasaki.jp !city.kitakyushu.jp !city.kobe.jp !city.nagoya.jp !city.sapporo.jp !city.sendai.jp !city.yokohama.jp // 4th level registration aisai.aichi.jp ama.aichi.jp anjo.aichi.jp asuke.aichi.jp chiryu.aichi.jp chita.aichi.jp fuso.aichi.jp gamagori.aichi.jp handa.aichi.jp hazu.aichi.jp hekinan.aichi.jp higashiura.aichi.jp ichinomiya.aichi.jp inazawa.aichi.jp inuyama.aichi.jp isshiki.aichi.jp iwakura.aichi.jp kanie.aichi.jp kariya.aichi.jp kasugai.aichi.jp kira.aichi.jp kiyosu.aichi.jp komaki.aichi.jp konan.aichi.jp kota.aichi.jp mihama.aichi.jp miyoshi.aichi.jp nishio.aichi.jp nisshin.aichi.jp obu.aichi.jp oguchi.aichi.jp oharu.aichi.jp okazaki.aichi.jp owariasahi.aichi.jp seto.aichi.jp shikatsu.aichi.jp shinshiro.aichi.jp shitara.aichi.jp tahara.aichi.jp takahama.aichi.jp tobishima.aichi.jp toei.aichi.jp togo.aichi.jp tokai.aichi.jp tokoname.aichi.jp toyoake.aichi.jp toyohashi.aichi.jp toyokawa.aichi.jp toyone.aichi.jp toyota.aichi.jp tsushima.aichi.jp yatomi.aichi.jp akita.akita.jp daisen.akita.jp fujisato.akita.jp gojome.akita.jp hachirogata.akita.jp happou.akita.jp higashinaruse.akita.jp honjo.akita.jp honjyo.akita.jp ikawa.akita.jp kamikoani.akita.jp kamioka.akita.jp katagami.akita.jp kazuno.akita.jp kitaakita.akita.jp kosaka.akita.jp kyowa.akita.jp misato.akita.jp mitane.akita.jp moriyoshi.akita.jp nikaho.akita.jp noshiro.akita.jp odate.akita.jp oga.akita.jp ogata.akita.jp semboku.akita.jp yokote.akita.jp yurihonjo.akita.jp aomori.aomori.jp gonohe.aomori.jp hachinohe.aomori.jp hashikami.aomori.jp hiranai.aomori.jp hirosaki.aomori.jp itayanagi.aomori.jp kuroishi.aomori.jp misawa.aomori.jp mutsu.aomori.jp nakadomari.aomori.jp noheji.aomori.jp oirase.aomori.jp owani.aomori.jp rokunohe.aomori.jp sannohe.aomori.jp shichinohe.aomori.jp shingo.aomori.jp takko.aomori.jp towada.aomori.jp tsugaru.aomori.jp tsuruta.aomori.jp abiko.chiba.jp asahi.chiba.jp chonan.chiba.jp chosei.chiba.jp choshi.chiba.jp chuo.chiba.jp funabashi.chiba.jp futtsu.chiba.jp hanamigawa.chiba.jp ichihara.chiba.jp ichikawa.chiba.jp ichinomiya.chiba.jp inzai.chiba.jp isumi.chiba.jp kamagaya.chiba.jp kamogawa.chiba.jp kashiwa.chiba.jp katori.chiba.jp katsuura.chiba.jp kimitsu.chiba.jp kisarazu.chiba.jp kozaki.chiba.jp kujukuri.chiba.jp kyonan.chiba.jp matsudo.chiba.jp midori.chiba.jp mihama.chiba.jp minamiboso.chiba.jp mobara.chiba.jp mutsuzawa.chiba.jp nagara.chiba.jp nagareyama.chiba.jp narashino.chiba.jp narita.chiba.jp noda.chiba.jp oamishirasato.chiba.jp omigawa.chiba.jp onjuku.chiba.jp otaki.chiba.jp sakae.chiba.jp sakura.chiba.jp shimofusa.chiba.jp shirako.chiba.jp shiroi.chiba.jp shisui.chiba.jp sodegaura.chiba.jp sosa.chiba.jp tako.chiba.jp tateyama.chiba.jp togane.chiba.jp tohnosho.chiba.jp tomisato.chiba.jp urayasu.chiba.jp yachimata.chiba.jp yachiyo.chiba.jp yokaichiba.chiba.jp yokoshibahikari.chiba.jp yotsukaido.chiba.jp ainan.ehime.jp honai.ehime.jp ikata.ehime.jp imabari.ehime.jp iyo.ehime.jp kamijima.ehime.jp kihoku.ehime.jp kumakogen.ehime.jp masaki.ehime.jp matsuno.ehime.jp matsuyama.ehime.jp namikata.ehime.jp niihama.ehime.jp ozu.ehime.jp saijo.ehime.jp seiyo.ehime.jp shikokuchuo.ehime.jp tobe.ehime.jp toon.ehime.jp uchiko.ehime.jp uwajima.ehime.jp yawatahama.ehime.jp echizen.fukui.jp eiheiji.fukui.jp fukui.fukui.jp ikeda.fukui.jp katsuyama.fukui.jp mihama.fukui.jp minamiechizen.fukui.jp obama.fukui.jp ohi.fukui.jp ono.fukui.jp sabae.fukui.jp sakai.fukui.jp takahama.fukui.jp tsuruga.fukui.jp wakasa.fukui.jp ashiya.fukuoka.jp buzen.fukuoka.jp chikugo.fukuoka.jp chikuho.fukuoka.jp chikujo.fukuoka.jp chikushino.fukuoka.jp chikuzen.fukuoka.jp chuo.fukuoka.jp dazaifu.fukuoka.jp fukuchi.fukuoka.jp hakata.fukuoka.jp higashi.fukuoka.jp hirokawa.fukuoka.jp hisayama.fukuoka.jp iizuka.fukuoka.jp inatsuki.fukuoka.jp kaho.fukuoka.jp kasuga.fukuoka.jp kasuya.fukuoka.jp kawara.fukuoka.jp keisen.fukuoka.jp koga.fukuoka.jp kurate.fukuoka.jp kurogi.fukuoka.jp kurume.fukuoka.jp minami.fukuoka.jp miyako.fukuoka.jp miyama.fukuoka.jp miyawaka.fukuoka.jp mizumaki.fukuoka.jp munakata.fukuoka.jp nakagawa.fukuoka.jp nakama.fukuoka.jp nishi.fukuoka.jp nogata.fukuoka.jp ogori.fukuoka.jp okagaki.fukuoka.jp okawa.fukuoka.jp oki.fukuoka.jp omuta.fukuoka.jp onga.fukuoka.jp onojo.fukuoka.jp oto.fukuoka.jp saigawa.fukuoka.jp sasaguri.fukuoka.jp shingu.fukuoka.jp shinyoshitomi.fukuoka.jp shonai.fukuoka.jp soeda.fukuoka.jp sue.fukuoka.jp tachiarai.fukuoka.jp tagawa.fukuoka.jp takata.fukuoka.jp toho.fukuoka.jp toyotsu.fukuoka.jp tsuiki.fukuoka.jp ukiha.fukuoka.jp umi.fukuoka.jp usui.fukuoka.jp yamada.fukuoka.jp yame.fukuoka.jp yanagawa.fukuoka.jp yukuhashi.fukuoka.jp aizubange.fukushima.jp aizumisato.fukushima.jp aizuwakamatsu.fukushima.jp asakawa.fukushima.jp bandai.fukushima.jp date.fukushima.jp fukushima.fukushima.jp furudono.fukushima.jp futaba.fukushima.jp hanawa.fukushima.jp higashi.fukushima.jp hirata.fukushima.jp hirono.fukushima.jp iitate.fukushima.jp inawashiro.fukushima.jp ishikawa.fukushima.jp iwaki.fukushima.jp izumizaki.fukushima.jp kagamiishi.fukushima.jp kaneyama.fukushima.jp kawamata.fukushima.jp kitakata.fukushima.jp kitashiobara.fukushima.jp koori.fukushima.jp koriyama.fukushima.jp kunimi.fukushima.jp miharu.fukushima.jp mishima.fukushima.jp namie.fukushima.jp nango.fukushima.jp nishiaizu.fukushima.jp nishigo.fukushima.jp okuma.fukushima.jp omotego.fukushima.jp ono.fukushima.jp otama.fukushima.jp samegawa.fukushima.jp shimogo.fukushima.jp shirakawa.fukushima.jp showa.fukushima.jp soma.fukushima.jp sukagawa.fukushima.jp taishin.fukushima.jp tamakawa.fukushima.jp tanagura.fukushima.jp tenei.fukushima.jp yabuki.fukushima.jp yamato.fukushima.jp yamatsuri.fukushima.jp yanaizu.fukushima.jp yugawa.fukushima.jp anpachi.gifu.jp ena.gifu.jp gifu.gifu.jp ginan.gifu.jp godo.gifu.jp gujo.gifu.jp hashima.gifu.jp hichiso.gifu.jp hida.gifu.jp higashishirakawa.gifu.jp ibigawa.gifu.jp ikeda.gifu.jp kakamigahara.gifu.jp kani.gifu.jp kasahara.gifu.jp kasamatsu.gifu.jp kawaue.gifu.jp kitagata.gifu.jp mino.gifu.jp minokamo.gifu.jp mitake.gifu.jp mizunami.gifu.jp motosu.gifu.jp nakatsugawa.gifu.jp ogaki.gifu.jp sakahogi.gifu.jp seki.gifu.jp sekigahara.gifu.jp shirakawa.gifu.jp tajimi.gifu.jp takayama.gifu.jp tarui.gifu.jp toki.gifu.jp tomika.gifu.jp wanouchi.gifu.jp yamagata.gifu.jp yaotsu.gifu.jp yoro.gifu.jp annaka.gunma.jp chiyoda.gunma.jp fujioka.gunma.jp higashiagatsuma.gunma.jp isesaki.gunma.jp itakura.gunma.jp kanna.gunma.jp kanra.gunma.jp katashina.gunma.jp kawaba.gunma.jp kiryu.gunma.jp kusatsu.gunma.jp maebashi.gunma.jp meiwa.gunma.jp midori.gunma.jp minakami.gunma.jp naganohara.gunma.jp nakanojo.gunma.jp nanmoku.gunma.jp numata.gunma.jp oizumi.gunma.jp ora.gunma.jp ota.gunma.jp shibukawa.gunma.jp shimonita.gunma.jp shinto.gunma.jp showa.gunma.jp takasaki.gunma.jp takayama.gunma.jp tamamura.gunma.jp tatebayashi.gunma.jp tomioka.gunma.jp tsukiyono.gunma.jp tsumagoi.gunma.jp ueno.gunma.jp yoshioka.gunma.jp asaminami.hiroshima.jp daiwa.hiroshima.jp etajima.hiroshima.jp fuchu.hiroshima.jp fukuyama.hiroshima.jp hatsukaichi.hiroshima.jp higashihiroshima.hiroshima.jp hongo.hiroshima.jp jinsekikogen.hiroshima.jp kaita.hiroshima.jp kui.hiroshima.jp kumano.hiroshima.jp kure.hiroshima.jp mihara.hiroshima.jp miyoshi.hiroshima.jp naka.hiroshima.jp onomichi.hiroshima.jp osakikamijima.hiroshima.jp otake.hiroshima.jp saka.hiroshima.jp sera.hiroshima.jp seranishi.hiroshima.jp shinichi.hiroshima.jp shobara.hiroshima.jp takehara.hiroshima.jp abashiri.hokkaido.jp abira.hokkaido.jp aibetsu.hokkaido.jp akabira.hokkaido.jp akkeshi.hokkaido.jp asahikawa.hokkaido.jp ashibetsu.hokkaido.jp ashoro.hokkaido.jp assabu.hokkaido.jp atsuma.hokkaido.jp bibai.hokkaido.jp biei.hokkaido.jp bifuka.hokkaido.jp bihoro.hokkaido.jp biratori.hokkaido.jp chippubetsu.hokkaido.jp chitose.hokkaido.jp date.hokkaido.jp ebetsu.hokkaido.jp embetsu.hokkaido.jp eniwa.hokkaido.jp erimo.hokkaido.jp esan.hokkaido.jp esashi.hokkaido.jp fukagawa.hokkaido.jp fukushima.hokkaido.jp furano.hokkaido.jp furubira.hokkaido.jp haboro.hokkaido.jp hakodate.hokkaido.jp hamatonbetsu.hokkaido.jp hidaka.hokkaido.jp higashikagura.hokkaido.jp higashikawa.hokkaido.jp hiroo.hokkaido.jp hokuryu.hokkaido.jp hokuto.hokkaido.jp honbetsu.hokkaido.jp horokanai.hokkaido.jp horonobe.hokkaido.jp ikeda.hokkaido.jp imakane.hokkaido.jp ishikari.hokkaido.jp iwamizawa.hokkaido.jp iwanai.hokkaido.jp kamifurano.hokkaido.jp kamikawa.hokkaido.jp kamishihoro.hokkaido.jp kamisunagawa.hokkaido.jp kamoenai.hokkaido.jp kayabe.hokkaido.jp kembuchi.hokkaido.jp kikonai.hokkaido.jp kimobetsu.hokkaido.jp kitahiroshima.hokkaido.jp kitami.hokkaido.jp kiyosato.hokkaido.jp koshimizu.hokkaido.jp kunneppu.hokkaido.jp kuriyama.hokkaido.jp kuromatsunai.hokkaido.jp kushiro.hokkaido.jp kutchan.hokkaido.jp kyowa.hokkaido.jp mashike.hokkaido.jp matsumae.hokkaido.jp mikasa.hokkaido.jp minamifurano.hokkaido.jp mombetsu.hokkaido.jp moseushi.hokkaido.jp mukawa.hokkaido.jp muroran.hokkaido.jp naie.hokkaido.jp nakagawa.hokkaido.jp nakasatsunai.hokkaido.jp nakatombetsu.hokkaido.jp nanae.hokkaido.jp nanporo.hokkaido.jp nayoro.hokkaido.jp nemuro.hokkaido.jp niikappu.hokkaido.jp niki.hokkaido.jp nishiokoppe.hokkaido.jp noboribetsu.hokkaido.jp numata.hokkaido.jp obihiro.hokkaido.jp obira.hokkaido.jp oketo.hokkaido.jp okoppe.hokkaido.jp otaru.hokkaido.jp otobe.hokkaido.jp otofuke.hokkaido.jp otoineppu.hokkaido.jp oumu.hokkaido.jp ozora.hokkaido.jp pippu.hokkaido.jp rankoshi.hokkaido.jp rebun.hokkaido.jp rikubetsu.hokkaido.jp rishiri.hokkaido.jp rishirifuji.hokkaido.jp saroma.hokkaido.jp sarufutsu.hokkaido.jp shakotan.hokkaido.jp shari.hokkaido.jp shibecha.hokkaido.jp shibetsu.hokkaido.jp shikabe.hokkaido.jp shikaoi.hokkaido.jp shimamaki.hokkaido.jp shimizu.hokkaido.jp shimokawa.hokkaido.jp shinshinotsu.hokkaido.jp shintoku.hokkaido.jp shiranuka.hokkaido.jp shiraoi.hokkaido.jp shiriuchi.hokkaido.jp sobetsu.hokkaido.jp sunagawa.hokkaido.jp taiki.hokkaido.jp takasu.hokkaido.jp takikawa.hokkaido.jp takinoue.hokkaido.jp teshikaga.hokkaido.jp tobetsu.hokkaido.jp tohma.hokkaido.jp tomakomai.hokkaido.jp tomari.hokkaido.jp toya.hokkaido.jp toyako.hokkaido.jp toyotomi.hokkaido.jp toyoura.hokkaido.jp tsubetsu.hokkaido.jp tsukigata.hokkaido.jp urakawa.hokkaido.jp urausu.hokkaido.jp uryu.hokkaido.jp utashinai.hokkaido.jp wakkanai.hokkaido.jp wassamu.hokkaido.jp yakumo.hokkaido.jp yoichi.hokkaido.jp aioi.hyogo.jp akashi.hyogo.jp ako.hyogo.jp amagasaki.hyogo.jp aogaki.hyogo.jp asago.hyogo.jp ashiya.hyogo.jp awaji.hyogo.jp fukusaki.hyogo.jp goshiki.hyogo.jp harima.hyogo.jp himeji.hyogo.jp ichikawa.hyogo.jp inagawa.hyogo.jp itami.hyogo.jp kakogawa.hyogo.jp kamigori.hyogo.jp kamikawa.hyogo.jp kasai.hyogo.jp kasuga.hyogo.jp kawanishi.hyogo.jp miki.hyogo.jp minamiawaji.hyogo.jp nishinomiya.hyogo.jp nishiwaki.hyogo.jp ono.hyogo.jp sanda.hyogo.jp sannan.hyogo.jp sasayama.hyogo.jp sayo.hyogo.jp shingu.hyogo.jp shinonsen.hyogo.jp shiso.hyogo.jp sumoto.hyogo.jp taishi.hyogo.jp taka.hyogo.jp takarazuka.hyogo.jp takasago.hyogo.jp takino.hyogo.jp tamba.hyogo.jp tatsuno.hyogo.jp toyooka.hyogo.jp yabu.hyogo.jp yashiro.hyogo.jp yoka.hyogo.jp yokawa.hyogo.jp ami.ibaraki.jp asahi.ibaraki.jp bando.ibaraki.jp chikusei.ibaraki.jp daigo.ibaraki.jp fujishiro.ibaraki.jp hitachi.ibaraki.jp hitachinaka.ibaraki.jp hitachiomiya.ibaraki.jp hitachiota.ibaraki.jp ibaraki.ibaraki.jp ina.ibaraki.jp inashiki.ibaraki.jp itako.ibaraki.jp iwama.ibaraki.jp joso.ibaraki.jp kamisu.ibaraki.jp kasama.ibaraki.jp kashima.ibaraki.jp kasumigaura.ibaraki.jp koga.ibaraki.jp miho.ibaraki.jp mito.ibaraki.jp moriya.ibaraki.jp naka.ibaraki.jp namegata.ibaraki.jp oarai.ibaraki.jp ogawa.ibaraki.jp omitama.ibaraki.jp ryugasaki.ibaraki.jp sakai.ibaraki.jp sakuragawa.ibaraki.jp shimodate.ibaraki.jp shimotsuma.ibaraki.jp shirosato.ibaraki.jp sowa.ibaraki.jp suifu.ibaraki.jp takahagi.ibaraki.jp tamatsukuri.ibaraki.jp tokai.ibaraki.jp tomobe.ibaraki.jp tone.ibaraki.jp toride.ibaraki.jp tsuchiura.ibaraki.jp tsukuba.ibaraki.jp uchihara.ibaraki.jp ushiku.ibaraki.jp yachiyo.ibaraki.jp yamagata.ibaraki.jp yawara.ibaraki.jp yuki.ibaraki.jp anamizu.ishikawa.jp hakui.ishikawa.jp hakusan.ishikawa.jp kaga.ishikawa.jp kahoku.ishikawa.jp kanazawa.ishikawa.jp kawakita.ishikawa.jp komatsu.ishikawa.jp nakanoto.ishikawa.jp nanao.ishikawa.jp nomi.ishikawa.jp nonoichi.ishikawa.jp noto.ishikawa.jp shika.ishikawa.jp suzu.ishikawa.jp tsubata.ishikawa.jp tsurugi.ishikawa.jp uchinada.ishikawa.jp wajima.ishikawa.jp fudai.iwate.jp fujisawa.iwate.jp hanamaki.iwate.jp hiraizumi.iwate.jp hirono.iwate.jp ichinohe.iwate.jp ichinoseki.iwate.jp iwaizumi.iwate.jp iwate.iwate.jp joboji.iwate.jp kamaishi.iwate.jp kanegasaki.iwate.jp karumai.iwate.jp kawai.iwate.jp kitakami.iwate.jp kuji.iwate.jp kunohe.iwate.jp kuzumaki.iwate.jp miyako.iwate.jp mizusawa.iwate.jp morioka.iwate.jp ninohe.iwate.jp noda.iwate.jp ofunato.iwate.jp oshu.iwate.jp otsuchi.iwate.jp rikuzentakata.iwate.jp shiwa.iwate.jp shizukuishi.iwate.jp sumita.iwate.jp tanohata.iwate.jp tono.iwate.jp yahaba.iwate.jp yamada.iwate.jp ayagawa.kagawa.jp higashikagawa.kagawa.jp kanonji.kagawa.jp kotohira.kagawa.jp manno.kagawa.jp marugame.kagawa.jp mitoyo.kagawa.jp naoshima.kagawa.jp sanuki.kagawa.jp tadotsu.kagawa.jp takamatsu.kagawa.jp tonosho.kagawa.jp uchinomi.kagawa.jp utazu.kagawa.jp zentsuji.kagawa.jp akune.kagoshima.jp amami.kagoshima.jp hioki.kagoshima.jp isa.kagoshima.jp isen.kagoshima.jp izumi.kagoshima.jp kagoshima.kagoshima.jp kanoya.kagoshima.jp kawanabe.kagoshima.jp kinko.kagoshima.jp kouyama.kagoshima.jp makurazaki.kagoshima.jp matsumoto.kagoshima.jp minamitane.kagoshima.jp nakatane.kagoshima.jp nishinoomote.kagoshima.jp satsumasendai.kagoshima.jp soo.kagoshima.jp tarumizu.kagoshima.jp yusui.kagoshima.jp aikawa.kanagawa.jp atsugi.kanagawa.jp ayase.kanagawa.jp chigasaki.kanagawa.jp ebina.kanagawa.jp fujisawa.kanagawa.jp hadano.kanagawa.jp hakone.kanagawa.jp hiratsuka.kanagawa.jp isehara.kanagawa.jp kaisei.kanagawa.jp kamakura.kanagawa.jp kiyokawa.kanagawa.jp matsuda.kanagawa.jp minamiashigara.kanagawa.jp miura.kanagawa.jp nakai.kanagawa.jp ninomiya.kanagawa.jp odawara.kanagawa.jp oi.kanagawa.jp oiso.kanagawa.jp sagamihara.kanagawa.jp samukawa.kanagawa.jp tsukui.kanagawa.jp yamakita.kanagawa.jp yamato.kanagawa.jp yokosuka.kanagawa.jp yugawara.kanagawa.jp zama.kanagawa.jp zushi.kanagawa.jp aki.kochi.jp geisei.kochi.jp hidaka.kochi.jp higashitsuno.kochi.jp ino.kochi.jp kagami.kochi.jp kami.kochi.jp kitagawa.kochi.jp kochi.kochi.jp mihara.kochi.jp motoyama.kochi.jp muroto.kochi.jp nahari.kochi.jp nakamura.kochi.jp nankoku.kochi.jp nishitosa.kochi.jp niyodogawa.kochi.jp ochi.kochi.jp okawa.kochi.jp otoyo.kochi.jp otsuki.kochi.jp sakawa.kochi.jp sukumo.kochi.jp susaki.kochi.jp tosa.kochi.jp tosashimizu.kochi.jp toyo.kochi.jp tsuno.kochi.jp umaji.kochi.jp yasuda.kochi.jp yusuhara.kochi.jp amakusa.kumamoto.jp arao.kumamoto.jp aso.kumamoto.jp choyo.kumamoto.jp gyokuto.kumamoto.jp kamiamakusa.kumamoto.jp kikuchi.kumamoto.jp kumamoto.kumamoto.jp mashiki.kumamoto.jp mifune.kumamoto.jp minamata.kumamoto.jp minamioguni.kumamoto.jp nagasu.kumamoto.jp nishihara.kumamoto.jp oguni.kumamoto.jp ozu.kumamoto.jp sumoto.kumamoto.jp takamori.kumamoto.jp uki.kumamoto.jp uto.kumamoto.jp yamaga.kumamoto.jp yamato.kumamoto.jp yatsushiro.kumamoto.jp ayabe.kyoto.jp fukuchiyama.kyoto.jp higashiyama.kyoto.jp ide.kyoto.jp ine.kyoto.jp joyo.kyoto.jp kameoka.kyoto.jp kamo.kyoto.jp kita.kyoto.jp kizu.kyoto.jp kumiyama.kyoto.jp kyotamba.kyoto.jp kyotanabe.kyoto.jp kyotango.kyoto.jp maizuru.kyoto.jp minami.kyoto.jp minamiyamashiro.kyoto.jp miyazu.kyoto.jp muko.kyoto.jp nagaokakyo.kyoto.jp nakagyo.kyoto.jp nantan.kyoto.jp oyamazaki.kyoto.jp sakyo.kyoto.jp seika.kyoto.jp tanabe.kyoto.jp uji.kyoto.jp ujitawara.kyoto.jp wazuka.kyoto.jp yamashina.kyoto.jp yawata.kyoto.jp asahi.mie.jp inabe.mie.jp ise.mie.jp kameyama.mie.jp kawagoe.mie.jp kiho.mie.jp kisosaki.mie.jp kiwa.mie.jp komono.mie.jp kumano.mie.jp kuwana.mie.jp matsusaka.mie.jp meiwa.mie.jp mihama.mie.jp minamiise.mie.jp misugi.mie.jp miyama.mie.jp nabari.mie.jp shima.mie.jp suzuka.mie.jp tado.mie.jp taiki.mie.jp taki.mie.jp tamaki.mie.jp toba.mie.jp tsu.mie.jp udono.mie.jp ureshino.mie.jp watarai.mie.jp yokkaichi.mie.jp furukawa.miyagi.jp higashimatsushima.miyagi.jp ishinomaki.miyagi.jp iwanuma.miyagi.jp kakuda.miyagi.jp kami.miyagi.jp kawasaki.miyagi.jp marumori.miyagi.jp matsushima.miyagi.jp minamisanriku.miyagi.jp misato.miyagi.jp murata.miyagi.jp natori.miyagi.jp ogawara.miyagi.jp ohira.miyagi.jp onagawa.miyagi.jp osaki.miyagi.jp rifu.miyagi.jp semine.miyagi.jp shibata.miyagi.jp shichikashuku.miyagi.jp shikama.miyagi.jp shiogama.miyagi.jp shiroishi.miyagi.jp tagajo.miyagi.jp taiwa.miyagi.jp tome.miyagi.jp tomiya.miyagi.jp wakuya.miyagi.jp watari.miyagi.jp yamamoto.miyagi.jp zao.miyagi.jp aya.miyazaki.jp ebino.miyazaki.jp gokase.miyazaki.jp hyuga.miyazaki.jp kadogawa.miyazaki.jp kawaminami.miyazaki.jp kijo.miyazaki.jp kitagawa.miyazaki.jp kitakata.miyazaki.jp kitaura.miyazaki.jp kobayashi.miyazaki.jp kunitomi.miyazaki.jp kushima.miyazaki.jp mimata.miyazaki.jp miyakonojo.miyazaki.jp miyazaki.miyazaki.jp morotsuka.miyazaki.jp nichinan.miyazaki.jp nishimera.miyazaki.jp nobeoka.miyazaki.jp saito.miyazaki.jp shiiba.miyazaki.jp shintomi.miyazaki.jp takaharu.miyazaki.jp takanabe.miyazaki.jp takazaki.miyazaki.jp tsuno.miyazaki.jp achi.nagano.jp agematsu.nagano.jp anan.nagano.jp aoki.nagano.jp asahi.nagano.jp azumino.nagano.jp chikuhoku.nagano.jp chikuma.nagano.jp chino.nagano.jp fujimi.nagano.jp hakuba.nagano.jp hara.nagano.jp hiraya.nagano.jp iida.nagano.jp iijima.nagano.jp iiyama.nagano.jp iizuna.nagano.jp ikeda.nagano.jp ikusaka.nagano.jp ina.nagano.jp karuizawa.nagano.jp kawakami.nagano.jp kiso.nagano.jp kisofukushima.nagano.jp kitaaiki.nagano.jp komagane.nagano.jp komoro.nagano.jp matsukawa.nagano.jp matsumoto.nagano.jp miasa.nagano.jp minamiaiki.nagano.jp minamimaki.nagano.jp minamiminowa.nagano.jp minowa.nagano.jp miyada.nagano.jp miyota.nagano.jp mochizuki.nagano.jp nagano.nagano.jp nagawa.nagano.jp nagiso.nagano.jp nakagawa.nagano.jp nakano.nagano.jp nozawaonsen.nagano.jp obuse.nagano.jp ogawa.nagano.jp okaya.nagano.jp omachi.nagano.jp omi.nagano.jp ookuwa.nagano.jp ooshika.nagano.jp otaki.nagano.jp otari.nagano.jp sakae.nagano.jp sakaki.nagano.jp saku.nagano.jp sakuho.nagano.jp shimosuwa.nagano.jp shinanomachi.nagano.jp shiojiri.nagano.jp suwa.nagano.jp suzaka.nagano.jp takagi.nagano.jp takamori.nagano.jp takayama.nagano.jp tateshina.nagano.jp tatsuno.nagano.jp togakushi.nagano.jp togura.nagano.jp tomi.nagano.jp ueda.nagano.jp wada.nagano.jp yamagata.nagano.jp yamanouchi.nagano.jp yasaka.nagano.jp yasuoka.nagano.jp chijiwa.nagasaki.jp futsu.nagasaki.jp goto.nagasaki.jp hasami.nagasaki.jp hirado.nagasaki.jp iki.nagasaki.jp isahaya.nagasaki.jp kawatana.nagasaki.jp kuchinotsu.nagasaki.jp matsuura.nagasaki.jp nagasaki.nagasaki.jp obama.nagasaki.jp omura.nagasaki.jp oseto.nagasaki.jp saikai.nagasaki.jp sasebo.nagasaki.jp seihi.nagasaki.jp shimabara.nagasaki.jp shinkamigoto.nagasaki.jp togitsu.nagasaki.jp tsushima.nagasaki.jp unzen.nagasaki.jp ando.nara.jp gose.nara.jp heguri.nara.jp higashiyoshino.nara.jp ikaruga.nara.jp ikoma.nara.jp kamikitayama.nara.jp kanmaki.nara.jp kashiba.nara.jp kashihara.nara.jp katsuragi.nara.jp kawai.nara.jp kawakami.nara.jp kawanishi.nara.jp koryo.nara.jp kurotaki.nara.jp mitsue.nara.jp miyake.nara.jp nara.nara.jp nosegawa.nara.jp oji.nara.jp ouda.nara.jp oyodo.nara.jp sakurai.nara.jp sango.nara.jp shimoichi.nara.jp shimokitayama.nara.jp shinjo.nara.jp soni.nara.jp takatori.nara.jp tawaramoto.nara.jp tenkawa.nara.jp tenri.nara.jp uda.nara.jp yamatokoriyama.nara.jp yamatotakada.nara.jp yamazoe.nara.jp yoshino.nara.jp aga.niigata.jp agano.niigata.jp gosen.niigata.jp itoigawa.niigata.jp izumozaki.niigata.jp joetsu.niigata.jp kamo.niigata.jp kariwa.niigata.jp kashiwazaki.niigata.jp minamiuonuma.niigata.jp mitsuke.niigata.jp muika.niigata.jp murakami.niigata.jp myoko.niigata.jp nagaoka.niigata.jp niigata.niigata.jp ojiya.niigata.jp omi.niigata.jp sado.niigata.jp sanjo.niigata.jp seiro.niigata.jp seirou.niigata.jp sekikawa.niigata.jp shibata.niigata.jp tagami.niigata.jp tainai.niigata.jp tochio.niigata.jp tokamachi.niigata.jp tsubame.niigata.jp tsunan.niigata.jp uonuma.niigata.jp yahiko.niigata.jp yoita.niigata.jp yuzawa.niigata.jp beppu.oita.jp bungoono.oita.jp bungotakada.oita.jp hasama.oita.jp hiji.oita.jp himeshima.oita.jp hita.oita.jp kamitsue.oita.jp kokonoe.oita.jp kuju.oita.jp kunisaki.oita.jp kusu.oita.jp oita.oita.jp saiki.oita.jp taketa.oita.jp tsukumi.oita.jp usa.oita.jp usuki.oita.jp yufu.oita.jp akaiwa.okayama.jp asakuchi.okayama.jp bizen.okayama.jp hayashima.okayama.jp ibara.okayama.jp kagamino.okayama.jp kasaoka.okayama.jp kibichuo.okayama.jp kumenan.okayama.jp kurashiki.okayama.jp maniwa.okayama.jp misaki.okayama.jp nagi.okayama.jp niimi.okayama.jp nishiawakura.okayama.jp okayama.okayama.jp satosho.okayama.jp setouchi.okayama.jp shinjo.okayama.jp shoo.okayama.jp soja.okayama.jp takahashi.okayama.jp tamano.okayama.jp tsuyama.okayama.jp wake.okayama.jp yakage.okayama.jp aguni.okinawa.jp ginowan.okinawa.jp ginoza.okinawa.jp gushikami.okinawa.jp haebaru.okinawa.jp higashi.okinawa.jp hirara.okinawa.jp iheya.okinawa.jp ishigaki.okinawa.jp ishikawa.okinawa.jp itoman.okinawa.jp izena.okinawa.jp kadena.okinawa.jp kin.okinawa.jp kitadaito.okinawa.jp kitanakagusuku.okinawa.jp kumejima.okinawa.jp kunigami.okinawa.jp minamidaito.okinawa.jp motobu.okinawa.jp nago.okinawa.jp naha.okinawa.jp nakagusuku.okinawa.jp nakijin.okinawa.jp nanjo.okinawa.jp nishihara.okinawa.jp ogimi.okinawa.jp okinawa.okinawa.jp onna.okinawa.jp shimoji.okinawa.jp taketomi.okinawa.jp tarama.okinawa.jp tokashiki.okinawa.jp tomigusuku.okinawa.jp tonaki.okinawa.jp urasoe.okinawa.jp uruma.okinawa.jp yaese.okinawa.jp yomitan.okinawa.jp yonabaru.okinawa.jp yonaguni.okinawa.jp zamami.okinawa.jp abeno.osaka.jp chihayaakasaka.osaka.jp chuo.osaka.jp daito.osaka.jp fujiidera.osaka.jp habikino.osaka.jp hannan.osaka.jp higashiosaka.osaka.jp higashisumiyoshi.osaka.jp higashiyodogawa.osaka.jp hirakata.osaka.jp ibaraki.osaka.jp ikeda.osaka.jp izumi.osaka.jp izumiotsu.osaka.jp izumisano.osaka.jp kadoma.osaka.jp kaizuka.osaka.jp kanan.osaka.jp kashiwara.osaka.jp katano.osaka.jp kawachinagano.osaka.jp kishiwada.osaka.jp kita.osaka.jp kumatori.osaka.jp matsubara.osaka.jp minato.osaka.jp minoh.osaka.jp misaki.osaka.jp moriguchi.osaka.jp neyagawa.osaka.jp nishi.osaka.jp nose.osaka.jp osakasayama.osaka.jp sakai.osaka.jp sayama.osaka.jp sennan.osaka.jp settsu.osaka.jp shijonawate.osaka.jp shimamoto.osaka.jp suita.osaka.jp tadaoka.osaka.jp taishi.osaka.jp tajiri.osaka.jp takaishi.osaka.jp takatsuki.osaka.jp tondabayashi.osaka.jp toyonaka.osaka.jp toyono.osaka.jp yao.osaka.jp ariake.saga.jp arita.saga.jp fukudomi.saga.jp genkai.saga.jp hamatama.saga.jp hizen.saga.jp imari.saga.jp kamimine.saga.jp kanzaki.saga.jp karatsu.saga.jp kashima.saga.jp kitagata.saga.jp kitahata.saga.jp kiyama.saga.jp kouhoku.saga.jp kyuragi.saga.jp nishiarita.saga.jp ogi.saga.jp omachi.saga.jp ouchi.saga.jp saga.saga.jp shiroishi.saga.jp taku.saga.jp tara.saga.jp tosu.saga.jp yoshinogari.saga.jp arakawa.saitama.jp asaka.saitama.jp chichibu.saitama.jp fujimi.saitama.jp fujimino.saitama.jp fukaya.saitama.jp hanno.saitama.jp hanyu.saitama.jp hasuda.saitama.jp hatogaya.saitama.jp hatoyama.saitama.jp hidaka.saitama.jp higashichichibu.saitama.jp higashimatsuyama.saitama.jp honjo.saitama.jp ina.saitama.jp iruma.saitama.jp iwatsuki.saitama.jp kamiizumi.saitama.jp kamikawa.saitama.jp kamisato.saitama.jp kasukabe.saitama.jp kawagoe.saitama.jp kawaguchi.saitama.jp kawajima.saitama.jp kazo.saitama.jp kitamoto.saitama.jp koshigaya.saitama.jp kounosu.saitama.jp kuki.saitama.jp kumagaya.saitama.jp matsubushi.saitama.jp minano.saitama.jp misato.saitama.jp miyashiro.saitama.jp miyoshi.saitama.jp moroyama.saitama.jp nagatoro.saitama.jp namegawa.saitama.jp niiza.saitama.jp ogano.saitama.jp ogawa.saitama.jp ogose.saitama.jp okegawa.saitama.jp omiya.saitama.jp otaki.saitama.jp ranzan.saitama.jp ryokami.saitama.jp saitama.saitama.jp sakado.saitama.jp satte.saitama.jp sayama.saitama.jp shiki.saitama.jp shiraoka.saitama.jp soka.saitama.jp sugito.saitama.jp toda.saitama.jp tokigawa.saitama.jp tokorozawa.saitama.jp tsurugashima.saitama.jp urawa.saitama.jp warabi.saitama.jp yashio.saitama.jp yokoze.saitama.jp yono.saitama.jp yorii.saitama.jp yoshida.saitama.jp yoshikawa.saitama.jp yoshimi.saitama.jp aisho.shiga.jp gamo.shiga.jp higashiomi.shiga.jp hikone.shiga.jp koka.shiga.jp konan.shiga.jp kosei.shiga.jp koto.shiga.jp kusatsu.shiga.jp maibara.shiga.jp moriyama.shiga.jp nagahama.shiga.jp nishiazai.shiga.jp notogawa.shiga.jp omihachiman.shiga.jp otsu.shiga.jp ritto.shiga.jp ryuoh.shiga.jp takashima.shiga.jp takatsuki.shiga.jp torahime.shiga.jp toyosato.shiga.jp yasu.shiga.jp akagi.shimane.jp ama.shimane.jp gotsu.shimane.jp hamada.shimane.jp higashiizumo.shimane.jp hikawa.shimane.jp hikimi.shimane.jp izumo.shimane.jp kakinoki.shimane.jp masuda.shimane.jp matsue.shimane.jp misato.shimane.jp nishinoshima.shimane.jp ohda.shimane.jp okinoshima.shimane.jp okuizumo.shimane.jp shimane.shimane.jp tamayu.shimane.jp tsuwano.shimane.jp unnan.shimane.jp yakumo.shimane.jp yasugi.shimane.jp yatsuka.shimane.jp arai.shizuoka.jp atami.shizuoka.jp fuji.shizuoka.jp fujieda.shizuoka.jp fujikawa.shizuoka.jp fujinomiya.shizuoka.jp fukuroi.shizuoka.jp gotemba.shizuoka.jp haibara.shizuoka.jp hamamatsu.shizuoka.jp higashiizu.shizuoka.jp ito.shizuoka.jp iwata.shizuoka.jp izu.shizuoka.jp izunokuni.shizuoka.jp kakegawa.shizuoka.jp kannami.shizuoka.jp kawanehon.shizuoka.jp kawazu.shizuoka.jp kikugawa.shizuoka.jp kosai.shizuoka.jp makinohara.shizuoka.jp matsuzaki.shizuoka.jp minamiizu.shizuoka.jp mishima.shizuoka.jp morimachi.shizuoka.jp nishiizu.shizuoka.jp numazu.shizuoka.jp omaezaki.shizuoka.jp shimada.shizuoka.jp shimizu.shizuoka.jp shimoda.shizuoka.jp shizuoka.shizuoka.jp susono.shizuoka.jp yaizu.shizuoka.jp yoshida.shizuoka.jp ashikaga.tochigi.jp bato.tochigi.jp haga.tochigi.jp ichikai.tochigi.jp iwafune.tochigi.jp kaminokawa.tochigi.jp kanuma.tochigi.jp karasuyama.tochigi.jp kuroiso.tochigi.jp mashiko.tochigi.jp mibu.tochigi.jp moka.tochigi.jp motegi.tochigi.jp nasu.tochigi.jp nasushiobara.tochigi.jp nikko.tochigi.jp nishikata.tochigi.jp nogi.tochigi.jp ohira.tochigi.jp ohtawara.tochigi.jp oyama.tochigi.jp sakura.tochigi.jp sano.tochigi.jp shimotsuke.tochigi.jp shioya.tochigi.jp takanezawa.tochigi.jp tochigi.tochigi.jp tsuga.tochigi.jp ujiie.tochigi.jp utsunomiya.tochigi.jp yaita.tochigi.jp aizumi.tokushima.jp anan.tokushima.jp ichiba.tokushima.jp itano.tokushima.jp kainan.tokushima.jp komatsushima.tokushima.jp matsushige.tokushima.jp mima.tokushima.jp minami.tokushima.jp miyoshi.tokushima.jp mugi.tokushima.jp nakagawa.tokushima.jp naruto.tokushima.jp sanagochi.tokushima.jp shishikui.tokushima.jp tokushima.tokushima.jp wajiki.tokushima.jp adachi.tokyo.jp akiruno.tokyo.jp akishima.tokyo.jp aogashima.tokyo.jp arakawa.tokyo.jp bunkyo.tokyo.jp chiyoda.tokyo.jp chofu.tokyo.jp chuo.tokyo.jp edogawa.tokyo.jp fuchu.tokyo.jp fussa.tokyo.jp hachijo.tokyo.jp hachioji.tokyo.jp hamura.tokyo.jp higashikurume.tokyo.jp higashimurayama.tokyo.jp higashiyamato.tokyo.jp hino.tokyo.jp hinode.tokyo.jp hinohara.tokyo.jp inagi.tokyo.jp itabashi.tokyo.jp katsushika.tokyo.jp kita.tokyo.jp kiyose.tokyo.jp kodaira.tokyo.jp koganei.tokyo.jp kokubunji.tokyo.jp komae.tokyo.jp koto.tokyo.jp kouzushima.tokyo.jp kunitachi.tokyo.jp machida.tokyo.jp meguro.tokyo.jp minato.tokyo.jp mitaka.tokyo.jp mizuho.tokyo.jp musashimurayama.tokyo.jp musashino.tokyo.jp nakano.tokyo.jp nerima.tokyo.jp ogasawara.tokyo.jp okutama.tokyo.jp ome.tokyo.jp oshima.tokyo.jp ota.tokyo.jp setagaya.tokyo.jp shibuya.tokyo.jp shinagawa.tokyo.jp shinjuku.tokyo.jp suginami.tokyo.jp sumida.tokyo.jp tachikawa.tokyo.jp taito.tokyo.jp tama.tokyo.jp toshima.tokyo.jp chizu.tottori.jp hino.tottori.jp kawahara.tottori.jp koge.tottori.jp kotoura.tottori.jp misasa.tottori.jp nanbu.tottori.jp nichinan.tottori.jp sakaiminato.tottori.jp tottori.tottori.jp wakasa.tottori.jp yazu.tottori.jp yonago.tottori.jp asahi.toyama.jp fuchu.toyama.jp fukumitsu.toyama.jp funahashi.toyama.jp himi.toyama.jp imizu.toyama.jp inami.toyama.jp johana.toyama.jp kamiichi.toyama.jp kurobe.toyama.jp nakaniikawa.toyama.jp namerikawa.toyama.jp nanto.toyama.jp nyuzen.toyama.jp oyabe.toyama.jp taira.toyama.jp takaoka.toyama.jp tateyama.toyama.jp toga.toyama.jp tonami.toyama.jp toyama.toyama.jp unazuki.toyama.jp uozu.toyama.jp yamada.toyama.jp arida.wakayama.jp aridagawa.wakayama.jp gobo.wakayama.jp hashimoto.wakayama.jp hidaka.wakayama.jp hirogawa.wakayama.jp inami.wakayama.jp iwade.wakayama.jp kainan.wakayama.jp kamitonda.wakayama.jp katsuragi.wakayama.jp kimino.wakayama.jp kinokawa.wakayama.jp kitayama.wakayama.jp koya.wakayama.jp koza.wakayama.jp kozagawa.wakayama.jp kudoyama.wakayama.jp kushimoto.wakayama.jp mihama.wakayama.jp misato.wakayama.jp nachikatsuura.wakayama.jp shingu.wakayama.jp shirahama.wakayama.jp taiji.wakayama.jp tanabe.wakayama.jp wakayama.wakayama.jp yuasa.wakayama.jp yura.wakayama.jp asahi.yamagata.jp funagata.yamagata.jp higashine.yamagata.jp iide.yamagata.jp kahoku.yamagata.jp kaminoyama.yamagata.jp kaneyama.yamagata.jp kawanishi.yamagata.jp mamurogawa.yamagata.jp mikawa.yamagata.jp murayama.yamagata.jp nagai.yamagata.jp nakayama.yamagata.jp nanyo.yamagata.jp nishikawa.yamagata.jp obanazawa.yamagata.jp oe.yamagata.jp oguni.yamagata.jp ohkura.yamagata.jp oishida.yamagata.jp sagae.yamagata.jp sakata.yamagata.jp sakegawa.yamagata.jp shinjo.yamagata.jp shirataka.yamagata.jp shonai.yamagata.jp takahata.yamagata.jp tendo.yamagata.jp tozawa.yamagata.jp tsuruoka.yamagata.jp yamagata.yamagata.jp yamanobe.yamagata.jp yonezawa.yamagata.jp yuza.yamagata.jp abu.yamaguchi.jp hagi.yamaguchi.jp hikari.yamaguchi.jp hofu.yamaguchi.jp iwakuni.yamaguchi.jp kudamatsu.yamaguchi.jp mitou.yamaguchi.jp nagato.yamaguchi.jp oshima.yamaguchi.jp shimonoseki.yamaguchi.jp shunan.yamaguchi.jp tabuse.yamaguchi.jp tokuyama.yamaguchi.jp toyota.yamaguchi.jp ube.yamaguchi.jp yuu.yamaguchi.jp chuo.yamanashi.jp doshi.yamanashi.jp fuefuki.yamanashi.jp fujikawa.yamanashi.jp fujikawaguchiko.yamanashi.jp fujiyoshida.yamanashi.jp hayakawa.yamanashi.jp hokuto.yamanashi.jp ichikawamisato.yamanashi.jp kai.yamanashi.jp kofu.yamanashi.jp koshu.yamanashi.jp kosuge.yamanashi.jp minami-alps.yamanashi.jp minobu.yamanashi.jp nakamichi.yamanashi.jp nanbu.yamanashi.jp narusawa.yamanashi.jp nirasaki.yamanashi.jp nishikatsura.yamanashi.jp oshino.yamanashi.jp otsuki.yamanashi.jp showa.yamanashi.jp tabayama.yamanashi.jp tsuru.yamanashi.jp uenohara.yamanashi.jp yamanakako.yamanashi.jp yamanashi.yamanashi.jp // ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145 *.ke // kg : http://www.domain.kg/dmn_n.html kg org.kg net.kg com.kg edu.kg gov.kg mil.kg // kh : http://www.mptc.gov.kh/dns_registration.htm *.kh // ki : http://www.ki/dns/index.html ki edu.ki biz.ki net.ki org.ki gov.ki info.ki com.ki // km : https://en.wikipedia.org/wiki/.km // http://www.domaine.km/documents/charte.doc km org.km nom.km gov.km prd.km tm.km edu.km mil.km ass.km com.km // These are only mentioned as proposed suggestions at domaine.km, but // https://en.wikipedia.org/wiki/.km says they're available for registration: coop.km asso.km presse.km medecin.km notaires.km pharmaciens.km veterinaire.km gouv.km // kn : https://en.wikipedia.org/wiki/.kn // http://www.dot.kn/domainRules.html kn net.kn org.kn edu.kn gov.kn // kp : http://www.kcce.kp/en_index.php kp com.kp edu.kp gov.kp org.kp rep.kp tra.kp // kr : https://en.wikipedia.org/wiki/.kr // see also: http://domain.nida.or.kr/eng/registration.jsp kr ac.kr co.kr es.kr go.kr hs.kr kg.kr mil.kr ms.kr ne.kr or.kr pe.kr re.kr sc.kr // kr geographical names busan.kr chungbuk.kr chungnam.kr daegu.kr daejeon.kr gangwon.kr gwangju.kr gyeongbuk.kr gyeonggi.kr gyeongnam.kr incheon.kr jeju.kr jeonbuk.kr jeonnam.kr seoul.kr ulsan.kr // kw : https://en.wikipedia.org/wiki/.kw *.kw // ky : http://www.icta.ky/da_ky_reg_dom.php // Confirmed by registry <kysupport@perimeterusa.com> 2008-06-17 ky edu.ky gov.ky com.ky org.ky net.ky // kz : https://en.wikipedia.org/wiki/.kz // see also: http://www.nic.kz/rules/index.jsp kz org.kz edu.kz net.kz gov.kz mil.kz com.kz // la : https://en.wikipedia.org/wiki/.la // Submitted by registry <gavin.brown@nic.la> la int.la net.la info.la edu.la gov.la per.la com.la org.la // lb : https://en.wikipedia.org/wiki/.lb // Submitted by registry <randy@psg.com> lb com.lb edu.lb gov.lb net.lb org.lb // lc : https://en.wikipedia.org/wiki/.lc // see also: http://www.nic.lc/rules.htm lc com.lc net.lc co.lc org.lc edu.lc gov.lc // li : https://en.wikipedia.org/wiki/.li li // lk : http://www.nic.lk/seclevpr.html lk gov.lk sch.lk net.lk int.lk com.lk org.lk edu.lk ngo.lk soc.lk web.lk ltd.lk assn.lk grp.lk hotel.lk ac.lk // lr : http://psg.com/dns/lr/lr.txt // Submitted by registry <randy@psg.com> lr com.lr edu.lr gov.lr org.lr net.lr // ls : https://en.wikipedia.org/wiki/.ls ls co.ls org.ls // lt : https://en.wikipedia.org/wiki/.lt lt // gov.lt : http://www.gov.lt/index_en.php gov.lt // lu : http://www.dns.lu/en/ lu // lv : http://www.nic.lv/DNS/En/generic.php lv com.lv edu.lv gov.lv org.lv mil.lv id.lv net.lv asn.lv conf.lv // ly : http://www.nic.ly/regulations.php ly com.ly net.ly gov.ly plc.ly edu.ly sch.ly med.ly org.ly id.ly // ma : https://en.wikipedia.org/wiki/.ma // http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf ma co.ma net.ma gov.ma org.ma ac.ma press.ma // mc : http://www.nic.mc/ mc tm.mc asso.mc // md : https://en.wikipedia.org/wiki/.md md // me : https://en.wikipedia.org/wiki/.me me co.me net.me org.me edu.me ac.me gov.me its.me priv.me // mg : http://nic.mg/nicmg/?page_id=39 mg org.mg nom.mg gov.mg prd.mg tm.mg edu.mg mil.mg com.mg co.mg // mh : https://en.wikipedia.org/wiki/.mh mh // mil : https://en.wikipedia.org/wiki/.mil mil // mk : https://en.wikipedia.org/wiki/.mk // see also: http://dns.marnet.net.mk/postapka.php mk com.mk org.mk net.mk edu.mk gov.mk inf.mk name.mk // ml : http://www.gobin.info/domainname/ml-template.doc // see also: https://en.wikipedia.org/wiki/.ml ml com.ml edu.ml gouv.ml gov.ml net.ml org.ml presse.ml // mm : https://en.wikipedia.org/wiki/.mm *.mm // mn : https://en.wikipedia.org/wiki/.mn mn gov.mn edu.mn org.mn // mo : http://www.monic.net.mo/ mo com.mo net.mo org.mo edu.mo gov.mo // mobi : https://en.wikipedia.org/wiki/.mobi mobi // mp : http://www.dot.mp/ // Confirmed by registry <dcamacho@saipan.com> 2008-06-17 mp // mq : https://en.wikipedia.org/wiki/.mq mq // mr : https://en.wikipedia.org/wiki/.mr mr gov.mr // ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf ms com.ms edu.ms gov.ms net.ms org.ms // mt : https://www.nic.org.mt/go/policy // Submitted by registry <help@nic.org.mt> mt com.mt edu.mt net.mt org.mt // mu : https://en.wikipedia.org/wiki/.mu mu com.mu net.mu org.mu gov.mu ac.mu co.mu or.mu // museum : http://about.museum/naming/ // http://index.museum/ museum academy.museum agriculture.museum air.museum airguard.museum alabama.museum alaska.museum amber.museum ambulance.museum american.museum americana.museum americanantiques.museum americanart.museum amsterdam.museum and.museum annefrank.museum anthro.museum anthropology.museum antiques.museum aquarium.museum arboretum.museum archaeological.museum archaeology.museum architecture.museum art.museum artanddesign.museum artcenter.museum artdeco.museum arteducation.museum artgallery.museum arts.museum artsandcrafts.museum asmatart.museum assassination.museum assisi.museum association.museum astronomy.museum atlanta.museum austin.museum australia.museum automotive.museum aviation.museum axis.museum badajoz.museum baghdad.museum bahn.museum bale.museum baltimore.museum barcelona.museum baseball.museum basel.museum baths.museum bauern.museum beauxarts.museum beeldengeluid.museum bellevue.museum bergbau.museum berkeley.museum berlin.museum bern.museum bible.museum bilbao.museum bill.museum birdart.museum birthplace.museum bonn.museum boston.museum botanical.museum botanicalgarden.museum botanicgarden.museum botany.museum brandywinevalley.museum brasil.museum bristol.museum british.museum britishcolumbia.museum broadcast.museum brunel.museum brussel.museum brussels.museum bruxelles.museum building.museum burghof.museum bus.museum bushey.museum cadaques.museum california.museum cambridge.museum can.museum canada.museum capebreton.museum carrier.museum cartoonart.museum casadelamoneda.museum castle.museum castres.museum celtic.museum center.museum chattanooga.museum cheltenham.museum chesapeakebay.museum chicago.museum children.museum childrens.museum childrensgarden.museum chiropractic.museum chocolate.museum christiansburg.museum cincinnati.museum cinema.museum circus.museum civilisation.museum civilization.museum civilwar.museum clinton.museum clock.museum coal.museum coastaldefence.museum cody.museum coldwar.museum collection.museum colonialwilliamsburg.museum coloradoplateau.museum columbia.museum columbus.museum communication.museum communications.museum community.museum computer.museum computerhistory.museum comunicações.museum contemporary.museum contemporaryart.museum convent.museum copenhagen.museum corporation.museum correios-e-telecomunicações.museum corvette.museum costume.museum countryestate.museum county.museum crafts.museum cranbrook.museum creation.museum cultural.museum culturalcenter.museum culture.museum cyber.museum cymru.museum dali.museum dallas.museum database.museum ddr.museum decorativearts.museum delaware.museum delmenhorst.museum denmark.museum depot.museum design.museum detroit.museum dinosaur.museum discovery.museum dolls.museum donostia.museum durham.museum eastafrica.museum eastcoast.museum education.museum educational.museum egyptian.museum eisenbahn.museum elburg.museum elvendrell.museum embroidery.museum encyclopedic.museum england.museum entomology.museum environment.museum environmentalconservation.museum epilepsy.museum essex.museum estate.museum ethnology.museum exeter.museum exhibition.museum family.museum farm.museum farmequipment.museum farmers.museum farmstead.museum field.museum figueres.museum filatelia.museum film.museum fineart.museum finearts.museum finland.museum flanders.museum florida.museum force.museum fortmissoula.museum fortworth.museum foundation.museum francaise.museum frankfurt.museum franziskaner.museum freemasonry.museum freiburg.museum fribourg.museum frog.museum fundacio.museum furniture.museum gallery.museum garden.museum gateway.museum geelvinck.museum gemological.museum geology.museum georgia.museum giessen.museum glas.museum glass.museum gorge.museum grandrapids.museum graz.museum guernsey.museum halloffame.museum hamburg.museum handson.museum harvestcelebration.museum hawaii.museum health.museum heimatunduhren.museum hellas.museum helsinki.museum hembygdsforbund.museum heritage.museum histoire.museum historical.museum historicalsociety.museum historichouses.museum historisch.museum historisches.museum history.museum historyofscience.museum horology.museum house.museum humanities.museum illustration.museum imageandsound.museum indian.museum indiana.museum indianapolis.museum indianmarket.museum intelligence.museum interactive.museum iraq.museum iron.museum isleofman.museum jamison.museum jefferson.museum jerusalem.museum jewelry.museum jewish.museum jewishart.museum jfk.museum journalism.museum judaica.museum judygarland.museum juedisches.museum juif.museum karate.museum karikatur.museum kids.museum koebenhavn.museum koeln.museum kunst.museum kunstsammlung.museum kunstunddesign.museum labor.museum labour.museum lajolla.museum lancashire.museum landes.museum lans.museum läns.museum larsson.museum lewismiller.museum lincoln.museum linz.museum living.museum livinghistory.museum localhistory.museum london.museum losangeles.museum louvre.museum loyalist.museum lucerne.museum luxembourg.museum luzern.museum mad.museum madrid.museum mallorca.museum manchester.museum mansion.museum mansions.museum manx.museum marburg.museum maritime.museum maritimo.museum maryland.museum marylhurst.museum media.museum medical.museum medizinhistorisches.museum meeres.museum memorial.museum mesaverde.museum michigan.museum midatlantic.museum military.museum mill.museum miners.museum mining.museum minnesota.museum missile.museum missoula.museum modern.museum moma.museum money.museum monmouth.museum monticello.museum montreal.museum moscow.museum motorcycle.museum muenchen.museum muenster.museum mulhouse.museum muncie.museum museet.museum museumcenter.museum museumvereniging.museum music.museum national.museum nationalfirearms.museum nationalheritage.museum nativeamerican.museum naturalhistory.museum naturalhistorymuseum.museum naturalsciences.museum nature.museum naturhistorisches.museum natuurwetenschappen.museum naumburg.museum naval.museum nebraska.museum neues.museum newhampshire.museum newjersey.museum newmexico.museum newport.museum newspaper.museum newyork.museum niepce.museum norfolk.museum north.museum nrw.museum nuernberg.museum nuremberg.museum nyc.museum nyny.museum oceanographic.museum oceanographique.museum omaha.museum online.museum ontario.museum openair.museum oregon.museum oregontrail.museum otago.museum oxford.museum pacific.museum paderborn.museum palace.museum paleo.museum palmsprings.museum panama.museum paris.museum pasadena.museum pharmacy.museum philadelphia.museum philadelphiaarea.museum philately.museum phoenix.museum photography.museum pilots.museum pittsburgh.museum planetarium.museum plantation.museum plants.museum plaza.museum portal.museum portland.museum portlligat.museum posts-and-telecommunications.museum preservation.museum presidio.museum press.museum project.museum public.museum pubol.museum quebec.museum railroad.museum railway.museum research.museum resistance.museum riodejaneiro.museum rochester.museum rockart.museum roma.museum russia.museum saintlouis.museum salem.museum salvadordali.museum salzburg.museum sandiego.museum sanfrancisco.museum santabarbara.museum santacruz.museum santafe.museum saskatchewan.museum satx.museum savannahga.museum schlesisches.museum schoenbrunn.museum schokoladen.museum school.museum schweiz.museum science.museum scienceandhistory.museum scienceandindustry.museum sciencecenter.museum sciencecenters.museum science-fiction.museum sciencehistory.museum sciences.museum sciencesnaturelles.museum scotland.museum seaport.museum settlement.museum settlers.museum shell.museum sherbrooke.museum sibenik.museum silk.museum ski.museum skole.museum society.museum sologne.museum soundandvision.museum southcarolina.museum southwest.museum space.museum spy.museum square.museum stadt.museum stalbans.museum starnberg.museum state.museum stateofdelaware.museum station.museum steam.museum steiermark.museum stjohn.museum stockholm.museum stpetersburg.museum stuttgart.museum suisse.museum surgeonshall.museum surrey.museum svizzera.museum sweden.museum sydney.museum tank.museum tcm.museum technology.museum telekommunikation.museum television.museum texas.museum textile.museum theater.museum time.museum timekeeping.museum topology.museum torino.museum touch.museum town.museum transport.museum tree.museum trolley.museum trust.museum trustee.museum uhren.museum ulm.museum undersea.museum university.museum usa.museum usantiques.museum usarts.museum uscountryestate.museum usculture.museum usdecorativearts.museum usgarden.museum ushistory.museum ushuaia.museum uslivinghistory.museum utah.museum uvic.museum valley.museum vantaa.museum versailles.museum viking.museum village.museum virginia.museum virtual.museum virtuel.museum vlaanderen.museum volkenkunde.museum wales.museum wallonie.museum war.museum washingtondc.museum watchandclock.museum watch-and-clock.museum western.museum westfalen.museum whaling.museum wildlife.museum williamsburg.museum windmill.museum workshop.museum york.museum yorkshire.museum yosemite.museum youth.museum zoological.museum zoology.museum ירושלים.museum иком.museum // mv : https://en.wikipedia.org/wiki/.mv // "mv" included because, contra Wikipedia, google.mv exists. mv aero.mv biz.mv com.mv coop.mv edu.mv gov.mv info.mv int.mv mil.mv museum.mv name.mv net.mv org.mv pro.mv // mw : http://www.registrar.mw/ mw ac.mw biz.mw co.mw com.mw coop.mw edu.mw gov.mw int.mw museum.mw net.mw org.mw // mx : http://www.nic.mx/ // Submitted by registry <farias@nic.mx> mx com.mx org.mx gob.mx edu.mx net.mx // my : http://www.mynic.net.my/ my com.my net.my org.my gov.my edu.my mil.my name.my // mz : http://www.uem.mz/ // Submitted by registry <antonio@uem.mz> mz ac.mz adv.mz co.mz edu.mz gov.mz mil.mz net.mz org.mz // na : http://www.na-nic.com.na/ // http://www.info.na/domain/ na info.na pro.na name.na school.na or.na dr.na us.na mx.na ca.na in.na cc.na tv.na ws.na mobi.na co.na com.na org.na // name : has 2nd-level tlds, but there's no list of them name // nc : http://www.cctld.nc/ nc asso.nc // ne : https://en.wikipedia.org/wiki/.ne ne // net : https://en.wikipedia.org/wiki/.net net // nf : https://en.wikipedia.org/wiki/.nf nf com.nf net.nf per.nf rec.nf web.nf arts.nf firm.nf info.nf other.nf store.nf // ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds ng com.ng edu.ng gov.ng i.ng mil.ng mobi.ng name.ng net.ng org.ng sch.ng // ni : http://www.nic.ni/ ni ac.ni biz.ni co.ni com.ni edu.ni gob.ni in.ni info.ni int.ni mil.ni net.ni nom.ni org.ni web.ni // nl : https://en.wikipedia.org/wiki/.nl // https://www.sidn.nl/ // ccTLD for the Netherlands nl // BV.nl will be a registry for dutch BV's (besloten vennootschap) bv.nl // no : http://www.norid.no/regelverk/index.en.html // The Norwegian registry has declined to notify us of updates. The web pages // referenced below are the official source of the data. There is also an // announce mailing list: // https://postlister.uninett.no/sympa/info/norid-diskusjon no // Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html fhs.no vgs.no fylkesbibl.no folkebibl.no museum.no idrett.no priv.no // Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html mil.no stat.no dep.no kommune.no herad.no // no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html // counties aa.no ah.no bu.no fm.no hl.no hm.no jan-mayen.no mr.no nl.no nt.no of.no ol.no oslo.no rl.no sf.no st.no svalbard.no tm.no tr.no va.no vf.no // primary and lower secondary schools per county gs.aa.no gs.ah.no gs.bu.no gs.fm.no gs.hl.no gs.hm.no gs.jan-mayen.no gs.mr.no gs.nl.no gs.nt.no gs.of.no gs.ol.no gs.oslo.no gs.rl.no gs.sf.no gs.st.no gs.svalbard.no gs.tm.no gs.tr.no gs.va.no gs.vf.no // cities akrehamn.no åkrehamn.no algard.no ålgård.no arna.no brumunddal.no bryne.no bronnoysund.no brønnøysund.no drobak.no drøbak.no egersund.no fetsund.no floro.no florø.no fredrikstad.no hokksund.no honefoss.no hønefoss.no jessheim.no jorpeland.no jørpeland.no kirkenes.no kopervik.no krokstadelva.no langevag.no langevåg.no leirvik.no mjondalen.no mjøndalen.no mo-i-rana.no mosjoen.no mosjøen.no nesoddtangen.no orkanger.no osoyro.no osøyro.no raholt.no råholt.no sandnessjoen.no sandnessjøen.no skedsmokorset.no slattum.no spjelkavik.no stathelle.no stavern.no stjordalshalsen.no stjørdalshalsen.no tananger.no tranby.no vossevangen.no // communities afjord.no åfjord.no agdenes.no al.no ål.no alesund.no ålesund.no alstahaug.no alta.no áltá.no alaheadju.no álaheadju.no alvdal.no amli.no åmli.no amot.no åmot.no andebu.no andoy.no andøy.no andasuolo.no ardal.no årdal.no aremark.no arendal.no ås.no aseral.no åseral.no asker.no askim.no askvoll.no askoy.no askøy.no asnes.no åsnes.no audnedaln.no aukra.no aure.no aurland.no aurskog-holand.no aurskog-høland.no austevoll.no austrheim.no averoy.no averøy.no balestrand.no ballangen.no balat.no bálát.no balsfjord.no bahccavuotna.no báhccavuotna.no bamble.no bardu.no beardu.no beiarn.no bajddar.no bájddar.no baidar.no báidár.no berg.no bergen.no berlevag.no berlevåg.no bearalvahki.no bearalváhki.no bindal.no birkenes.no bjarkoy.no bjarkøy.no bjerkreim.no bjugn.no bodo.no bodø.no badaddja.no bådåddjå.no budejju.no bokn.no bremanger.no bronnoy.no brønnøy.no bygland.no bykle.no barum.no bærum.no bo.telemark.no bø.telemark.no bo.nordland.no bø.nordland.no bievat.no bievát.no bomlo.no bømlo.no batsfjord.no båtsfjord.no bahcavuotna.no báhcavuotna.no dovre.no drammen.no drangedal.no dyroy.no dyrøy.no donna.no dønna.no eid.no eidfjord.no eidsberg.no eidskog.no eidsvoll.no eigersund.no elverum.no enebakk.no engerdal.no etne.no etnedal.no evenes.no evenassi.no evenášši.no evje-og-hornnes.no farsund.no fauske.no fuossko.no fuoisku.no fedje.no fet.no finnoy.no finnøy.no fitjar.no fjaler.no fjell.no flakstad.no flatanger.no flekkefjord.no flesberg.no flora.no fla.no flå.no folldal.no forsand.no fosnes.no frei.no frogn.no froland.no frosta.no frana.no fræna.no froya.no frøya.no fusa.no fyresdal.no forde.no førde.no gamvik.no gangaviika.no gáŋgaviika.no gaular.no gausdal.no gildeskal.no gildeskål.no giske.no gjemnes.no gjerdrum.no gjerstad.no gjesdal.no gjovik.no gjøvik.no gloppen.no gol.no gran.no grane.no granvin.no gratangen.no grimstad.no grong.no kraanghke.no kråanghke.no grue.no gulen.no hadsel.no halden.no halsa.no hamar.no hamaroy.no habmer.no hábmer.no hapmir.no hápmir.no hammerfest.no hammarfeasta.no hámmárfeasta.no haram.no hareid.no harstad.no hasvik.no aknoluokta.no ákŋoluokta.no hattfjelldal.no aarborte.no haugesund.no hemne.no hemnes.no hemsedal.no heroy.more-og-romsdal.no herøy.møre-og-romsdal.no heroy.nordland.no herøy.nordland.no hitra.no hjartdal.no hjelmeland.no hobol.no hobøl.no hof.no hol.no hole.no holmestrand.no holtalen.no holtålen.no hornindal.no horten.no hurdal.no hurum.no hvaler.no hyllestad.no hagebostad.no hægebostad.no hoyanger.no høyanger.no hoylandet.no høylandet.no ha.no hå.no ibestad.no inderoy.no inderøy.no iveland.no jevnaker.no jondal.no jolster.no jølster.no karasjok.no karasjohka.no kárášjohka.no karlsoy.no galsa.no gálsá.no karmoy.no karmøy.no kautokeino.no guovdageaidnu.no klepp.no klabu.no klæbu.no kongsberg.no kongsvinger.no kragero.no kragerø.no kristiansand.no kristiansund.no krodsherad.no krødsherad.no kvalsund.no rahkkeravju.no ráhkkerávju.no kvam.no kvinesdal.no kvinnherad.no kviteseid.no kvitsoy.no kvitsøy.no kvafjord.no kvæfjord.no giehtavuoatna.no kvanangen.no kvænangen.no navuotna.no návuotna.no kafjord.no kåfjord.no gaivuotna.no gáivuotna.no larvik.no lavangen.no lavagis.no loabat.no loabát.no lebesby.no davvesiida.no leikanger.no leirfjord.no leka.no leksvik.no lenvik.no leangaviika.no leaŋgaviika.no lesja.no levanger.no lier.no lierne.no lillehammer.no lillesand.no lindesnes.no lindas.no lindås.no lom.no loppa.no lahppi.no láhppi.no lund.no lunner.no luroy.no lurøy.no luster.no lyngdal.no lyngen.no ivgu.no lardal.no lerdal.no lærdal.no lodingen.no lødingen.no lorenskog.no lørenskog.no loten.no løten.no malvik.no masoy.no måsøy.no muosat.no muosát.no mandal.no marker.no marnardal.no masfjorden.no meland.no meldal.no melhus.no meloy.no meløy.no meraker.no meråker.no moareke.no moåreke.no midsund.no midtre-gauldal.no modalen.no modum.no molde.no moskenes.no moss.no mosvik.no malselv.no målselv.no malatvuopmi.no málatvuopmi.no namdalseid.no aejrie.no namsos.no namsskogan.no naamesjevuemie.no nååmesjevuemie.no laakesvuemie.no nannestad.no narvik.no narviika.no naustdal.no nedre-eiker.no nes.akershus.no nes.buskerud.no nesna.no nesodden.no nesseby.no unjarga.no unjárga.no nesset.no nissedal.no nittedal.no nord-aurdal.no nord-fron.no nord-odal.no norddal.no nordkapp.no davvenjarga.no davvenjárga.no nordre-land.no nordreisa.no raisa.no ráisa.no nore-og-uvdal.no notodden.no naroy.no nærøy.no notteroy.no nøtterøy.no odda.no oksnes.no øksnes.no oppdal.no oppegard.no oppegård.no orkdal.no orland.no ørland.no orskog.no ørskog.no orsta.no ørsta.no os.hedmark.no os.hordaland.no osen.no osteroy.no osterøy.no ostre-toten.no østre-toten.no overhalla.no ovre-eiker.no øvre-eiker.no oyer.no øyer.no oygarden.no øygarden.no oystre-slidre.no øystre-slidre.no porsanger.no porsangu.no porsáŋgu.no porsgrunn.no radoy.no radøy.no rakkestad.no rana.no ruovat.no randaberg.no rauma.no rendalen.no rennebu.no rennesoy.no rennesøy.no rindal.no ringebu.no ringerike.no ringsaker.no rissa.no risor.no risør.no roan.no rollag.no rygge.no ralingen.no rælingen.no rodoy.no rødøy.no romskog.no rømskog.no roros.no røros.no rost.no røst.no royken.no røyken.no royrvik.no røyrvik.no rade.no råde.no salangen.no siellak.no saltdal.no salat.no sálát.no sálat.no samnanger.no sande.more-og-romsdal.no sande.møre-og-romsdal.no sande.vestfold.no sandefjord.no sandnes.no sandoy.no sandøy.no sarpsborg.no sauda.no sauherad.no sel.no selbu.no selje.no seljord.no sigdal.no siljan.no sirdal.no skaun.no skedsmo.no ski.no skien.no skiptvet.no skjervoy.no skjervøy.no skierva.no skiervá.no skjak.no skjåk.no skodje.no skanland.no skånland.no skanit.no skánit.no smola.no smøla.no snillfjord.no snasa.no snåsa.no snoasa.no snaase.no snåase.no sogndal.no sokndal.no sola.no solund.no songdalen.no sortland.no spydeberg.no stange.no stavanger.no steigen.no steinkjer.no stjordal.no stjørdal.no stokke.no stor-elvdal.no stord.no stordal.no storfjord.no omasvuotna.no strand.no stranda.no stryn.no sula.no suldal.no sund.no sunndal.no surnadal.no sveio.no svelvik.no sykkylven.no sogne.no søgne.no somna.no sømna.no sondre-land.no søndre-land.no sor-aurdal.no sør-aurdal.no sor-fron.no sør-fron.no sor-odal.no sør-odal.no sor-varanger.no sør-varanger.no matta-varjjat.no mátta-várjjat.no sorfold.no sørfold.no sorreisa.no sørreisa.no sorum.no sørum.no tana.no deatnu.no time.no tingvoll.no tinn.no tjeldsund.no dielddanuorri.no tjome.no tjøme.no tokke.no tolga.no torsken.no tranoy.no tranøy.no tromso.no tromsø.no tromsa.no romsa.no trondheim.no troandin.no trysil.no trana.no træna.no trogstad.no trøgstad.no tvedestrand.no tydal.no tynset.no tysfjord.no divtasvuodna.no divttasvuotna.no tysnes.no tysvar.no tysvær.no tonsberg.no tønsberg.no ullensaker.no ullensvang.no ulvik.no utsira.no vadso.no vadsø.no cahcesuolo.no čáhcesuolo.no vaksdal.no valle.no vang.no vanylven.no vardo.no vardø.no varggat.no várggát.no vefsn.no vaapste.no vega.no vegarshei.no vegårshei.no vennesla.no verdal.no verran.no vestby.no vestnes.no vestre-slidre.no vestre-toten.no vestvagoy.no vestvågøy.no vevelstad.no vik.no vikna.no vindafjord.no volda.no voss.no varoy.no værøy.no vagan.no vågan.no voagat.no vagsoy.no vågsøy.no vaga.no vågå.no valer.ostfold.no våler.østfold.no valer.hedmark.no våler.hedmark.no // np : http://www.mos.com.np/register.html *.np // nr : http://cenpac.net.nr/dns/index.html // Submitted by registry <technician@cenpac.net.nr> nr biz.nr info.nr gov.nr edu.nr org.nr net.nr com.nr // nu : https://en.wikipedia.org/wiki/.nu nu // nz : https://en.wikipedia.org/wiki/.nz // Submitted by registry <jay@nzrs.net.nz> nz ac.nz co.nz cri.nz geek.nz gen.nz govt.nz health.nz iwi.nz kiwi.nz maori.nz mil.nz māori.nz net.nz org.nz parliament.nz school.nz // om : https://en.wikipedia.org/wiki/.om om co.om com.om edu.om gov.om med.om museum.om net.om org.om pro.om // onion : https://tools.ietf.org/html/rfc7686 onion // org : https://en.wikipedia.org/wiki/.org org // pa : http://www.nic.pa/ // Some additional second level "domains" resolve directly as hostnames, such as // pannet.pa, so we add a rule for "pa". pa ac.pa gob.pa com.pa org.pa sld.pa edu.pa net.pa ing.pa abo.pa med.pa nom.pa // pe : https://www.nic.pe/InformeFinalComision.pdf pe edu.pe gob.pe nom.pe mil.pe org.pe com.pe net.pe // pf : http://www.gobin.info/domainname/formulaire-pf.pdf pf com.pf org.pf edu.pf // pg : https://en.wikipedia.org/wiki/.pg *.pg // ph : http://www.domains.ph/FAQ2.asp // Submitted by registry <jed@email.com.ph> ph com.ph net.ph org.ph gov.ph edu.ph ngo.ph mil.ph i.ph // pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK pk com.pk net.pk edu.pk org.pk fam.pk biz.pk web.pk gov.pk gob.pk gok.pk gon.pk gop.pk gos.pk info.pk // pl http://www.dns.pl/english/index.html // Submitted by registry pl com.pl net.pl org.pl // pl functional domains (http://www.dns.pl/english/index.html) aid.pl agro.pl atm.pl auto.pl biz.pl edu.pl gmina.pl gsm.pl info.pl mail.pl miasta.pl media.pl mil.pl nieruchomosci.pl nom.pl pc.pl powiat.pl priv.pl realestate.pl rel.pl sex.pl shop.pl sklep.pl sos.pl szkola.pl targi.pl tm.pl tourism.pl travel.pl turystyka.pl // Government domains gov.pl ap.gov.pl ic.gov.pl is.gov.pl us.gov.pl kmpsp.gov.pl kppsp.gov.pl kwpsp.gov.pl psp.gov.pl wskr.gov.pl kwp.gov.pl mw.gov.pl ug.gov.pl um.gov.pl umig.gov.pl ugim.gov.pl upow.gov.pl uw.gov.pl starostwo.gov.pl pa.gov.pl po.gov.pl psse.gov.pl pup.gov.pl rzgw.gov.pl sa.gov.pl so.gov.pl sr.gov.pl wsa.gov.pl sko.gov.pl uzs.gov.pl wiih.gov.pl winb.gov.pl pinb.gov.pl wios.gov.pl witd.gov.pl wzmiuw.gov.pl piw.gov.pl wiw.gov.pl griw.gov.pl wif.gov.pl oum.gov.pl sdn.gov.pl zp.gov.pl uppo.gov.pl mup.gov.pl wuoz.gov.pl konsulat.gov.pl oirm.gov.pl // pl regional domains (http://www.dns.pl/english/index.html) augustow.pl babia-gora.pl bedzin.pl beskidy.pl bialowieza.pl bialystok.pl bielawa.pl bieszczady.pl boleslawiec.pl bydgoszcz.pl bytom.pl cieszyn.pl czeladz.pl czest.pl dlugoleka.pl elblag.pl elk.pl glogow.pl gniezno.pl gorlice.pl grajewo.pl ilawa.pl jaworzno.pl jelenia-gora.pl jgora.pl kalisz.pl kazimierz-dolny.pl karpacz.pl kartuzy.pl kaszuby.pl katowice.pl kepno.pl ketrzyn.pl klodzko.pl kobierzyce.pl kolobrzeg.pl konin.pl konskowola.pl kutno.pl lapy.pl lebork.pl legnica.pl lezajsk.pl limanowa.pl lomza.pl lowicz.pl lubin.pl lukow.pl malbork.pl malopolska.pl mazowsze.pl mazury.pl mielec.pl mielno.pl mragowo.pl naklo.pl nowaruda.pl nysa.pl olawa.pl olecko.pl olkusz.pl olsztyn.pl opoczno.pl opole.pl ostroda.pl ostroleka.pl ostrowiec.pl ostrowwlkp.pl pila.pl pisz.pl podhale.pl podlasie.pl polkowice.pl pomorze.pl pomorskie.pl prochowice.pl pruszkow.pl przeworsk.pl pulawy.pl radom.pl rawa-maz.pl rybnik.pl rzeszow.pl sanok.pl sejny.pl slask.pl slupsk.pl sosnowiec.pl stalowa-wola.pl skoczow.pl starachowice.pl stargard.pl suwalki.pl swidnica.pl swiebodzin.pl swinoujscie.pl szczecin.pl szczytno.pl tarnobrzeg.pl tgory.pl turek.pl tychy.pl ustka.pl walbrzych.pl warmia.pl warszawa.pl waw.pl wegrow.pl wielun.pl wlocl.pl wloclawek.pl wodzislaw.pl wolomin.pl wroclaw.pl zachpomor.pl zagan.pl zarow.pl zgora.pl zgorzelec.pl // pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf pm // pn : http://www.government.pn/PnRegistry/policies.htm pn gov.pn co.pn org.pn edu.pn net.pn // post : https://en.wikipedia.org/wiki/.post post // pr : http://www.nic.pr/index.asp?f=1 pr com.pr net.pr org.pr gov.pr edu.pr isla.pr pro.pr biz.pr info.pr name.pr // these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr est.pr prof.pr ac.pr // pro : http://registry.pro/get-pro pro aaa.pro aca.pro acct.pro avocat.pro bar.pro cpa.pro eng.pro jur.pro law.pro med.pro recht.pro // ps : https://en.wikipedia.org/wiki/.ps // http://www.nic.ps/registration/policy.html#reg ps edu.ps gov.ps sec.ps plo.ps com.ps org.ps net.ps // pt : http://online.dns.pt/dns/start_dns pt net.pt gov.pt org.pt edu.pt int.pt publ.pt com.pt nome.pt // pw : https://en.wikipedia.org/wiki/.pw pw co.pw ne.pw or.pw ed.pw go.pw belau.pw // py : http://www.nic.py/pautas.html#seccion_9 // Submitted by registry py com.py coop.py edu.py gov.py mil.py net.py org.py // qa : http://domains.qa/en/ qa com.qa edu.qa gov.qa mil.qa name.qa net.qa org.qa sch.qa // re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs re asso.re com.re nom.re // ro : http://www.rotld.ro/ ro arts.ro com.ro firm.ro info.ro nom.ro nt.ro org.ro rec.ro store.ro tm.ro www.ro // rs : https://www.rnids.rs/en/domains/national-domains rs ac.rs co.rs edu.rs gov.rs in.rs org.rs // ru : https://cctld.ru/en/domains/domens_ru/reserved/ ru ac.ru edu.ru gov.ru int.ru mil.ru test.ru // rw : http://www.nic.rw/cgi-bin/policy.pl rw gov.rw net.rw edu.rw ac.rw com.rw co.rw int.rw mil.rw gouv.rw // sa : http://www.nic.net.sa/ sa com.sa net.sa org.sa gov.sa med.sa pub.sa edu.sa sch.sa // sb : http://www.sbnic.net.sb/ // Submitted by registry <lee.humphries@telekom.com.sb> sb com.sb edu.sb gov.sb net.sb org.sb // sc : http://www.nic.sc/ sc com.sc gov.sc net.sc org.sc edu.sc // sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm // Submitted by registry <admin@isoc.sd> sd com.sd net.sd org.sd edu.sd med.sd tv.sd gov.sd info.sd // se : https://en.wikipedia.org/wiki/.se // Submitted by registry <patrik.wallstrom@iis.se> se a.se ac.se b.se bd.se brand.se c.se d.se e.se f.se fh.se fhsk.se fhv.se g.se h.se i.se k.se komforb.se kommunalforbund.se komvux.se l.se lanbib.se m.se n.se naturbruksgymn.se o.se org.se p.se parti.se pp.se press.se r.se s.se t.se tm.se u.se w.se x.se y.se z.se // sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines sg com.sg net.sg org.sg gov.sg edu.sg per.sg // sh : http://www.nic.sh/registrar.html sh com.sh net.sh gov.sh org.sh mil.sh // si : https://en.wikipedia.org/wiki/.si si // sj : No registrations at this time. // Submitted by registry <jarle@uninett.no> sj // sk : https://en.wikipedia.org/wiki/.sk // list of 2nd level domains ? sk // sl : http://www.nic.sl // Submitted by registry <adam@neoip.com> sl com.sl net.sl edu.sl gov.sl org.sl // sm : https://en.wikipedia.org/wiki/.sm sm // sn : https://en.wikipedia.org/wiki/.sn sn art.sn com.sn edu.sn gouv.sn org.sn perso.sn univ.sn // so : http://www.soregistry.com/ so com.so net.so org.so // sr : https://en.wikipedia.org/wiki/.sr sr // st : http://www.nic.st/html/policyrules/ st co.st com.st consulado.st edu.st embaixada.st gov.st mil.st net.st org.st principe.st saotome.st store.st // su : https://en.wikipedia.org/wiki/.su su // sv : http://www.svnet.org.sv/niveldos.pdf sv com.sv edu.sv gob.sv org.sv red.sv // sx : https://en.wikipedia.org/wiki/.sx // Submitted by registry <jcvignes@openregistry.com> sx gov.sx // sy : https://en.wikipedia.org/wiki/.sy // see also: http://www.gobin.info/domainname/sy.doc sy edu.sy gov.sy net.sy mil.sy com.sy org.sy // sz : https://en.wikipedia.org/wiki/.sz // http://www.sispa.org.sz/ sz co.sz ac.sz org.sz // tc : https://en.wikipedia.org/wiki/.tc tc // td : https://en.wikipedia.org/wiki/.td td // tel: https://en.wikipedia.org/wiki/.tel // http://www.telnic.org/ tel // tf : https://en.wikipedia.org/wiki/.tf tf // tg : https://en.wikipedia.org/wiki/.tg // http://www.nic.tg/ tg // th : https://en.wikipedia.org/wiki/.th // Submitted by registry <krit@thains.co.th> th ac.th co.th go.th in.th mi.th net.th or.th // tj : http://www.nic.tj/policy.html tj ac.tj biz.tj co.tj com.tj edu.tj go.tj gov.tj int.tj mil.tj name.tj net.tj nic.tj org.tj test.tj web.tj // tk : https://en.wikipedia.org/wiki/.tk tk // tl : https://en.wikipedia.org/wiki/.tl tl gov.tl // tm : http://www.nic.tm/local.html tm com.tm co.tm org.tm net.tm nom.tm gov.tm mil.tm edu.tm // tn : https://en.wikipedia.org/wiki/.tn // http://whois.ati.tn/ tn com.tn ens.tn fin.tn gov.tn ind.tn intl.tn nat.tn net.tn org.tn info.tn perso.tn tourism.tn edunet.tn rnrt.tn rns.tn rnu.tn mincom.tn agrinet.tn defense.tn turen.tn // to : https://en.wikipedia.org/wiki/.to // Submitted by registry <egullich@colo.to> to com.to gov.to net.to org.to edu.to mil.to // subTLDs: https://www.nic.tr/forms/eng/policies.pdf // and: https://www.nic.tr/forms/politikalar.pdf // Submitted by <mehmetgurevin@gmail.com> tr com.tr info.tr biz.tr net.tr org.tr web.tr gen.tr tv.tr av.tr dr.tr bbs.tr name.tr tel.tr gov.tr bel.tr pol.tr mil.tr k12.tr edu.tr kep.tr // Used by Northern Cyprus nc.tr // Used by government agencies of Northern Cyprus gov.nc.tr // travel : https://en.wikipedia.org/wiki/.travel travel // tt : http://www.nic.tt/ tt co.tt com.tt org.tt net.tt biz.tt info.tt pro.tt int.tt coop.tt jobs.tt mobi.tt travel.tt museum.tt aero.tt name.tt gov.tt edu.tt // tv : https://en.wikipedia.org/wiki/.tv // Not listing any 2LDs as reserved since none seem to exist in practice, // Wikipedia notwithstanding. tv // tw : https://en.wikipedia.org/wiki/.tw tw edu.tw gov.tw mil.tw com.tw net.tw org.tw idv.tw game.tw ebiz.tw club.tw 網路.tw 組織.tw 商業.tw // tz : http://www.tznic.or.tz/index.php/domains // Submitted by registry <manager@tznic.or.tz> tz ac.tz co.tz go.tz hotel.tz info.tz me.tz mil.tz mobi.tz ne.tz or.tz sc.tz tv.tz // ua : https://hostmaster.ua/policy/?ua // Submitted by registry <dk@cctld.ua> ua // ua 2LD com.ua edu.ua gov.ua in.ua net.ua org.ua // ua geographic names // https://hostmaster.ua/2ld/ cherkassy.ua cherkasy.ua chernigov.ua chernihiv.ua chernivtsi.ua chernovtsy.ua ck.ua cn.ua cr.ua crimea.ua cv.ua dn.ua dnepropetrovsk.ua dnipropetrovsk.ua dominic.ua donetsk.ua dp.ua if.ua ivano-frankivsk.ua kh.ua kharkiv.ua kharkov.ua kherson.ua khmelnitskiy.ua khmelnytskyi.ua kiev.ua kirovograd.ua km.ua kr.ua krym.ua ks.ua kv.ua kyiv.ua lg.ua lt.ua lugansk.ua lutsk.ua lv.ua lviv.ua mk.ua mykolaiv.ua nikolaev.ua od.ua odesa.ua odessa.ua pl.ua poltava.ua rivne.ua rovno.ua rv.ua sb.ua sebastopol.ua sevastopol.ua sm.ua sumy.ua te.ua ternopil.ua uz.ua uzhgorod.ua vinnica.ua vinnytsia.ua vn.ua volyn.ua yalta.ua zaporizhzhe.ua zaporizhzhia.ua zhitomir.ua zhytomyr.ua zp.ua zt.ua // ug : https://www.registry.co.ug/ ug co.ug or.ug ac.ug sc.ug go.ug ne.ug com.ug org.ug // uk : https://en.wikipedia.org/wiki/.uk // Submitted by registry <Michael.Daly@nominet.org.uk> uk ac.uk co.uk gov.uk ltd.uk me.uk net.uk nhs.uk org.uk plc.uk police.uk *.sch.uk // us : https://en.wikipedia.org/wiki/.us us dni.us fed.us isa.us kids.us nsn.us // us geographic names ak.us al.us ar.us as.us az.us ca.us co.us ct.us dc.us de.us fl.us ga.us gu.us hi.us ia.us id.us il.us in.us ks.us ky.us la.us ma.us md.us me.us mi.us mn.us mo.us ms.us mt.us nc.us nd.us ne.us nh.us nj.us nm.us nv.us ny.us oh.us ok.us or.us pa.us pr.us ri.us sc.us sd.us tn.us tx.us ut.us vi.us vt.us va.us wa.us wi.us wv.us wy.us // The registrar notes several more specific domains available in each state, // such as state.*.us, dst.*.us, etc., but resolution of these is somewhat // haphazard; in some states these domains resolve as addresses, while in others // only subdomains are available, or even nothing at all. We include the // most common ones where it's clear that different sites are different // entities. k12.ak.us k12.al.us k12.ar.us k12.as.us k12.az.us k12.ca.us k12.co.us k12.ct.us k12.dc.us k12.de.us k12.fl.us k12.ga.us k12.gu.us // k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login k12.ia.us k12.id.us k12.il.us k12.in.us k12.ks.us k12.ky.us k12.la.us k12.ma.us k12.md.us k12.me.us k12.mi.us k12.mn.us k12.mo.us k12.ms.us k12.mt.us k12.nc.us // k12.nd.us Bug 1028347 - Removed at request of Travis Rosso <trossow@nd.gov> k12.ne.us k12.nh.us k12.nj.us k12.nm.us k12.nv.us k12.ny.us k12.oh.us k12.ok.us k12.or.us k12.pa.us k12.pr.us k12.ri.us k12.sc.us // k12.sd.us Bug 934131 - Removed at request of James Booze <James.Booze@k12.sd.us> k12.tn.us k12.tx.us k12.ut.us k12.vi.us k12.vt.us k12.va.us k12.wa.us k12.wi.us // k12.wv.us Bug 947705 - Removed at request of Verne Britton <verne@wvnet.edu> k12.wy.us cc.ak.us cc.al.us cc.ar.us cc.as.us cc.az.us cc.ca.us cc.co.us cc.ct.us cc.dc.us cc.de.us cc.fl.us cc.ga.us cc.gu.us cc.hi.us cc.ia.us cc.id.us cc.il.us cc.in.us cc.ks.us cc.ky.us cc.la.us cc.ma.us cc.md.us cc.me.us cc.mi.us cc.mn.us cc.mo.us cc.ms.us cc.mt.us cc.nc.us cc.nd.us cc.ne.us cc.nh.us cc.nj.us cc.nm.us cc.nv.us cc.ny.us cc.oh.us cc.ok.us cc.or.us cc.pa.us cc.pr.us cc.ri.us cc.sc.us cc.sd.us cc.tn.us cc.tx.us cc.ut.us cc.vi.us cc.vt.us cc.va.us cc.wa.us cc.wi.us cc.wv.us cc.wy.us lib.ak.us lib.al.us lib.ar.us lib.as.us lib.az.us lib.ca.us lib.co.us lib.ct.us lib.dc.us // lib.de.us Issue #243 - Moved to Private section at request of Ed Moore <Ed.Moore@lib.de.us> lib.fl.us lib.ga.us lib.gu.us lib.hi.us lib.ia.us lib.id.us lib.il.us lib.in.us lib.ks.us lib.ky.us lib.la.us lib.ma.us lib.md.us lib.me.us lib.mi.us lib.mn.us lib.mo.us lib.ms.us lib.mt.us lib.nc.us lib.nd.us lib.ne.us lib.nh.us lib.nj.us lib.nm.us lib.nv.us lib.ny.us lib.oh.us lib.ok.us lib.or.us lib.pa.us lib.pr.us lib.ri.us lib.sc.us lib.sd.us lib.tn.us lib.tx.us lib.ut.us lib.vi.us lib.vt.us lib.va.us lib.wa.us lib.wi.us // lib.wv.us Bug 941670 - Removed at request of Larry W Arnold <arnold@wvlc.lib.wv.us> lib.wy.us // k12.ma.us contains school districts in Massachusetts. The 4LDs are // managed independently except for private (PVT), charter (CHTR) and // parochial (PAROCH) schools. Those are delegated directly to the // 5LD operators. <k12-ma-hostmaster _ at _ rsuc.gweep.net> pvt.k12.ma.us chtr.k12.ma.us paroch.k12.ma.us // uy : http://www.nic.org.uy/ uy com.uy edu.uy gub.uy mil.uy net.uy org.uy // uz : http://www.reg.uz/ uz co.uz com.uz net.uz org.uz // va : https://en.wikipedia.org/wiki/.va va // vc : https://en.wikipedia.org/wiki/.vc // Submitted by registry <kshah@ca.afilias.info> vc com.vc net.vc org.vc gov.vc mil.vc edu.vc // ve : https://registro.nic.ve/ // Submitted by registry ve arts.ve co.ve com.ve e12.ve edu.ve firm.ve gob.ve gov.ve info.ve int.ve mil.ve net.ve org.ve rec.ve store.ve tec.ve web.ve // vg : https://en.wikipedia.org/wiki/.vg vg // vi : http://www.nic.vi/newdomainform.htm // http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other // TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they // are available for registration (which they do not seem to be). vi co.vi com.vi k12.vi net.vi org.vi // vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp vn com.vn net.vn org.vn edu.vn gov.vn int.vn ac.vn biz.vn info.vn name.vn pro.vn health.vn // vu : https://en.wikipedia.org/wiki/.vu // http://www.vunic.vu/ vu com.vu edu.vu net.vu org.vu // wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf wf // ws : https://en.wikipedia.org/wiki/.ws // http://samoanic.ws/index.dhtml ws com.ws net.ws org.ws gov.ws edu.ws // yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf yt // IDN ccTLDs // When submitting patches, please maintain a sort by ISO 3166 ccTLD, then // U-label, and follow this format: // // A-Label ("<Latin renderings>", <language name>[, variant info]) : <ISO 3166 ccTLD> // // [sponsoring org] // U-Label // xn--mgbaam7a8h ("Emerat", Arabic) : AE // http://nic.ae/english/arabicdomain/rules.jsp امارات // xn--y9a3aq ("hye", Armenian) : AM // ISOC AM (operated by .am Registry) հայ // xn--54b7fta0cc ("Bangla", Bangla) : BD বাংলা // xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY // Operated by .by registry бел // xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN // CNNIC // http://cnnic.cn/html/Dir/2005/10/11/3218.htm 中国 // xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN // CNNIC // http://cnnic.cn/html/Dir/2005/10/11/3218.htm 中國 // xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ الجزائر // xn--wgbh1c ("Egypt/Masr", Arabic) : EG // http://www.dotmasr.eg/ مصر // xn--e1a4c ("eu", Cyrillic) : EU ею // xn--node ("ge", Georgian Mkhedruli) : GE გე // xn--qxam ("el", Greek) : GR // Hellenic Ministry of Infrastructure, Transport, and Networks ελ // xn--j6w193g ("Hong Kong", Chinese) : HK // https://www2.hkirc.hk/register/rules.jsp 香港 // xn--h2brj9c ("Bharat", Devanagari) : IN // India भारत // xn--mgbbh1a71e ("Bharat", Arabic) : IN // India بھارت // xn--fpcrj9c3d ("Bharat", Telugu) : IN // India భారత్ // xn--gecrj9c ("Bharat", Gujarati) : IN // India ભારત // xn--s9brj9c ("Bharat", Gurmukhi) : IN // India ਭਾਰਤ // xn--45brj9c ("Bharat", Bengali) : IN // India ভারত // xn--xkc2dl3a5ee0h ("India", Tamil) : IN // India இந்தியா // xn--mgba3a4f16a ("Iran", Persian) : IR ایران // xn--mgba3a4fra ("Iran", Arabic) : IR ايران // xn--mgbtx2b ("Iraq", Arabic) : IQ // Communications and Media Commission عراق // xn--mgbayh7gpa ("al-Ordon", Arabic) : JO // National Information Technology Center (NITC) // Royal Scientific Society, Al-Jubeiha الاردن // xn--3e0b707e ("Republic of Korea", Hangul) : KR 한국 // xn--80ao21a ("Kaz", Kazakh) : KZ қаз // xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK // http://nic.lk ලංකා // xn--xkc2al3hye2a ("Ilangai", Tamil) : LK // http://nic.lk இலங்கை // xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA المغرب // xn--d1alf ("mkd", Macedonian) : MK // MARnet мкд // xn--l1acc ("mon", Mongolian) : MN мон // xn--mix891f ("Macao", Chinese, Traditional) : MO // MONIC / HNET Asia (Registry Operator for .mo) 澳門 // xn--mix082f ("Macao", Chinese, Simplified) : MO 澳门 // xn--mgbx4cd0ab ("Malaysia", Malay) : MY مليسيا // xn--mgb9awbf ("Oman", Arabic) : OM عمان // xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK پاکستان // xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK پاكستان // xn--ygbi2ammx ("Falasteen", Arabic) : PS // The Palestinian National Internet Naming Authority (PNINA) // http://www.pnina.ps فلسطين // xn--90a3ac ("srb", Cyrillic) : RS // https://www.rnids.rs/en/domains/national-domains срб пр.срб орг.срб обр.срб од.срб упр.срб ак.срб // xn--p1ai ("rf", Russian-Cyrillic) : RU // http://www.cctld.ru/en/docs/rulesrf.php рф // xn--wgbl6a ("Qatar", Arabic) : QA // http://www.ict.gov.qa/ قطر // xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA // http://www.nic.net.sa/ السعودية // xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA السعودیة // xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA السعودیۃ // xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA السعوديه // xn--mgbpl2fh ("sudan", Arabic) : SD // Operated by .sd registry سودان // xn--yfro4i67o Singapore ("Singapore", Chinese) : SG 新加坡 // xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG சிங்கப்பூர் // xn--ogbpf8fl ("Syria", Arabic) : SY سورية // xn--mgbtf8fl ("Syria", Arabic, variant) : SY سوريا // xn--o3cw4h ("Thai", Thai) : TH // http://www.thnic.co.th ไทย ศึกษา.ไทย ธุรกิจ.ไทย รัฐบาล.ไทย ทหาร.ไทย เน็ต.ไทย องค์กร.ไทย // xn--pgbs0dh ("Tunisia", Arabic) : TN // http://nic.tn تونس // xn--kpry57d ("Taiwan", Chinese, Traditional) : TW // http://www.twnic.net/english/dn/dn_07a.htm 台灣 // xn--kprw13d ("Taiwan", Chinese, Simplified) : TW // http://www.twnic.net/english/dn/dn_07a.htm 台湾 // xn--nnx388a ("Taiwan", Chinese, variant) : TW 臺灣 // xn--j1amh ("ukr", Cyrillic) : UA укр // xn--mgb2ddes ("AlYemen", Arabic) : YE اليمن // xxx : http://icmregistry.com xxx // ye : http://www.y.net.ye/services/domain_name.htm *.ye // za : http://www.zadna.org.za/content/page/domain-information ac.za agric.za alt.za co.za edu.za gov.za grondar.za law.za mil.za net.za ngo.za nis.za nom.za org.za school.za tm.za web.za // zm : https://zicta.zm/ // Submitted by registry <info@zicta.zm> zm ac.zm biz.zm co.zm com.zm edu.zm gov.zm info.zm mil.zm net.zm org.zm sch.zm // zw : https://www.potraz.gov.zw/ // Confirmed by registry <bmtengwa@potraz.gov.zw> 2017-01-25 zw ac.zw co.zw gov.zw mil.zw org.zw // List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2017-02-23T00:46:09Z // aaa : 2015-02-26 American Automobile Association, Inc. aaa // aarp : 2015-05-21 AARP aarp // abarth : 2015-07-30 Fiat Chrysler Automobiles N.V. abarth // abb : 2014-10-24 ABB Ltd abb // abbott : 2014-07-24 Abbott Laboratories, Inc. abbott // abbvie : 2015-07-30 AbbVie Inc. abbvie // abc : 2015-07-30 Disney Enterprises, Inc. abc // able : 2015-06-25 Able Inc. able // abogado : 2014-04-24 Top Level Domain Holdings Limited abogado // abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre abudhabi // academy : 2013-11-07 Half Oaks, LLC academy // accenture : 2014-08-15 Accenture plc accenture // accountant : 2014-11-20 dot Accountant Limited accountant // accountants : 2014-03-20 Knob Town, LLC accountants // aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG aco // active : 2014-05-01 The Active Network, Inc active // actor : 2013-12-12 United TLD Holdco Ltd. actor // adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC) adac // ads : 2014-12-04 Charleston Road Registry Inc. ads // adult : 2014-10-16 ICM Registry AD LLC adult // aeg : 2015-03-19 Aktiebolaget Electrolux aeg // aetna : 2015-05-21 Aetna Life Insurance Company aetna // afamilycompany : 2015-07-23 Johnson Shareholdings, Inc. afamilycompany // afl : 2014-10-02 Australian Football League afl // africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa africa // agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) agakhan // agency : 2013-11-14 Steel Falls, LLC agency // aig : 2014-12-18 American International Group, Inc. aig // aigo : 2015-08-06 aigo Digital Technology Co,Ltd. aigo // airbus : 2015-07-30 Airbus S.A.S. airbus // airforce : 2014-03-06 United TLD Holdco Ltd. airforce // airtel : 2014-10-24 Bharti Airtel Limited airtel // akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) akdn // alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V. alfaromeo // alibaba : 2015-01-15 Alibaba Group Holding Limited alibaba // alipay : 2015-01-15 Alibaba Group Holding Limited alipay // allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft allfinanz // allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company allstate // ally : 2015-06-18 Ally Financial Inc. ally // alsace : 2014-07-02 REGION D ALSACE alsace // alstom : 2015-07-30 ALSTOM alstom // americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc. americanexpress // americanfamily : 2015-07-23 AmFam, Inc. americanfamily // amex : 2015-07-31 American Express Travel Related Services Company, Inc. amex // amfam : 2015-07-23 AmFam, Inc. amfam // amica : 2015-05-28 Amica Mutual Insurance Company amica // amsterdam : 2014-07-24 Gemeente Amsterdam amsterdam // analytics : 2014-12-18 Campus IP LLC analytics // android : 2014-08-07 Charleston Road Registry Inc. android // anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. anquan // anz : 2015-07-31 Australia and New Zealand Banking Group Limited anz // aol : 2015-09-17 AOL Inc. aol // apartments : 2014-12-11 June Maple, LLC apartments // app : 2015-05-14 Charleston Road Registry Inc. app // apple : 2015-05-14 Apple Inc. apple // aquarelle : 2014-07-24 Aquarelle.com aquarelle // arab : 2015-11-12 League of Arab States arab // aramco : 2014-11-20 Aramco Services Company aramco // archi : 2014-02-06 STARTING DOT LIMITED archi // army : 2014-03-06 United TLD Holdco Ltd. army // art : 2016-03-24 UK Creative Ideas Limited art // arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. arte // asda : 2015-07-31 Wal-Mart Stores, Inc. asda // associates : 2014-03-06 Baxter Hill, LLC associates // athleta : 2015-07-30 The Gap, Inc. athleta // attorney : 2014-03-20 attorney // auction : 2014-03-20 auction // audi : 2015-05-21 AUDI Aktiengesellschaft audi // audible : 2015-06-25 Amazon EU S.à r.l. audible // audio : 2014-03-20 Uniregistry, Corp. audio // auspost : 2015-08-13 Australian Postal Corporation auspost // author : 2014-12-18 Amazon EU S.à r.l. author // auto : 2014-11-13 auto // autos : 2014-01-09 DERAutos, LLC autos // avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca avianca // aws : 2015-06-25 Amazon EU S.à r.l. aws // axa : 2013-12-19 AXA SA axa // azure : 2014-12-18 Microsoft Corporation azure // baby : 2015-04-09 Johnson & Johnson Services, Inc. baby // baidu : 2015-01-08 Baidu, Inc. baidu // banamex : 2015-07-30 Citigroup Inc. banamex // bananarepublic : 2015-07-31 The Gap, Inc. bananarepublic // band : 2014-06-12 band // bank : 2014-09-25 fTLD Registry Services LLC bank // bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable bar // barcelona : 2014-07-24 Municipi de Barcelona barcelona // barclaycard : 2014-11-20 Barclays Bank PLC barclaycard // barclays : 2014-11-20 Barclays Bank PLC barclays // barefoot : 2015-06-11 Gallo Vineyards, Inc. barefoot // bargains : 2013-11-14 Half Hallow, LLC bargains // baseball : 2015-10-29 MLB Advanced Media DH, LLC baseball // basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA) basketball // bauhaus : 2014-04-17 Werkhaus GmbH bauhaus // bayern : 2014-01-23 Bayern Connect GmbH bayern // bbc : 2014-12-18 British Broadcasting Corporation bbc // bbt : 2015-07-23 BB&T Corporation bbt // bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. bbva // bcg : 2015-04-02 The Boston Consulting Group, Inc. bcg // bcn : 2014-07-24 Municipi de Barcelona bcn // beats : 2015-05-14 Beats Electronics, LLC beats // beauty : 2015-12-03 L'Oréal beauty // beer : 2014-01-09 Top Level Domain Holdings Limited beer // bentley : 2014-12-18 Bentley Motors Limited bentley // berlin : 2013-10-31 dotBERLIN GmbH & Co. KG berlin // best : 2013-12-19 BestTLD Pty Ltd best // bestbuy : 2015-07-31 BBY Solutions, Inc. bestbuy // bet : 2015-05-07 Afilias plc bet // bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited bharti // bible : 2014-06-19 American Bible Society bible // bid : 2013-12-19 dot Bid Limited bid // bike : 2013-08-27 Grand Hollow, LLC bike // bing : 2014-12-18 Microsoft Corporation bing // bingo : 2014-12-04 Sand Cedar, LLC bingo // bio : 2014-03-06 STARTING DOT LIMITED bio // black : 2014-01-16 Afilias Limited black // blackfriday : 2014-01-16 Uniregistry, Corp. blackfriday // blanco : 2015-07-16 BLANCO GmbH + Co KG blanco // blockbuster : 2015-07-30 Dish DBS Corporation blockbuster // blog : 2015-05-14 blog // bloomberg : 2014-07-17 Bloomberg IP Holdings LLC bloomberg // blue : 2013-11-07 Afilias Limited blue // bms : 2014-10-30 Bristol-Myers Squibb Company bms // bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft bmw // bnl : 2014-07-24 Banca Nazionale del Lavoro bnl // bnpparibas : 2014-05-29 BNP Paribas bnpparibas // boats : 2014-12-04 DERBoats, LLC boats // boehringer : 2015-07-09 Boehringer Ingelheim International GmbH boehringer // bofa : 2015-07-31 NMS Services, Inc. bofa // bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br bom // bond : 2014-06-05 Bond University Limited bond // boo : 2014-01-30 Charleston Road Registry Inc. boo // book : 2015-08-27 Amazon EU S.à r.l. book // booking : 2015-07-16 Booking.com B.V. booking // boots : 2015-01-08 THE BOOTS COMPANY PLC boots // bosch : 2015-06-18 Robert Bosch GMBH bosch // bostik : 2015-05-28 Bostik SA bostik // boston : 2015-12-10 boston // bot : 2014-12-18 Amazon EU S.à r.l. bot // boutique : 2013-11-14 Over Galley, LLC boutique // box : 2015-11-12 NS1 Limited box // bradesco : 2014-12-18 Banco Bradesco S.A. bradesco // bridgestone : 2014-12-18 Bridgestone Corporation bridgestone // broadway : 2014-12-22 Celebrate Broadway, Inc. broadway // broker : 2014-12-11 IG Group Holdings PLC broker // brother : 2015-01-29 Brother Industries, Ltd. brother // brussels : 2014-02-06 DNS.be vzw brussels // budapest : 2013-11-21 Top Level Domain Holdings Limited budapest // bugatti : 2015-07-23 Bugatti International SA bugatti // build : 2013-11-07 Plan Bee LLC build // builders : 2013-11-07 Atomic Madison, LLC builders // business : 2013-11-07 Spring Cross, LLC business // buy : 2014-12-18 Amazon EU S.à r.l. buy // buzz : 2013-10-02 DOTSTRATEGY CO. buzz // bzh : 2014-02-27 Association www.bzh bzh // cab : 2013-10-24 Half Sunset, LLC cab // cafe : 2015-02-11 Pioneer Canyon, LLC cafe // cal : 2014-07-24 Charleston Road Registry Inc. cal // call : 2014-12-18 Amazon EU S.à r.l. call // calvinklein : 2015-07-30 PVH gTLD Holdings LLC calvinklein // cam : 2016-04-21 AC Webconnecting Holding B.V. cam // camera : 2013-08-27 Atomic Maple, LLC camera // camp : 2013-11-07 Delta Dynamite, LLC camp // cancerresearch : 2014-05-15 Australian Cancer Research Foundation cancerresearch // canon : 2014-09-12 Canon Inc. canon // capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry capetown // capital : 2014-03-06 Delta Mill, LLC capital // capitalone : 2015-08-06 Capital One Financial Corporation capitalone // car : 2015-01-22 car // caravan : 2013-12-12 Caravan International, Inc. caravan // cards : 2013-12-05 Foggy Hollow, LLC cards // care : 2014-03-06 Goose Cross care // career : 2013-10-09 dotCareer LLC career // careers : 2013-10-02 Wild Corner, LLC careers // cars : 2014-11-13 cars // cartier : 2014-06-23 Richemont DNS Inc. cartier // casa : 2013-11-21 Top Level Domain Holdings Limited casa // case : 2015-09-03 CNH Industrial N.V. case // caseih : 2015-09-03 CNH Industrial N.V. caseih // cash : 2014-03-06 Delta Lake, LLC cash // casino : 2014-12-18 Binky Sky, LLC casino // catering : 2013-12-05 New Falls. LLC catering // catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) catholic // cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA cba // cbn : 2014-08-22 The Christian Broadcasting Network, Inc. cbn // cbre : 2015-07-02 CBRE, Inc. cbre // cbs : 2015-08-06 CBS Domains Inc. cbs // ceb : 2015-04-09 The Corporate Executive Board Company ceb // center : 2013-11-07 Tin Mill, LLC center // ceo : 2013-11-07 CEOTLD Pty Ltd ceo // cern : 2014-06-05 European Organization for Nuclear Research ("CERN") cern // cfa : 2014-08-28 CFA Institute cfa // cfd : 2014-12-11 IG Group Holdings PLC cfd // chanel : 2015-04-09 Chanel International B.V. chanel // channel : 2014-05-08 Charleston Road Registry Inc. channel // chase : 2015-04-30 JPMorgan Chase & Co. chase // chat : 2014-12-04 Sand Fields, LLC chat // cheap : 2013-11-14 Sand Cover, LLC cheap // chintai : 2015-06-11 CHINTAI Corporation chintai // chloe : 2014-10-16 Richemont DNS Inc. chloe // christmas : 2013-11-21 Uniregistry, Corp. christmas // chrome : 2014-07-24 Charleston Road Registry Inc. chrome // chrysler : 2015-07-30 FCA US LLC. chrysler // church : 2014-02-06 Holly Fields, LLC church // cipriani : 2015-02-19 Hotel Cipriani Srl cipriani // circle : 2014-12-18 Amazon EU S.à r.l. circle // cisco : 2014-12-22 Cisco Technology, Inc. cisco // citadel : 2015-07-23 Citadel Domain LLC citadel // citi : 2015-07-30 Citigroup Inc. citi // citic : 2014-01-09 CITIC Group Corporation citic // city : 2014-05-29 Snow Sky, LLC city // cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. cityeats // claims : 2014-03-20 Black Corner, LLC claims // cleaning : 2013-12-05 Fox Shadow, LLC cleaning // click : 2014-06-05 Uniregistry, Corp. click // clinic : 2014-03-20 Goose Park, LLC clinic // clinique : 2015-10-01 The Estée Lauder Companies Inc. clinique // clothing : 2013-08-27 Steel Lake, LLC clothing // cloud : 2015-04-16 ARUBA S.p.A. cloud // club : 2013-11-08 .CLUB DOMAINS, LLC club // clubmed : 2015-06-25 Club Méditerranée S.A. clubmed // coach : 2014-10-09 Koko Island, LLC coach // codes : 2013-10-31 Puff Willow, LLC codes // coffee : 2013-10-17 Trixy Cover, LLC coffee // college : 2014-01-16 XYZ.COM LLC college // cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH cologne // comcast : 2015-07-23 Comcast IP Holdings I, LLC comcast // commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA commbank // community : 2013-12-05 Fox Orchard, LLC community // company : 2013-11-07 Silver Avenue, LLC company // compare : 2015-10-08 iSelect Ltd compare // computer : 2013-10-24 Pine Mill, LLC computer // comsec : 2015-01-08 VeriSign, Inc. comsec // condos : 2013-12-05 Pine House, LLC condos // construction : 2013-09-16 Fox Dynamite, LLC construction // consulting : 2013-12-05 consulting // contact : 2015-01-08 Top Level Spectrum, Inc. contact // contractors : 2013-09-10 Magic Woods, LLC contractors // cooking : 2013-11-21 Top Level Domain Holdings Limited cooking // cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. cookingchannel // cool : 2013-11-14 Koko Lake, LLC cool // corsica : 2014-09-25 Collectivité Territoriale de Corse corsica // country : 2013-12-19 Top Level Domain Holdings Limited country // coupon : 2015-02-26 Amazon EU S.à r.l. coupon // coupons : 2015-03-26 Black Island, LLC coupons // courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD courses // credit : 2014-03-20 Snow Shadow, LLC credit // creditcard : 2014-03-20 Binky Frostbite, LLC creditcard // creditunion : 2015-01-22 CUNA Performance Resources, LLC creditunion // cricket : 2014-10-09 dot Cricket Limited cricket // crown : 2014-10-24 Crown Equipment Corporation crown // crs : 2014-04-03 Federated Co-operatives Limited crs // cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd. cruise // cruises : 2013-12-05 Spring Way, LLC cruises // csc : 2014-09-25 Alliance-One Services, Inc. csc // cuisinella : 2014-04-03 SALM S.A.S. cuisinella // cymru : 2014-05-08 Nominet UK cymru // cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd. cyou // dabur : 2014-02-06 Dabur India Limited dabur // dad : 2014-01-23 Charleston Road Registry Inc. dad // dance : 2013-10-24 United TLD Holdco Ltd. dance // data : 2016-06-02 Dish DBS Corporation data // date : 2014-11-20 dot Date Limited date // dating : 2013-12-05 Pine Fest, LLC dating // datsun : 2014-03-27 NISSAN MOTOR CO., LTD. datsun // day : 2014-01-30 Charleston Road Registry Inc. day // dclk : 2014-11-20 Charleston Road Registry Inc. dclk // dds : 2015-05-07 Top Level Domain Holdings Limited dds // deal : 2015-06-25 Amazon EU S.à r.l. deal // dealer : 2014-12-22 Dealer Dot Com, Inc. dealer // deals : 2014-05-22 Sand Sunset, LLC deals // degree : 2014-03-06 degree // delivery : 2014-09-11 Steel Station, LLC delivery // dell : 2014-10-24 Dell Inc. dell // deloitte : 2015-07-31 Deloitte Touche Tohmatsu deloitte // delta : 2015-02-19 Delta Air Lines, Inc. delta // democrat : 2013-10-24 United TLD Holdco Ltd. democrat // dental : 2014-03-20 Tin Birch, LLC dental // dentist : 2014-03-20 dentist // desi : 2013-11-14 Desi Networks LLC desi // design : 2014-11-07 Top Level Design, LLC design // dev : 2014-10-16 Charleston Road Registry Inc. dev // dhl : 2015-07-23 Deutsche Post AG dhl // diamonds : 2013-09-22 John Edge, LLC diamonds // diet : 2014-06-26 Uniregistry, Corp. diet // digital : 2014-03-06 Dash Park, LLC digital // direct : 2014-04-10 Half Trail, LLC direct // directory : 2013-09-20 Extra Madison, LLC directory // discount : 2014-03-06 Holly Hill, LLC discount // discover : 2015-07-23 Discover Financial Services discover // dish : 2015-07-30 Dish DBS Corporation dish // diy : 2015-11-05 Lifestyle Domain Holdings, Inc. diy // dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. dnp // docs : 2014-10-16 Charleston Road Registry Inc. docs // doctor : 2016-06-02 Brice Trail, LLC doctor // dodge : 2015-07-30 FCA US LLC. dodge // dog : 2014-12-04 Koko Mill, LLC dog // doha : 2014-09-18 Communications Regulatory Authority (CRA) doha // domains : 2013-10-17 Sugar Cross, LLC domains // dot : 2015-05-21 Dish DBS Corporation dot // download : 2014-11-20 dot Support Limited download // drive : 2015-03-05 Charleston Road Registry Inc. drive // dtv : 2015-06-04 Dish DBS Corporation dtv // dubai : 2015-01-01 Dubai Smart Government Department dubai // duck : 2015-07-23 Johnson Shareholdings, Inc. duck // dunlop : 2015-07-02 The Goodyear Tire & Rubber Company dunlop // duns : 2015-08-06 The Dun & Bradstreet Corporation duns // dupont : 2015-06-25 E. I. du Pont de Nemours and Company dupont // durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry durban // dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG dvag // dvr : 2016-05-26 Hughes Satellite Systems Corporation dvr // earth : 2014-12-04 Interlink Co., Ltd. earth // eat : 2014-01-23 Charleston Road Registry Inc. eat // eco : 2016-07-08 Big Room Inc. eco // edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. edeka // education : 2013-11-07 Brice Way, LLC education // email : 2013-10-31 Spring Madison, LLC email // emerck : 2014-04-03 Merck KGaA emerck // energy : 2014-09-11 Binky Birch, LLC energy // engineer : 2014-03-06 United TLD Holdco Ltd. engineer // engineering : 2014-03-06 Romeo Canyon engineering // enterprises : 2013-09-20 Snow Oaks, LLC enterprises // epost : 2015-07-23 Deutsche Post AG epost // epson : 2014-12-04 Seiko Epson Corporation epson // equipment : 2013-08-27 Corn Station, LLC equipment // ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson ericsson // erni : 2014-04-03 ERNI Group Holding AG erni // esq : 2014-05-08 Charleston Road Registry Inc. esq // estate : 2013-08-27 Trixy Park, LLC estate // esurance : 2015-07-23 Esurance Insurance Company esurance // etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) etisalat // eurovision : 2014-04-24 European Broadcasting Union (EBU) eurovision // eus : 2013-12-12 Puntueus Fundazioa eus // events : 2013-12-05 Pioneer Maple, LLC events // everbank : 2014-05-15 EverBank everbank // exchange : 2014-03-06 Spring Falls, LLC exchange // expert : 2013-11-21 Magic Pass, LLC expert // exposed : 2013-12-05 Victor Beach, LLC exposed // express : 2015-02-11 Sea Sunset, LLC express // extraspace : 2015-05-14 Extra Space Storage LLC extraspace // fage : 2014-12-18 Fage International S.A. fage // fail : 2014-03-06 Atomic Pipe, LLC fail // fairwinds : 2014-11-13 FairWinds Partners, LLC fairwinds // faith : 2014-11-20 dot Faith Limited faith // family : 2015-04-02 family // fan : 2014-03-06 fan // fans : 2014-11-07 Asiamix Digital Limited fans // farm : 2013-11-07 Just Maple, LLC farm // farmers : 2015-07-09 Farmers Insurance Exchange farmers // fashion : 2014-07-03 Top Level Domain Holdings Limited fashion // fast : 2014-12-18 Amazon EU S.à r.l. fast // fedex : 2015-08-06 Federal Express Corporation fedex // feedback : 2013-12-19 Top Level Spectrum, Inc. feedback // ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V. ferrari // ferrero : 2014-12-18 Ferrero Trading Lux S.A. ferrero // fiat : 2015-07-31 Fiat Chrysler Automobiles N.V. fiat // fidelity : 2015-07-30 Fidelity Brokerage Services LLC fidelity // fido : 2015-08-06 Rogers Communications Partnership fido // film : 2015-01-08 Motion Picture Domain Registry Pty Ltd film // final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br final // finance : 2014-03-20 Cotton Cypress, LLC finance // financial : 2014-03-06 Just Cover, LLC financial // fire : 2015-06-25 Amazon EU S.à r.l. fire // firestone : 2014-12-18 Bridgestone Corporation firestone // firmdale : 2014-03-27 Firmdale Holdings Limited firmdale // fish : 2013-12-12 Fox Woods, LLC fish // fishing : 2013-11-21 Top Level Domain Holdings Limited fishing // fit : 2014-11-07 Top Level Domain Holdings Limited fit // fitness : 2014-03-06 Brice Orchard, LLC fitness // flickr : 2015-04-02 Yahoo! Domain Services Inc. flickr // flights : 2013-12-05 Fox Station, LLC flights // flir : 2015-07-23 FLIR Systems, Inc. flir // florist : 2013-11-07 Half Cypress, LLC florist // flowers : 2014-10-09 Uniregistry, Corp. flowers // fly : 2014-05-08 Charleston Road Registry Inc. fly // foo : 2014-01-23 Charleston Road Registry Inc. foo // food : 2016-04-21 Lifestyle Domain Holdings, Inc. food // foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. foodnetwork // football : 2014-12-18 Foggy Farms, LLC football // ford : 2014-11-13 Ford Motor Company ford // forex : 2014-12-11 IG Group Holdings PLC forex // forsale : 2014-05-22 forsale // forum : 2015-04-02 Fegistry, LLC forum // foundation : 2013-12-05 John Dale, LLC foundation // fox : 2015-09-11 FOX Registry, LLC fox // free : 2015-12-10 Amazon EU S.à r.l. free // fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH fresenius // frl : 2014-05-15 FRLregistry B.V. frl // frogans : 2013-12-19 OP3FT frogans // frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. frontdoor // frontier : 2015-02-05 Frontier Communications Corporation frontier // ftr : 2015-07-16 Frontier Communications Corporation ftr // fujitsu : 2015-07-30 Fujitsu Limited fujitsu // fujixerox : 2015-07-23 Xerox DNHC LLC fujixerox // fun : 2016-01-14 fun // fund : 2014-03-20 John Castle, LLC fund // furniture : 2014-03-20 Lone Fields, LLC furniture // futbol : 2013-09-20 futbol // fyi : 2015-04-02 Silver Tigers, LLC fyi // gal : 2013-11-07 Asociación puntoGAL gal // gallery : 2013-09-13 Sugar House, LLC gallery // gallo : 2015-06-11 Gallo Vineyards, Inc. gallo // gallup : 2015-02-19 Gallup, Inc. gallup // game : 2015-05-28 Uniregistry, Corp. game // games : 2015-05-28 games // gap : 2015-07-31 The Gap, Inc. gap // garden : 2014-06-26 Top Level Domain Holdings Limited garden // gbiz : 2014-07-17 Charleston Road Registry Inc. gbiz // gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" gdn // gea : 2014-12-04 GEA Group Aktiengesellschaft gea // gent : 2014-01-23 COMBELL GROUP NV/SA gent // genting : 2015-03-12 Resorts World Inc Pte. Ltd. genting // george : 2015-07-31 Wal-Mart Stores, Inc. george // ggee : 2014-01-09 GMO Internet, Inc. ggee // gift : 2013-10-17 Uniregistry, Corp. gift // gifts : 2014-07-03 Goose Sky, LLC gifts // gives : 2014-03-06 United TLD Holdco Ltd. gives // giving : 2014-11-13 Giving Limited giving // glade : 2015-07-23 Johnson Shareholdings, Inc. glade // glass : 2013-11-07 Black Cover, LLC glass // gle : 2014-07-24 Charleston Road Registry Inc. gle // global : 2014-04-17 Dot GLOBAL AS global // globo : 2013-12-19 Globo Comunicação e Participações S.A globo // gmail : 2014-05-01 Charleston Road Registry Inc. gmail // gmbh : 2016-01-29 Extra Dynamite, LLC gmbh // gmo : 2014-01-09 GMO Internet, Inc. gmo // gmx : 2014-04-24 1&1 Mail & Media GmbH gmx // godaddy : 2015-07-23 Go Daddy East, LLC godaddy // gold : 2015-01-22 June Edge, LLC gold // goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. goldpoint // golf : 2014-12-18 Lone falls, LLC golf // goo : 2014-12-18 NTT Resonant Inc. goo // goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company goodhands // goodyear : 2015-07-02 The Goodyear Tire & Rubber Company goodyear // goog : 2014-11-20 Charleston Road Registry Inc. goog // google : 2014-07-24 Charleston Road Registry Inc. google // gop : 2014-01-16 Republican State Leadership Committee, Inc. gop // got : 2014-12-18 Amazon EU S.à r.l. got // grainger : 2015-05-07 Grainger Registry Services, LLC grainger // graphics : 2013-09-13 Over Madison, LLC graphics // gratis : 2014-03-20 Pioneer Tigers, LLC gratis // green : 2014-05-08 Afilias Limited green // gripe : 2014-03-06 Corn Sunset, LLC gripe // grocery : 2016-06-16 Wal-Mart Stores, Inc. grocery // group : 2014-08-15 Romeo Town, LLC group // guardian : 2015-07-30 The Guardian Life Insurance Company of America guardian // gucci : 2014-11-13 Guccio Gucci S.p.a. gucci // guge : 2014-08-28 Charleston Road Registry Inc. guge // guide : 2013-09-13 Snow Moon, LLC guide // guitars : 2013-11-14 Uniregistry, Corp. guitars // guru : 2013-08-27 Pioneer Cypress, LLC guru // hair : 2015-12-03 L'Oréal hair // hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH hamburg // hangout : 2014-11-13 Charleston Road Registry Inc. hangout // haus : 2013-12-05 haus // hbo : 2015-07-30 HBO Registry Services, Inc. hbo // hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED hdfc // hdfcbank : 2015-02-12 HDFC Bank Limited hdfcbank // health : 2015-02-11 DotHealth, LLC health // healthcare : 2014-06-12 Silver Glen, LLC healthcare // help : 2014-06-26 Uniregistry, Corp. help // helsinki : 2015-02-05 City of Helsinki helsinki // here : 2014-02-06 Charleston Road Registry Inc. here // hermes : 2014-07-10 HERMES INTERNATIONAL hermes // hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. hgtv // hiphop : 2014-03-06 Uniregistry, Corp. hiphop // hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. hisamitsu // hitachi : 2014-10-31 Hitachi, Ltd. hitachi // hiv : 2014-03-13 hiv // hkt : 2015-05-14 PCCW-HKT DataCom Services Limited hkt // hockey : 2015-03-19 Half Willow, LLC hockey // holdings : 2013-08-27 John Madison, LLC holdings // holiday : 2013-11-07 Goose Woods, LLC holiday // homedepot : 2015-04-02 Homer TLC, Inc. homedepot // homegoods : 2015-07-16 The TJX Companies, Inc. homegoods // homes : 2014-01-09 DERHomes, LLC homes // homesense : 2015-07-16 The TJX Companies, Inc. homesense // honda : 2014-12-18 Honda Motor Co., Ltd. honda // honeywell : 2015-07-23 Honeywell GTLD LLC honeywell // horse : 2013-11-21 Top Level Domain Holdings Limited horse // hospital : 2016-10-20 Ruby Pike, LLC hospital // host : 2014-04-17 DotHost Inc. host // hosting : 2014-05-29 Uniregistry, Corp. hosting // hot : 2015-08-27 Amazon EU S.à r.l. hot // hoteles : 2015-03-05 Travel Reservations SRL hoteles // hotels : 2016-04-07 Booking.com B.V. hotels // hotmail : 2014-12-18 Microsoft Corporation hotmail // house : 2013-11-07 Sugar Park, LLC house // how : 2014-01-23 Charleston Road Registry Inc. how // hsbc : 2014-10-24 HSBC Holdings PLC hsbc // htc : 2015-04-02 HTC corporation htc // hughes : 2015-07-30 Hughes Satellite Systems Corporation hughes // hyatt : 2015-07-30 Hyatt GTLD, L.L.C. hyatt // hyundai : 2015-07-09 Hyundai Motor Company hyundai // ibm : 2014-07-31 International Business Machines Corporation ibm // icbc : 2015-02-19 Industrial and Commercial Bank of China Limited icbc // ice : 2014-10-30 IntercontinentalExchange, Inc. ice // icu : 2015-01-08 One.com A/S icu // ieee : 2015-07-23 IEEE Global LLC ieee // ifm : 2014-01-30 ifm electronic gmbh ifm // ikano : 2015-07-09 Ikano S.A. ikano // imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) imamat // imdb : 2015-06-25 Amazon EU S.à r.l. imdb // immo : 2014-07-10 Auburn Bloom, LLC immo // immobilien : 2013-11-07 United TLD Holdco Ltd. immobilien // industries : 2013-12-05 Outer House, LLC industries // infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. infiniti // ing : 2014-01-23 Charleston Road Registry Inc. ing // ink : 2013-12-05 Top Level Design, LLC ink // institute : 2013-11-07 Outer Maple, LLC institute // insurance : 2015-02-19 fTLD Registry Services LLC insurance // insure : 2014-03-20 Pioneer Willow, LLC insure // intel : 2015-08-06 Intel Corporation intel // international : 2013-11-07 Wild Way, LLC international // intuit : 2015-07-30 Intuit Administrative Services, Inc. intuit // investments : 2014-03-20 Holly Glen, LLC investments // ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. ipiranga // irish : 2014-08-07 Dot-Irish LLC irish // iselect : 2015-02-11 iSelect Ltd iselect // ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) ismaili // ist : 2014-08-28 Istanbul Metropolitan Municipality ist // istanbul : 2014-08-28 Istanbul Metropolitan Municipality istanbul // itau : 2014-10-02 Itau Unibanco Holding S.A. itau // itv : 2015-07-09 ITV Services Limited itv // iveco : 2015-09-03 CNH Industrial N.V. iveco // iwc : 2014-06-23 Richemont DNS Inc. iwc // jaguar : 2014-11-13 Jaguar Land Rover Ltd jaguar // java : 2014-06-19 Oracle Corporation java // jcb : 2014-11-20 JCB Co., Ltd. jcb // jcp : 2015-04-23 JCP Media, Inc. jcp // jeep : 2015-07-30 FCA US LLC. jeep // jetzt : 2014-01-09 jetzt // jewelry : 2015-03-05 Wild Bloom, LLC jewelry // jio : 2015-04-02 Affinity Names, Inc. jio // jlc : 2014-12-04 Richemont DNS Inc. jlc // jll : 2015-04-02 Jones Lang LaSalle Incorporated jll // jmp : 2015-03-26 Matrix IP LLC jmp // jnj : 2015-06-18 Johnson & Johnson Services, Inc. jnj // joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry joburg // jot : 2014-12-18 Amazon EU S.à r.l. jot // joy : 2014-12-18 Amazon EU S.à r.l. joy // jpmorgan : 2015-04-30 JPMorgan Chase & Co. jpmorgan // jprs : 2014-09-18 Japan Registry Services Co., Ltd. jprs // juegos : 2014-03-20 Uniregistry, Corp. juegos // juniper : 2015-07-30 JUNIPER NETWORKS, INC. juniper // kaufen : 2013-11-07 United TLD Holdco Ltd. kaufen // kddi : 2014-09-12 KDDI CORPORATION kddi // kerryhotels : 2015-04-30 Kerry Trading Co. Limited kerryhotels // kerrylogistics : 2015-04-09 Kerry Trading Co. Limited kerrylogistics // kerryproperties : 2015-04-09 Kerry Trading Co. Limited kerryproperties // kfh : 2014-12-04 Kuwait Finance House kfh // kia : 2015-07-09 KIA MOTORS CORPORATION kia // kim : 2013-09-23 Afilias Limited kim // kinder : 2014-11-07 Ferrero Trading Lux S.A. kinder // kindle : 2015-06-25 Amazon EU S.à r.l. kindle // kitchen : 2013-09-20 Just Goodbye, LLC kitchen // kiwi : 2013-09-20 DOT KIWI LIMITED kiwi // koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH koeln // komatsu : 2015-01-08 Komatsu Ltd. komatsu // kosher : 2015-08-20 Kosher Marketing Assets LLC kosher // kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) kpmg // kpn : 2015-01-08 Koninklijke KPN N.V. kpn // krd : 2013-12-05 KRG Department of Information Technology krd // kred : 2013-12-19 KredTLD Pty Ltd kred // kuokgroup : 2015-04-09 Kerry Trading Co. Limited kuokgroup // kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen kyoto // lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA lacaixa // ladbrokes : 2015-08-06 LADBROKES INTERNATIONAL PLC ladbrokes // lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. lamborghini // lamer : 2015-10-01 The Estée Lauder Companies Inc. lamer // lancaster : 2015-02-12 LANCASTER lancaster // lancia : 2015-07-31 Fiat Chrysler Automobiles N.V. lancia // lancome : 2015-07-23 L'Oréal lancome // land : 2013-09-10 Pine Moon, LLC land // landrover : 2014-11-13 Jaguar Land Rover Ltd landrover // lanxess : 2015-07-30 LANXESS Corporation lanxess // lasalle : 2015-04-02 Jones Lang LaSalle Incorporated lasalle // lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico lat // latino : 2015-07-30 Dish DBS Corporation latino // latrobe : 2014-06-16 La Trobe University latrobe // law : 2015-01-22 Minds + Machines Group Limited law // lawyer : 2014-03-20 lawyer // lds : 2014-03-20 IRI Domain Management, LLC ("Applicant") lds // lease : 2014-03-06 Victor Trail, LLC lease // leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc leclerc // lefrak : 2015-07-16 LeFrak Organization, Inc. lefrak // legal : 2014-10-16 Blue Falls, LLC legal // lego : 2015-07-16 LEGO Juris A/S lego // lexus : 2015-04-23 TOYOTA MOTOR CORPORATION lexus // lgbt : 2014-05-08 Afilias Limited lgbt // liaison : 2014-10-02 Liaison Technologies, Incorporated liaison // lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG lidl // life : 2014-02-06 Trixy Oaks, LLC life // lifeinsurance : 2015-01-15 American Council of Life Insurers lifeinsurance // lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. lifestyle // lighting : 2013-08-27 John McCook, LLC lighting // like : 2014-12-18 Amazon EU S.à r.l. like // lilly : 2015-07-31 Eli Lilly and Company lilly // limited : 2014-03-06 Big Fest, LLC limited // limo : 2013-10-17 Hidden Frostbite, LLC limo // lincoln : 2014-11-13 Ford Motor Company lincoln // linde : 2014-12-04 Linde Aktiengesellschaft linde // link : 2013-11-14 Uniregistry, Corp. link // lipsy : 2015-06-25 Lipsy Ltd lipsy // live : 2014-12-04 live // living : 2015-07-30 Lifestyle Domain Holdings, Inc. living // lixil : 2015-03-19 LIXIL Group Corporation lixil // loan : 2014-11-20 dot Loan Limited loan // loans : 2014-03-20 June Woods, LLC loans // locker : 2015-06-04 Dish DBS Corporation locker // locus : 2015-06-25 Locus Analytics LLC locus // loft : 2015-07-30 Annco, Inc. loft // lol : 2015-01-30 Uniregistry, Corp. lol // london : 2013-11-14 Dot London Domains Limited london // lotte : 2014-11-07 Lotte Holdings Co., Ltd. lotte // lotto : 2014-04-10 Afilias Limited lotto // love : 2014-12-22 Merchant Law Group LLP love // lpl : 2015-07-30 LPL Holdings, Inc. lpl // lplfinancial : 2015-07-30 LPL Holdings, Inc. lplfinancial // ltd : 2014-09-25 Over Corner, LLC ltd // ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA ltda // lundbeck : 2015-08-06 H. Lundbeck A/S lundbeck // lupin : 2014-11-07 LUPIN LIMITED lupin // luxe : 2014-01-09 Top Level Domain Holdings Limited luxe // luxury : 2013-10-17 Luxury Partners, LLC luxury // macys : 2015-07-31 Macys, Inc. macys // madrid : 2014-05-01 Comunidad de Madrid madrid // maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) maif // maison : 2013-12-05 Victor Frostbite, LLC maison // makeup : 2015-01-15 L'Oréal makeup // man : 2014-12-04 MAN SE man // management : 2013-11-07 John Goodbye, LLC management // mango : 2013-10-24 PUNTO FA S.L. mango // map : 2016-06-09 Charleston Road Registry Inc. map // market : 2014-03-06 market // marketing : 2013-11-07 Fern Pass, LLC marketing // markets : 2014-12-11 IG Group Holdings PLC markets // marriott : 2014-10-09 Marriott Worldwide Corporation marriott // marshalls : 2015-07-16 The TJX Companies, Inc. marshalls // maserati : 2015-07-31 Fiat Chrysler Automobiles N.V. maserati // mattel : 2015-08-06 Mattel Sites, Inc. mattel // mba : 2015-04-02 Lone Hollow, LLC mba // mcd : 2015-07-30 McDonald’s Corporation mcd // mcdonalds : 2015-07-30 McDonald’s Corporation mcdonalds // mckinsey : 2015-07-31 McKinsey Holdings, Inc. mckinsey // med : 2015-08-06 Medistry LLC med // media : 2014-03-06 Grand Glen, LLC media // meet : 2014-01-16 meet // melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation melbourne // meme : 2014-01-30 Charleston Road Registry Inc. meme // memorial : 2014-10-16 Dog Beach, LLC memorial // men : 2015-02-26 Exclusive Registry Limited men // menu : 2013-09-11 Wedding TLD2, LLC menu // meo : 2014-11-07 PT Comunicacoes S.A. meo // merckmsd : 2016-07-14 MSD Registry Holdings, Inc. merckmsd // metlife : 2015-05-07 MetLife Services and Solutions, LLC metlife // miami : 2013-12-19 Top Level Domain Holdings Limited miami // microsoft : 2014-12-18 Microsoft Corporation microsoft // mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft mini // mint : 2015-07-30 Intuit Administrative Services, Inc. mint // mit : 2015-07-02 Massachusetts Institute of Technology mit // mitsubishi : 2015-07-23 Mitsubishi Corporation mitsubishi // mlb : 2015-05-21 MLB Advanced Media DH, LLC mlb // mls : 2015-04-23 The Canadian Real Estate Association mls // mma : 2014-11-07 MMA IARD mma // mobile : 2016-06-02 Dish DBS Corporation mobile // mobily : 2014-12-18 GreenTech Consultancy Company W.L.L. mobily // moda : 2013-11-07 United TLD Holdco Ltd. moda // moe : 2013-11-13 Interlink Co., Ltd. moe // moi : 2014-12-18 Amazon EU S.à r.l. moi // mom : 2015-04-16 Uniregistry, Corp. mom // monash : 2013-09-30 Monash University monash // money : 2014-10-16 Outer McCook, LLC money // monster : 2015-09-11 Monster Worldwide, Inc. monster // montblanc : 2014-06-23 Richemont DNS Inc. montblanc // mopar : 2015-07-30 FCA US LLC. mopar // mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant") mormon // mortgage : 2014-03-20 mortgage // moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) moscow // moto : 2015-06-04 moto // motorcycles : 2014-01-09 DERMotorcycles, LLC motorcycles // mov : 2014-01-30 Charleston Road Registry Inc. mov // movie : 2015-02-05 New Frostbite, LLC movie // movistar : 2014-10-16 Telefónica S.A. movistar // msd : 2015-07-23 MSD Registry Holdings, Inc. msd // mtn : 2014-12-04 MTN Dubai Limited mtn // mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation mtpc // mtr : 2015-03-12 MTR Corporation Limited mtr // mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC mutual // nab : 2015-08-20 National Australia Bank Limited nab // nadex : 2014-12-11 IG Group Holdings PLC nadex // nagoya : 2013-10-24 GMO Registry, Inc. nagoya // nationwide : 2015-07-23 Nationwide Mutual Insurance Company nationwide // natura : 2015-03-12 NATURA COSMÉTICOS S.A. natura // navy : 2014-03-06 United TLD Holdco Ltd. navy // nba : 2015-07-31 NBA REGISTRY, LLC nba // nec : 2015-01-08 NEC Corporation nec // netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA netbank // netflix : 2015-06-18 Netflix, Inc. netflix // network : 2013-11-14 Trixy Manor, LLC network // neustar : 2013-12-05 NeuStar, Inc. neustar // new : 2014-01-30 Charleston Road Registry Inc. new // newholland : 2015-09-03 CNH Industrial N.V. newholland // news : 2014-12-18 news // next : 2015-06-18 Next plc next // nextdirect : 2015-06-18 Next plc nextdirect // nexus : 2014-07-24 Charleston Road Registry Inc. nexus // nfl : 2015-07-23 NFL Reg Ops LLC nfl // ngo : 2014-03-06 Public Interest Registry ngo // nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) nhk // nico : 2014-12-04 DWANGO Co., Ltd. nico // nike : 2015-07-23 NIKE, Inc. nike // nikon : 2015-05-21 NIKON CORPORATION nikon // ninja : 2013-11-07 United TLD Holdco Ltd. ninja // nissan : 2014-03-27 NISSAN MOTOR CO., LTD. nissan // nissay : 2015-10-29 Nippon Life Insurance Company nissay // nokia : 2015-01-08 Nokia Corporation nokia // northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC northwesternmutual // norton : 2014-12-04 Symantec Corporation norton // now : 2015-06-25 Amazon EU S.à r.l. now // nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. nowruz // nowtv : 2015-05-14 Starbucks (HK) Limited nowtv // nra : 2014-05-22 NRA Holdings Company, INC. nra // nrw : 2013-11-21 Minds + Machines GmbH nrw // ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION ntt // nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications nyc // obi : 2014-09-25 OBI Group Holding SE & Co. KGaA obi // observer : 2015-04-30 observer // off : 2015-07-23 Johnson Shareholdings, Inc. off // office : 2015-03-12 Microsoft Corporation office // okinawa : 2013-12-05 BusinessRalliart Inc. okinawa // olayan : 2015-05-14 Crescent Holding GmbH olayan // olayangroup : 2015-05-14 Crescent Holding GmbH olayangroup // oldnavy : 2015-07-31 The Gap, Inc. oldnavy // ollo : 2015-06-04 Dish DBS Corporation ollo // omega : 2015-01-08 The Swatch Group Ltd omega // one : 2014-11-07 One.com A/S one // ong : 2014-03-06 Public Interest Registry ong // onl : 2013-09-16 I-Registry Ltd. onl // online : 2015-01-15 DotOnline Inc. online // onyourside : 2015-07-23 Nationwide Mutual Insurance Company onyourside // ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED ooo // open : 2015-07-31 American Express Travel Related Services Company, Inc. open // oracle : 2014-06-19 Oracle Corporation oracle // orange : 2015-03-12 Orange Brand Services Limited orange // organic : 2014-03-27 Afilias Limited organic // orientexpress : 2015-02-05 orientexpress // origins : 2015-10-01 The Estée Lauder Companies Inc. origins // osaka : 2014-09-04 Interlink Co., Ltd. osaka // otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. otsuka // ott : 2015-06-04 Dish DBS Corporation ott // ovh : 2014-01-16 OVH SAS ovh // page : 2014-12-04 Charleston Road Registry Inc. page // pamperedchef : 2015-02-05 The Pampered Chef, Ltd. pamperedchef // panasonic : 2015-07-30 Panasonic Corporation panasonic // panerai : 2014-11-07 Richemont DNS Inc. panerai // paris : 2014-01-30 City of Paris paris // pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. pars // partners : 2013-12-05 Magic Glen, LLC partners // parts : 2013-12-05 Sea Goodbye, LLC parts // party : 2014-09-11 Blue Sky Registry Limited party // passagens : 2015-03-05 Travel Reservations SRL passagens // pay : 2015-08-27 Amazon EU S.à r.l. pay // pccw : 2015-05-14 PCCW Enterprises Limited pccw // pet : 2015-05-07 Afilias plc pet // pfizer : 2015-09-11 Pfizer Inc. pfizer // pharmacy : 2014-06-19 National Association of Boards of Pharmacy pharmacy // phd : 2016-07-28 Charleston Road Registry Inc. phd // philips : 2014-11-07 Koninklijke Philips N.V. philips // phone : 2016-06-02 Dish DBS Corporation phone // photo : 2013-11-14 Uniregistry, Corp. photo // photography : 2013-09-20 Sugar Glen, LLC photography // photos : 2013-10-17 Sea Corner, LLC photos // physio : 2014-05-01 PhysBiz Pty Ltd physio // piaget : 2014-10-16 Richemont DNS Inc. piaget // pics : 2013-11-14 Uniregistry, Corp. pics // pictet : 2014-06-26 Pictet Europe S.A. pictet // pictures : 2014-03-06 Foggy Sky, LLC pictures // pid : 2015-01-08 Top Level Spectrum, Inc. pid // pin : 2014-12-18 Amazon EU S.à r.l. pin // ping : 2015-06-11 Ping Registry Provider, Inc. ping // pink : 2013-10-01 Afilias Limited pink // pioneer : 2015-07-16 Pioneer Corporation pioneer // pizza : 2014-06-26 Foggy Moon, LLC pizza // place : 2014-04-24 Snow Galley, LLC place // play : 2015-03-05 Charleston Road Registry Inc. play // playstation : 2015-07-02 Sony Computer Entertainment Inc. playstation // plumbing : 2013-09-10 Spring Tigers, LLC plumbing // plus : 2015-02-05 Sugar Mill, LLC plus // pnc : 2015-07-02 PNC Domain Co., LLC pnc // pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG pohl // poker : 2014-07-03 Afilias Domains No. 5 Limited poker // politie : 2015-08-20 Politie Nederland politie // porn : 2014-10-16 ICM Registry PN LLC porn // pramerica : 2015-07-30 Prudential Financial, Inc. pramerica // praxi : 2013-12-05 Praxi S.p.A. praxi // press : 2014-04-03 DotPress Inc. press // prime : 2015-06-25 Amazon EU S.à r.l. prime // prod : 2014-01-23 Charleston Road Registry Inc. prod // productions : 2013-12-05 Magic Birch, LLC productions // prof : 2014-07-24 Charleston Road Registry Inc. prof // progressive : 2015-07-23 Progressive Casualty Insurance Company progressive // promo : 2014-12-18 promo // properties : 2013-12-05 Big Pass, LLC properties // property : 2014-05-22 Uniregistry, Corp. property // protection : 2015-04-23 protection // pru : 2015-07-30 Prudential Financial, Inc. pru // prudential : 2015-07-30 Prudential Financial, Inc. prudential // pub : 2013-12-12 United TLD Holdco Ltd. pub // pwc : 2015-10-29 PricewaterhouseCoopers LLP pwc // qpon : 2013-11-14 dotCOOL, Inc. qpon // quebec : 2013-12-19 PointQuébec Inc quebec // quest : 2015-03-26 Quest ION Limited quest // qvc : 2015-07-30 QVC, Inc. qvc // racing : 2014-12-04 Premier Registry Limited racing // radio : 2016-07-21 European Broadcasting Union (EBU) radio // raid : 2015-07-23 Johnson Shareholdings, Inc. raid // read : 2014-12-18 Amazon EU S.à r.l. read // realestate : 2015-09-11 dotRealEstate LLC realestate // realtor : 2014-05-29 Real Estate Domains LLC realtor // realty : 2015-03-19 Fegistry, LLC realty // recipes : 2013-10-17 Grand Island, LLC recipes // red : 2013-11-07 Afilias Limited red // redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. redstone // redumbrella : 2015-03-26 Travelers TLD, LLC redumbrella // rehab : 2014-03-06 United TLD Holdco Ltd. rehab // reise : 2014-03-13 reise // reisen : 2014-03-06 New Cypress, LLC reisen // reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. reit // reliance : 2015-04-02 Reliance Industries Limited reliance // ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd. ren // rent : 2014-12-04 DERRent, LLC rent // rentals : 2013-12-05 Big Hollow,LLC rentals // repair : 2013-11-07 Lone Sunset, LLC repair // report : 2013-12-05 Binky Glen, LLC report // republican : 2014-03-20 United TLD Holdco Ltd. republican // rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable rest // restaurant : 2014-07-03 Snow Avenue, LLC restaurant // review : 2014-11-20 dot Review Limited review // reviews : 2013-09-13 reviews // rexroth : 2015-06-18 Robert Bosch GMBH rexroth // rich : 2013-11-21 I-Registry Ltd. rich // richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited richardli // ricoh : 2014-11-20 Ricoh Company, Ltd. ricoh // rightathome : 2015-07-23 Johnson Shareholdings, Inc. rightathome // ril : 2015-04-02 Reliance Industries Limited ril // rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO rio // rip : 2014-07-10 United TLD Holdco Ltd. rip // rmit : 2015-11-19 Royal Melbourne Institute of Technology rmit // rocher : 2014-12-18 Ferrero Trading Lux S.A. rocher // rocks : 2013-11-14 rocks // rodeo : 2013-12-19 Top Level Domain Holdings Limited rodeo // rogers : 2015-08-06 Rogers Communications Partnership rogers // room : 2014-12-18 Amazon EU S.à r.l. room // rsvp : 2014-05-08 Charleston Road Registry Inc. rsvp // rugby : 2016-12-15 World Rugby Strategic Developments Limited rugby // ruhr : 2013-10-02 regiodot GmbH & Co. KG ruhr // run : 2015-03-19 Snow Park, LLC run // rwe : 2015-04-02 RWE AG rwe // ryukyu : 2014-01-09 BusinessRalliart Inc. ryukyu // saarland : 2013-12-12 dotSaarland GmbH saarland // safe : 2014-12-18 Amazon EU S.à r.l. safe // safety : 2015-01-08 Safety Registry Services, LLC. safety // sakura : 2014-12-18 SAKURA Internet Inc. sakura // sale : 2014-10-16 sale // salon : 2014-12-11 Outer Orchard, LLC salon // samsclub : 2015-07-31 Wal-Mart Stores, Inc. samsclub // samsung : 2014-04-03 SAMSUNG SDS CO., LTD samsung // sandvik : 2014-11-13 Sandvik AB sandvik // sandvikcoromant : 2014-11-07 Sandvik AB sandvikcoromant // sanofi : 2014-10-09 Sanofi sanofi // sap : 2014-03-27 SAP AG sap // sapo : 2014-11-07 PT Comunicacoes S.A. sapo // sarl : 2014-07-03 Delta Orchard, LLC sarl // sas : 2015-04-02 Research IP LLC sas // save : 2015-06-25 Amazon EU S.à r.l. save // saxo : 2014-10-31 Saxo Bank A/S saxo // sbi : 2015-03-12 STATE BANK OF INDIA sbi // sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION sbs // sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) sca // scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") scb // schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG schaeffler // schmidt : 2014-04-03 SALM S.A.S. schmidt // scholarships : 2014-04-24 Scholarships.com, LLC scholarships // school : 2014-12-18 Little Galley, LLC school // schule : 2014-03-06 Outer Moon, LLC schule // schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG schwarz // science : 2014-09-11 dot Science Limited science // scjohnson : 2015-07-23 Johnson Shareholdings, Inc. scjohnson // scor : 2014-10-31 SCOR SE scor // scot : 2014-01-23 Dot Scot Registry Limited scot // search : 2016-06-09 Charleston Road Registry Inc. search // seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) seat // secure : 2015-08-27 Amazon EU S.à r.l. secure // security : 2015-05-14 security // seek : 2014-12-04 Seek Limited seek // select : 2015-10-08 iSelect Ltd select // sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. sener // services : 2014-02-27 Fox Castle, LLC services // ses : 2015-07-23 SES ses // seven : 2015-08-06 Seven West Media Ltd seven // sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG sew // sex : 2014-11-13 ICM Registry SX LLC sex // sexy : 2013-09-11 Uniregistry, Corp. sexy // sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR sfr // shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited shangrila // sharp : 2014-05-01 Sharp Corporation sharp // shaw : 2015-04-23 Shaw Cablesystems G.P. shaw // shell : 2015-07-30 Shell Information Technology International Inc shell // shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. shia // shiksha : 2013-11-14 Afilias Limited shiksha // shoes : 2013-10-02 Binky Galley, LLC shoes // shop : 2016-04-08 GMO Registry, Inc. shop // shopping : 2016-03-31 shopping // shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. shouji // show : 2015-03-05 Snow Beach, LLC show // showtime : 2015-08-06 CBS Domains Inc. showtime // shriram : 2014-01-23 Shriram Capital Ltd. shriram // silk : 2015-06-25 Amazon EU S.à r.l. silk // sina : 2015-03-12 Sina Corporation sina // singles : 2013-08-27 Fern Madison, LLC singles // site : 2015-01-15 DotSite Inc. site // ski : 2015-04-09 STARTING DOT LIMITED ski // skin : 2015-01-15 L'Oréal skin // sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch sky // skype : 2014-12-18 Microsoft Corporation skype // sling : 2015-07-30 Hughes Satellite Systems Corporation sling // smart : 2015-07-09 Smart Communications, Inc. (SMART) smart // smile : 2014-12-18 Amazon EU S.à r.l. smile // sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F sncf // soccer : 2015-03-26 Foggy Shadow, LLC soccer // social : 2013-11-07 United TLD Holdco Ltd. social // softbank : 2015-07-02 SoftBank Corp. softbank // software : 2014-03-20 software // sohu : 2013-12-19 Sohu.com Limited sohu // solar : 2013-11-07 Ruby Town, LLC solar // solutions : 2013-11-07 Silver Cover, LLC solutions // song : 2015-02-26 Amazon EU S.à r.l. song // sony : 2015-01-08 Sony Corporation sony // soy : 2014-01-23 Charleston Road Registry Inc. soy // space : 2014-04-03 DotSpace Inc. space // spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG spiegel // spot : 2015-02-26 Amazon EU S.à r.l. spot // spreadbetting : 2014-12-11 IG Group Holdings PLC spreadbetting // srl : 2015-05-07 mySRL GmbH srl // srt : 2015-07-30 FCA US LLC. srt // stada : 2014-11-13 STADA Arzneimittel AG stada // staples : 2015-07-30 Staples, Inc. staples // star : 2015-01-08 Star India Private Limited star // starhub : 2015-02-05 StarHub Ltd starhub // statebank : 2015-03-12 STATE BANK OF INDIA statebank // statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company statefarm // statoil : 2014-12-04 Statoil ASA statoil // stc : 2014-10-09 Saudi Telecom Company stc // stcgroup : 2014-10-09 Saudi Telecom Company stcgroup // stockholm : 2014-12-18 Stockholms kommun stockholm // storage : 2014-12-22 Self Storage Company LLC storage // store : 2015-04-09 DotStore Inc. store // stream : 2016-01-08 dot Stream Limited stream // studio : 2015-02-11 studio // study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD study // style : 2014-12-04 Binky Moon, LLC style // sucks : 2014-12-22 Vox Populi Registry Inc. sucks // supplies : 2013-12-19 Atomic Fields, LLC supplies // supply : 2013-12-19 Half Falls, LLC supply // support : 2013-10-24 Grand Orchard, LLC support // surf : 2014-01-09 Top Level Domain Holdings Limited surf // surgery : 2014-03-20 Tin Avenue, LLC surgery // suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION suzuki // swatch : 2015-01-08 The Swatch Group Ltd swatch // swiftcover : 2015-07-23 Swiftcover Insurance Services Limited swiftcover // swiss : 2014-10-16 Swiss Confederation swiss // sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet sydney // symantec : 2014-12-04 Symantec Corporation symantec // systems : 2013-11-07 Dash Cypress, LLC systems // tab : 2014-12-04 Tabcorp Holdings Limited tab // taipei : 2014-07-10 Taipei City Government taipei // talk : 2015-04-09 Amazon EU S.à r.l. talk // taobao : 2015-01-15 Alibaba Group Holding Limited taobao // target : 2015-07-31 Target Domain Holdings, LLC target // tatamotors : 2015-03-12 Tata Motors Ltd tatamotors // tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" tatar // tattoo : 2013-08-30 Uniregistry, Corp. tattoo // tax : 2014-03-20 Storm Orchard, LLC tax // taxi : 2015-03-19 Pine Falls, LLC taxi // tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. tci // tdk : 2015-06-11 TDK Corporation tdk // team : 2015-03-05 Atomic Lake, LLC team // tech : 2015-01-30 Dot Tech LLC tech // technology : 2013-09-13 Auburn Falls technology // telecity : 2015-02-19 TelecityGroup International Limited telecity // telefonica : 2014-10-16 Telefónica S.A. telefonica // temasek : 2014-08-07 Temasek Holdings (Private) Limited temasek // tennis : 2014-12-04 Cotton Bloom, LLC tennis // teva : 2015-07-02 Teva Pharmaceutical Industries Limited teva // thd : 2015-04-02 Homer TLC, Inc. thd // theater : 2015-03-19 Blue Tigers, LLC theater // theatre : 2015-05-07 theatre // tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America tiaa // tickets : 2015-02-05 Accent Media Limited tickets // tienda : 2013-11-14 Victor Manor, LLC tienda // tiffany : 2015-01-30 Tiffany and Company tiffany // tips : 2013-09-20 Corn Willow, LLC tips // tires : 2014-11-07 Dog Edge, LLC tires // tirol : 2014-04-24 punkt Tirol GmbH tirol // tjmaxx : 2015-07-16 The TJX Companies, Inc. tjmaxx // tjx : 2015-07-16 The TJX Companies, Inc. tjx // tkmaxx : 2015-07-16 The TJX Companies, Inc. tkmaxx // tmall : 2015-01-15 Alibaba Group Holding Limited tmall // today : 2013-09-20 Pearl Woods, LLC today // tokyo : 2013-11-13 GMO Registry, Inc. tokyo // tools : 2013-11-21 Pioneer North, LLC tools // top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd. top // toray : 2014-12-18 Toray Industries, Inc. toray // toshiba : 2014-04-10 TOSHIBA Corporation toshiba // total : 2015-08-06 Total SA total // tours : 2015-01-22 Sugar Station, LLC tours // town : 2014-03-06 Koko Moon, LLC town // toyota : 2015-04-23 TOYOTA MOTOR CORPORATION toyota // toys : 2014-03-06 Pioneer Orchard, LLC toys // trade : 2014-01-23 Elite Registry Limited trade // trading : 2014-12-11 IG Group Holdings PLC trading // training : 2013-11-07 Wild Willow, LLC training // travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. travelchannel // travelers : 2015-03-26 Travelers TLD, LLC travelers // travelersinsurance : 2015-03-26 Travelers TLD, LLC travelersinsurance // trust : 2014-10-16 trust // trv : 2015-03-26 Travelers TLD, LLC trv // tube : 2015-06-11 Latin American Telecom LLC tube // tui : 2014-07-03 TUI AG tui // tunes : 2015-02-26 Amazon EU S.à r.l. tunes // tushu : 2014-12-18 Amazon EU S.à r.l. tushu // tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED tvs // ubank : 2015-08-20 National Australia Bank Limited ubank // ubs : 2014-12-11 UBS AG ubs // uconnect : 2015-07-30 FCA US LLC. uconnect // unicom : 2015-10-15 China United Network Communications Corporation Limited unicom // university : 2014-03-06 Little Station, LLC university // uno : 2013-09-11 Dot Latin LLC uno // uol : 2014-05-01 UBN INTERNET LTDA. uol // ups : 2015-06-25 UPS Market Driver, Inc. ups // vacations : 2013-12-05 Atomic Tigers, LLC vacations // vana : 2014-12-11 Lifestyle Domain Holdings, Inc. vana // vanguard : 2015-09-03 The Vanguard Group, Inc. vanguard // vegas : 2014-01-16 Dot Vegas, Inc. vegas // ventures : 2013-08-27 Binky Lake, LLC ventures // verisign : 2015-08-13 VeriSign, Inc. verisign // versicherung : 2014-03-20 versicherung // vet : 2014-03-06 vet // viajes : 2013-10-17 Black Madison, LLC viajes // video : 2014-10-16 video // vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe vig // viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. viking // villas : 2013-12-05 New Sky, LLC villas // vin : 2015-06-18 Holly Shadow, LLC vin // vip : 2015-01-22 Minds + Machines Group Limited vip // virgin : 2014-09-25 Virgin Enterprises Limited virgin // visa : 2015-07-30 Visa Worldwide Pte. Limited visa // vision : 2013-12-05 Koko Station, LLC vision // vista : 2014-09-18 Vistaprint Limited vista // vistaprint : 2014-09-18 Vistaprint Limited vistaprint // viva : 2014-11-07 Saudi Telecom Company viva // vivo : 2015-07-31 Telefonica Brasil S.A. vivo // vlaanderen : 2014-02-06 DNS.be vzw vlaanderen // vodka : 2013-12-19 Top Level Domain Holdings Limited vodka // volkswagen : 2015-05-14 Volkswagen Group of America Inc. volkswagen // volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag volvo // vote : 2013-11-21 Monolith Registry LLC vote // voting : 2013-11-13 Valuetainment Corp. voting // voto : 2013-11-21 Monolith Registry LLC voto // voyage : 2013-08-27 Ruby House, LLC voyage // vuelos : 2015-03-05 Travel Reservations SRL vuelos // wales : 2014-05-08 Nominet UK wales // walmart : 2015-07-31 Wal-Mart Stores, Inc. walmart // walter : 2014-11-13 Sandvik AB walter // wang : 2013-10-24 Zodiac Leo Limited wang // wanggou : 2014-12-18 Amazon EU S.à r.l. wanggou // warman : 2015-06-18 Weir Group IP Limited warman // watch : 2013-11-14 Sand Shadow, LLC watch // watches : 2014-12-22 Richemont DNS Inc. watches // weather : 2015-01-08 The Weather Channel, LLC weather // weatherchannel : 2015-03-12 The Weather Channel, LLC weatherchannel // webcam : 2014-01-23 dot Webcam Limited webcam // weber : 2015-06-04 Saint-Gobain Weber SA weber // website : 2014-04-03 DotWebsite Inc. website // wed : 2013-10-01 Atgron, Inc. wed // wedding : 2014-04-24 Top Level Domain Holdings Limited wedding // weibo : 2015-03-05 Sina Corporation weibo // weir : 2015-01-29 Weir Group IP Limited weir // whoswho : 2014-02-20 Who's Who Registry whoswho // wien : 2013-10-28 punkt.wien GmbH wien // wiki : 2013-11-07 Top Level Design, LLC wiki // williamhill : 2014-03-13 William Hill Organization Limited williamhill // win : 2014-11-20 First Registry Limited win // windows : 2014-12-18 Microsoft Corporation windows // wine : 2015-06-18 June Station, LLC wine // winners : 2015-07-16 The TJX Companies, Inc. winners // wme : 2014-02-13 William Morris Endeavor Entertainment, LLC wme // wolterskluwer : 2015-08-06 Wolters Kluwer N.V. wolterskluwer // woodside : 2015-07-09 Woodside Petroleum Limited woodside // work : 2013-12-19 Top Level Domain Holdings Limited work // works : 2013-11-14 Little Dynamite, LLC works // world : 2014-06-12 Bitter Fields, LLC world // wow : 2015-10-08 Amazon EU S.à r.l. wow // wtc : 2013-12-19 World Trade Centers Association, Inc. wtc // wtf : 2014-03-06 Hidden Way, LLC wtf // xbox : 2014-12-18 Microsoft Corporation xbox // xerox : 2014-10-24 Xerox DNHC LLC xerox // xfinity : 2015-07-09 Comcast IP Holdings I, LLC xfinity // xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. xihuan // xin : 2014-12-11 Elegant Leader Limited xin // xn--11b4c3d : 2015-01-15 VeriSign Sarl कॉम // xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l. セール // xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. 佛山 // xn--30rr7y : 2014-06-12 Excellent First Limited 慈善 // xn--3bst00m : 2013-09-13 Eagle Horizon Limited 集团 // xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED 在线 // xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd. 大众汽车 // xn--3pxu8k : 2015-01-15 VeriSign Sarl 点看 // xn--42c2d9a : 2015-01-15 VeriSign Sarl คอม // xn--45q11c : 2013-11-21 Zodiac Scorpio Limited 八卦 // xn--4gbrim : 2013-10-04 Suhub Electronic Establishment موقع // xn--55qw42g : 2013-11-08 China Organizational Name Administration Center 公益 // xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) 公司 // xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited 香格里拉 // xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited 网站 // xn--6frz82g : 2013-09-23 Afilias Limited 移动 // xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited 我爱你 // xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) москва // xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) католик // xn--80asehdb : 2013-07-14 CORE Association онлайн // xn--80aswg : 2013-07-14 CORE Association сайт // xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited 联通 // xn--9dbq2a : 2015-01-15 VeriSign Sarl קום // xn--9et52u : 2014-06-12 RISE VICTORY LIMITED 时尚 // xn--9krt00a : 2015-03-12 Sina Corporation 微博 // xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited 淡马锡 // xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l. ファッション // xn--c1avg : 2013-11-14 Public Interest Registry орг // xn--c2br7g : 2015-01-15 VeriSign Sarl नेट // xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l. ストア // xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD 삼성 // xn--czr694b : 2014-01-16 Dot Trademark TLD Holding Company Limited 商标 // xn--czrs0t : 2013-12-19 Wild Island, LLC 商店 // xn--czru2d : 2013-11-21 Zodiac Capricorn Limited 商城 // xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” дети // xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l. ポイント // xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社 新闻 // xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited 工行 // xn--fct429k : 2015-04-09 Amazon EU S.à r.l. 家電 // xn--fhbei : 2015-01-15 VeriSign Sarl كوم // xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED 中文网 // xn--fiq64b : 2013-10-14 CITIC Group Corporation 中信 // xn--fjq720a : 2014-05-22 Will Bloom, LLC 娱乐 // xn--flw351e : 2014-07-31 Charleston Road Registry Inc. 谷歌 // xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited 電訊盈科 // xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited 购物 // xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l. クラウド // xn--gk3at1e : 2015-10-08 Amazon EU S.à r.l. 通販 // xn--hxt814e : 2014-05-15 Zodiac Libra Limited 网店 // xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry संगठन // xn--imr513n : 2014-12-11 Dot Trademark TLD Holding Company Limited 餐厅 // xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) 网络 // xn--j1aef : 2015-01-15 VeriSign Sarl ком // xn--jlq61u9w7b : 2015-01-08 Nokia Corporation 诺基亚 // xn--jvr189m : 2015-02-26 Amazon EU S.à r.l. 食品 // xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. 飞利浦 // xn--kpu716f : 2014-12-22 Richemont DNS Inc. 手表 // xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd 手机 // xn--mgba3a3ejt : 2014-11-20 Aramco Services Company ارامكو // xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH العليان // xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) اتصالات // xn--mgbab2bd : 2013-10-31 CORE Association بازار // xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L. موبايلي // xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre ابوظبي // xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) كاثوليك // xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. همراه // xn--mk1bu44c : 2015-01-15 VeriSign Sarl 닷컴 // xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. 政府 // xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. شبكة // xn--ngbe9e0a : 2014-12-04 Kuwait Finance House بيتك // xn--ngbrx : 2015-11-12 League of Arab States عرب // xn--nqv7f : 2013-11-14 Public Interest Registry 机构 // xn--nqv7fs00ema : 2013-11-14 Public Interest Registry 组织机构 // xn--nyqy26a : 2014-11-07 Stable Tone Limited 健康 // xn--p1acf : 2013-12-12 Rusnames Limited рус // xn--pbt977c : 2014-12-22 Richemont DNS Inc. 珠宝 // xn--pssy2u : 2015-01-15 VeriSign Sarl 大拿 // xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. みんな // xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. グーグル // xn--rhqv96g : 2013-09-11 Stable Tone Limited 世界 // xn--rovu88b : 2015-02-26 Amazon EU S.à r.l. 書籍 // xn--ses554g : 2014-01-16 网址 // xn--t60b56a : 2015-01-15 VeriSign Sarl 닷넷 // xn--tckwe : 2015-01-15 VeriSign Sarl コム // xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) 天主教 // xn--unup4y : 2013-07-14 Spring Fields, LLC 游戏 // xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG vermögensberater // xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG vermögensberatung // xn--vhquv : 2013-08-27 Dash McCook, LLC 企业 // xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. 信息 // xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited 嘉里大酒店 // xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited 嘉里 // xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. 广东 // xn--zfr164b : 2013-11-08 China Organizational Name Administration Center 政务 // xperia : 2015-05-14 Sony Mobile Communications AB xperia // xyz : 2013-12-05 XYZ.COM LLC xyz // yachts : 2014-01-09 DERYachts, LLC yachts // yahoo : 2015-04-02 Yahoo! Domain Services Inc. yahoo // yamaxun : 2014-12-18 Amazon EU S.à r.l. yamaxun // yandex : 2014-04-10 YANDEX, LLC yandex // yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. yodobashi // yoga : 2014-05-29 Top Level Domain Holdings Limited yoga // yokohama : 2013-12-12 GMO Registry, Inc. yokohama // you : 2015-04-09 Amazon EU S.à r.l. you // youtube : 2014-05-01 Charleston Road Registry Inc. youtube // yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. yun // zappos : 2015-06-25 Amazon EU S.à r.l. zappos // zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) zara // zero : 2014-12-18 Amazon EU S.à r.l. zero // zip : 2014-05-08 Charleston Road Registry Inc. zip // zippo : 2015-07-02 Zadco Company zippo // zone : 2013-11-14 Outer Falls, LLC zone // zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) zuerich // ===END ICANN DOMAINS=== // ===BEGIN PRIVATE DOMAINS=== // (Note: these are in alphabetical order by company name) // Agnat sp. z o.o. : https://domena.pl // Submitted by Przemyslaw Plewa <it-admin@domena.pl> beep.pl // Alces Software Ltd : http://alces-software.com // Submitted by Mark J. Titorenko <mark.titorenko@alces-software.com> *.compute.estate *.alces.network // alwaysdata : https://www.alwaysdata.com // Submitted by Cyril <admin@alwaysdata.com> *.alwaysdata.net // Amazon CloudFront : https://aws.amazon.com/cloudfront/ // Submitted by Donavan Miller <donavanm@amazon.com> cloudfront.net // Amazon Elastic Compute Cloud : https://aws.amazon.com/ec2/ // Submitted by Luke Wells <psl-maintainers@amazon.com> *.compute.amazonaws.com *.compute-1.amazonaws.com *.compute.amazonaws.com.cn us-east-1.amazonaws.com // Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/ // Submitted by Luke Wells <psl-maintainers@amazon.com> elasticbeanstalk.cn-north-1.amazonaws.com.cn *.elasticbeanstalk.com // Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/ // Submitted by Luke Wells <psl-maintainers@amazon.com> *.elb.amazonaws.com *.elb.amazonaws.com.cn // Amazon S3 : https://aws.amazon.com/s3/ // Submitted by Luke Wells <psl-maintainers@amazon.com> s3.amazonaws.com s3-ap-northeast-1.amazonaws.com s3-ap-northeast-2.amazonaws.com s3-ap-south-1.amazonaws.com s3-ap-southeast-1.amazonaws.com s3-ap-southeast-2.amazonaws.com s3-ca-central-1.amazonaws.com s3-eu-central-1.amazonaws.com s3-eu-west-1.amazonaws.com s3-eu-west-2.amazonaws.com s3-external-1.amazonaws.com s3-fips-us-gov-west-1.amazonaws.com s3-sa-east-1.amazonaws.com s3-us-gov-west-1.amazonaws.com s3-us-east-2.amazonaws.com s3-us-west-1.amazonaws.com s3-us-west-2.amazonaws.com s3.ap-northeast-2.amazonaws.com s3.ap-south-1.amazonaws.com s3.cn-north-1.amazonaws.com.cn s3.ca-central-1.amazonaws.com s3.eu-central-1.amazonaws.com s3.eu-west-2.amazonaws.com s3.us-east-2.amazonaws.com s3.dualstack.ap-northeast-1.amazonaws.com s3.dualstack.ap-northeast-2.amazonaws.com s3.dualstack.ap-south-1.amazonaws.com s3.dualstack.ap-southeast-1.amazonaws.com s3.dualstack.ap-southeast-2.amazonaws.com s3.dualstack.ca-central-1.amazonaws.com s3.dualstack.eu-central-1.amazonaws.com s3.dualstack.eu-west-1.amazonaws.com s3.dualstack.eu-west-2.amazonaws.com s3.dualstack.sa-east-1.amazonaws.com s3.dualstack.us-east-1.amazonaws.com s3.dualstack.us-east-2.amazonaws.com s3-website-us-east-1.amazonaws.com s3-website-us-west-1.amazonaws.com s3-website-us-west-2.amazonaws.com s3-website-ap-northeast-1.amazonaws.com s3-website-ap-southeast-1.amazonaws.com s3-website-ap-southeast-2.amazonaws.com s3-website-eu-west-1.amazonaws.com s3-website-sa-east-1.amazonaws.com s3-website.ap-northeast-2.amazonaws.com s3-website.ap-south-1.amazonaws.com s3-website.ca-central-1.amazonaws.com s3-website.eu-central-1.amazonaws.com s3-website.eu-west-2.amazonaws.com s3-website.us-east-2.amazonaws.com // Amune : https://amune.org/ // Submitted by Team Amune <cert@amune.org> t3l3p0rt.net tele.amune.org // Aptible : https://www.aptible.com/ // Submitted by Thomas Orozco <thomas@aptible.com> on-aptible.com // Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ // Submitted by Hector Martin <marcan@euskalencounter.org> user.party.eus // Association potager.org : https://potager.org/ // Submitted by Lunar <jardiniers@potager.org> pimienta.org poivron.org potager.org sweetpepper.org // ASUSTOR Inc. : http://www.asustor.com // Submitted by Vincent Tseng <vincenttseng@asustor.com> myasustor.com // AVM : https://avm.de // Submitted by Andreas Weise <a.weise@avm.de> myfritz.net // AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com // Submitted by James Kennedy <domains@advisorwebsites.com> *.awdev.ca *.advisor.ws // backplane : https://www.backplane.io // Submitted by Anthony Voutas <anthony@backplane.io> backplaneapp.io // BetaInABox // Submitted by Adrian <adrian@betainabox.com> betainabox.com // BinaryLane : http://www.binarylane.com // Submitted by Nathan O'Sullivan <nathan@mammoth.com.au> bnr.la // Boxfuse : https://boxfuse.com // Submitted by Axel Fontaine <axel@boxfuse.com> boxfuse.io // bplaced : https://www.bplaced.net/ // Submitted by Miroslav Bozic <security@bplaced.net> square7.ch bplaced.com bplaced.de square7.de bplaced.net square7.net // BrowserSafetyMark // Submitted by Dave Tharp <browsersafetymark.io@quicinc.com> browsersafetymark.io // callidomus : https://www.callidomus.com/ // Submitted by Marcus Popp <admin@callidomus.com> mycd.eu // CentralNic : http://www.centralnic.com/names/domains // Submitted by registry <gavin.brown@centralnic.com> ae.org ar.com br.com cn.com com.de com.se de.com eu.com gb.com gb.net hu.com hu.net jp.net jpn.com kr.com mex.com no.com qc.com ru.com sa.com se.com se.net uk.com uk.net us.com uy.com za.bz za.com // Africa.com Web Solutions Ltd : https://registry.africa.com // Submitted by Gavin Brown <gavin.brown@centralnic.com> africa.com // iDOT Services Limited : http://www.domain.gr.com // Submitted by Gavin Brown <gavin.brown@centralnic.com> gr.com // Radix FZC : http://domains.in.net // Submitted by Gavin Brown <gavin.brown@centralnic.com> in.net // US REGISTRY LLC : http://us.org // Submitted by Gavin Brown <gavin.brown@centralnic.com> us.org // co.com Registry, LLC : https://registry.co.com // Submitted by Gavin Brown <gavin.brown@centralnic.com> co.com // c.la : http://www.c.la/ c.la // certmgr.org : https://certmgr.org // Submitted by B. Blechschmidt <hostmaster@certmgr.org> certmgr.org // Citrix : https://citrix.com // Submitted by Alex Stoddard <alex.stoddard@citrix.com> xenapponazure.com // ClearVox : http://www.clearvox.nl/ // Submitted by Leon Rowland <leon@clearvox.nl> virtueeldomein.nl // Cloud66 : https://www.cloud66.com/ // Submitted by Khash Sajadi <khash@cloud66.com> c66.me // cloudControl : https://www.cloudcontrol.com/ // Submitted by Tobias Wilken <tw@cloudcontrol.com> cloudcontrolled.com cloudcontrolapp.com // co.ca : http://registry.co.ca/ co.ca // i-registry s.r.o. : http://www.i-registry.cz/ // Submitted by Martin Semrad <semrad@i-registry.cz> co.cz // CDN77.com : http://www.cdn77.com // Submitted by Jan Krpes <jan.krpes@cdn77.com> c.cdn77.org cdn77-ssl.net r.cdn77.net rsc.cdn77.org ssl.origin.cdn77-secure.org // Cloud DNS Ltd : http://www.cloudns.net // Submitted by Aleksander Hristov <noc@cloudns.net> cloudns.asia cloudns.biz cloudns.club cloudns.cc cloudns.eu cloudns.in cloudns.info cloudns.org cloudns.pro cloudns.pw cloudns.us // CoDNS B.V. co.nl co.no // COSIMO GmbH : http://www.cosimo.de // Submitted by Rene Marticke <rmarticke@cosimo.de> dyn.cosidns.de dynamisches-dns.de dnsupdater.de internet-dns.de l-o-g-i-n.de dynamic-dns.info feste-ip.net knx-server.net static-access.net // Craynic, s.r.o. : http://www.craynic.com/ // Submitted by Ales Krajnik <ales.krajnik@craynic.com> realm.cz // Cryptonomic : https://cryptonomic.net/ // Submitted by Andrew Cady <public-suffix-list@cryptonomic.net> *.cryptonomic.net // Cupcake : https://cupcake.io/ // Submitted by Jonathan Rudenberg <jonathan@cupcake.io> cupcake.is // cyon GmbH : https://www.cyon.ch/ // Submitted by Dominic Luechinger <dol@cyon.ch> cyon.link cyon.site // Daplie, Inc : https://daplie.com // Submitted by AJ ONeal <aj@daplie.com> daplie.me localhost.daplie.me // Dansk.net : http://www.dansk.net/ // Submitted by Anani Voule <digital@digital.co.dk> biz.dk co.dk firm.dk reg.dk store.dk // deSEC : https://desec.io/ // Submitted by Peter Thomassen <peter@desec.io> dedyn.io // DNShome : https://www.dnshome.de/ // Submitted by Norbert Auler <mail@dnshome.de> dnshome.de // DreamHost : http://www.dreamhost.com/ // Submitted by Andrew Farmer <andrew.farmer@dreamhost.com> dreamhosters.com // Drobo : http://www.drobo.com/ // Submitted by Ricardo Padilha <rpadilha@drobo.com> mydrobo.com // Drud Holdings, LLC. : https://www.drud.com/ // Submitted by Kevin Bridges <kevin@drud.com> drud.io drud.us // DuckDNS : http://www.duckdns.org/ // Submitted by Richard Harper <richard@duckdns.org> duckdns.org // dy.fi : http://dy.fi/ // Submitted by Heikki Hannikainen <hessu@hes.iki.fi> dy.fi tunk.org // DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ dyndns-at-home.com dyndns-at-work.com dyndns-blog.com dyndns-free.com dyndns-home.com dyndns-ip.com dyndns-mail.com dyndns-office.com dyndns-pics.com dyndns-remote.com dyndns-server.com dyndns-web.com dyndns-wiki.com dyndns-work.com dyndns.biz dyndns.info dyndns.org dyndns.tv at-band-camp.net ath.cx barrel-of-knowledge.info barrell-of-knowledge.info better-than.tv blogdns.com blogdns.net blogdns.org blogsite.org boldlygoingnowhere.org broke-it.net buyshouses.net cechire.com dnsalias.com dnsalias.net dnsalias.org dnsdojo.com dnsdojo.net dnsdojo.org does-it.net doesntexist.com doesntexist.org dontexist.com dontexist.net dontexist.org doomdns.com doomdns.org dvrdns.org dyn-o-saur.com dynalias.com dynalias.net dynalias.org dynathome.net dyndns.ws endofinternet.net endofinternet.org endoftheinternet.org est-a-la-maison.com est-a-la-masion.com est-le-patron.com est-mon-blogueur.com for-better.biz for-more.biz for-our.info for-some.biz for-the.biz forgot.her.name forgot.his.name from-ak.com from-al.com from-ar.com from-az.net from-ca.com from-co.net from-ct.com from-dc.com from-de.com from-fl.com from-ga.com from-hi.com from-ia.com from-id.com from-il.com from-in.com from-ks.com from-ky.com from-la.net from-ma.com from-md.com from-me.org from-mi.com from-mn.com from-mo.com from-ms.com from-mt.com from-nc.com from-nd.com from-ne.com from-nh.com from-nj.com from-nm.com from-nv.com from-ny.net from-oh.com from-ok.com from-or.com from-pa.com from-pr.com from-ri.com from-sc.com from-sd.com from-tn.com from-tx.com from-ut.com from-va.com from-vt.com from-wa.com from-wi.com from-wv.com from-wy.com ftpaccess.cc fuettertdasnetz.de game-host.org game-server.cc getmyip.com gets-it.net go.dyndns.org gotdns.com gotdns.org groks-the.info groks-this.info ham-radio-op.net here-for-more.info hobby-site.com hobby-site.org home.dyndns.org homedns.org homeftp.net homeftp.org homeip.net homelinux.com homelinux.net homelinux.org homeunix.com homeunix.net homeunix.org iamallama.com in-the-band.net is-a-anarchist.com is-a-blogger.com is-a-bookkeeper.com is-a-bruinsfan.org is-a-bulls-fan.com is-a-candidate.org is-a-caterer.com is-a-celticsfan.org is-a-chef.com is-a-chef.net is-a-chef.org is-a-conservative.com is-a-cpa.com is-a-cubicle-slave.com is-a-democrat.com is-a-designer.com is-a-doctor.com is-a-financialadvisor.com is-a-geek.com is-a-geek.net is-a-geek.org is-a-green.com is-a-guru.com is-a-hard-worker.com is-a-hunter.com is-a-knight.org is-a-landscaper.com is-a-lawyer.com is-a-liberal.com is-a-libertarian.com is-a-linux-user.org is-a-llama.com is-a-musician.com is-a-nascarfan.com is-a-nurse.com is-a-painter.com is-a-patsfan.org is-a-personaltrainer.com is-a-photographer.com is-a-player.com is-a-republican.com is-a-rockstar.com is-a-socialist.com is-a-soxfan.org is-a-student.com is-a-teacher.com is-a-techie.com is-a-therapist.com is-an-accountant.com is-an-actor.com is-an-actress.com is-an-anarchist.com is-an-artist.com is-an-engineer.com is-an-entertainer.com is-by.us is-certified.com is-found.org is-gone.com is-into-anime.com is-into-cars.com is-into-cartoons.com is-into-games.com is-leet.com is-lost.org is-not-certified.com is-saved.org is-slick.com is-uberleet.com is-very-bad.org is-very-evil.org is-very-good.org is-very-nice.org is-very-sweet.org is-with-theband.com isa-geek.com isa-geek.net isa-geek.org isa-hockeynut.com issmarterthanyou.com isteingeek.de istmein.de kicks-ass.net kicks-ass.org knowsitall.info land-4-sale.us lebtimnetz.de leitungsen.de likes-pie.com likescandy.com merseine.nu mine.nu misconfused.org mypets.ws myphotos.cc neat-url.com office-on-the.net on-the-web.tv podzone.net podzone.org readmyblog.org saves-the-whales.com scrapper-site.net scrapping.cc selfip.biz selfip.com selfip.info selfip.net selfip.org sells-for-less.com sells-for-u.com sells-it.net sellsyourhome.org servebbs.com servebbs.net servebbs.org serveftp.net serveftp.org servegame.org shacknet.nu simple-url.com space-to-rent.com stuff-4-sale.org stuff-4-sale.us teaches-yoga.com thruhere.net traeumtgerade.de webhop.biz webhop.info webhop.net webhop.org worse-than.tv writesthisblog.com // ddnss.de : https://www.ddnss.de/ // Submitted by Robert Niedziela <webmaster@ddnss.de> ddnss.de dyn.ddnss.de dyndns.ddnss.de dyndns1.de dyn-ip24.de home-webserver.de dyn.home-webserver.de myhome-server.de ddnss.org // dynv6 : https://dynv6.com // Submitted by Dominik Menke <dom@digineo.de> dynv6.net // E4YOU spol. s.r.o. : https://e4you.cz/ // Submitted by Vladimir Dudr <info@e4you.cz> e4.cz // Enonic : http://enonic.com/ // Submitted by Erik Kaareng-Sunde <esu@enonic.com> enonic.io customer.enonic.io // EU.org https://eu.org/ // Submitted by Pierre Beyssac <hostmaster@eu.org> eu.org al.eu.org asso.eu.org at.eu.org au.eu.org be.eu.org bg.eu.org ca.eu.org cd.eu.org ch.eu.org cn.eu.org cy.eu.org cz.eu.org de.eu.org dk.eu.org edu.eu.org ee.eu.org es.eu.org fi.eu.org fr.eu.org gr.eu.org hr.eu.org hu.eu.org ie.eu.org il.eu.org in.eu.org int.eu.org is.eu.org it.eu.org jp.eu.org kr.eu.org lt.eu.org lu.eu.org lv.eu.org mc.eu.org me.eu.org mk.eu.org mt.eu.org my.eu.org net.eu.org ng.eu.org nl.eu.org no.eu.org nz.eu.org paris.eu.org pl.eu.org pt.eu.org q-a.eu.org ro.eu.org ru.eu.org se.eu.org si.eu.org sk.eu.org tr.eu.org uk.eu.org us.eu.org // Evennode : http://www.evennode.com/ // Submitted by Michal Kralik <support@evennode.com> eu-1.evennode.com eu-2.evennode.com eu-3.evennode.com us-1.evennode.com us-2.evennode.com us-3.evennode.com // eDirect Corp. : https://hosting.url.com.tw/ // Submitted by C.S. chang <cschang@corp.url.com.tw> twmail.cc twmail.net twmail.org mymailer.com.tw url.tw // Facebook, Inc. // Submitted by Peter Ruibal <public-suffix@fb.com> apps.fbsbx.com // FAITID : https://faitid.org/ // Submitted by Maxim Alzoba <tech.contact@faitid.org> // https://www.flexireg.net/stat_info ru.net adygeya.ru bashkiria.ru bir.ru cbg.ru com.ru dagestan.ru grozny.ru kalmykia.ru kustanai.ru marine.ru mordovia.ru msk.ru mytis.ru nalchik.ru nov.ru pyatigorsk.ru spb.ru vladikavkaz.ru vladimir.ru abkhazia.su adygeya.su aktyubinsk.su arkhangelsk.su armenia.su ashgabad.su azerbaijan.su balashov.su bashkiria.su bryansk.su bukhara.su chimkent.su dagestan.su east-kazakhstan.su exnet.su georgia.su grozny.su ivanovo.su jambyl.su kalmykia.su kaluga.su karacol.su karaganda.su karelia.su khakassia.su krasnodar.su kurgan.su kustanai.su lenug.su mangyshlak.su mordovia.su msk.su murmansk.su nalchik.su navoi.su north-kazakhstan.su nov.su obninsk.su penza.su pokrovsk.su sochi.su spb.su tashkent.su termez.su togliatti.su troitsk.su tselinograd.su tula.su tuva.su vladikavkaz.su vladimir.su vologda.su // Fastly Inc. : http://www.fastly.com/ // Submitted by Fastly Security <security@fastly.com> fastlylb.net map.fastlylb.net freetls.fastly.net map.fastly.net a.prod.fastly.net global.prod.fastly.net a.ssl.fastly.net b.ssl.fastly.net global.ssl.fastly.net // Featherhead : https://featherhead.xyz/ // Submitted by Simon Menke <simon@featherhead.xyz> fhapp.xyz // Fedora : https://fedoraproject.org/ // submitted by Patrick Uiterwijk <puiterwijk@fedoraproject.org> fedorainfracloud.org fedorapeople.org cloud.fedoraproject.org // Firebase, Inc. // Submitted by Chris Raynor <chris@firebase.com> firebaseapp.com // Flynn : https://flynn.io // Submitted by Jonathan Rudenberg <jonathan@flynn.io> flynnhub.com // Freebox : http://www.freebox.fr // Submitted by Romain Fliedel <rfliedel@freebox.fr> freebox-os.com freeboxos.com fbx-os.fr fbxos.fr freebox-os.fr freeboxos.fr // Fusion Intranet : https://www.fusion-intranet.com // Submitted by Matthias Burtscher <matthias.burtscher@fusonic.net> myfusion.cloud // Futureweb OG : http://www.futureweb.at // Submitted by Andreas Schnederle-Wagner <schnederle@futureweb.at> futurehosting.at futuremailing.at *.ex.ortsinfo.at *.kunden.ortsinfo.at *.statics.cloud // GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains // Submitted by David Illsley <david.illsley@digital.cabinet-office.gov.uk> service.gov.uk // GitHub, Inc. // Submitted by Patrick Toomey <security@github.com> github.io githubusercontent.com githubcloud.com *.api.githubcloud.com *.ext.githubcloud.com gist.githubcloud.com *.githubcloudusercontent.com // GitLab, Inc. // Submitted by Alex Hanselka <alex@gitlab.com> gitlab.io // UKHomeOffice : https://www.gov.uk/government/organisations/home-office // Submitted by Jon Shanks <jon.shanks@digital.homeoffice.gov.uk> homeoffice.gov.uk // GlobeHosting, Inc. // Submitted by Zoltan Egresi <egresi@globehosting.com> ro.im shop.ro // GoIP DNS Services : http://www.goip.de // Submitted by Christian Poulter <milchstrasse@goip.de> goip.de // Google, Inc. // Submitted by Eduardo Vela <evn@google.com> *.0emm.com appspot.com blogspot.ae blogspot.al blogspot.am blogspot.ba blogspot.be blogspot.bg blogspot.bj blogspot.ca blogspot.cf blogspot.ch blogspot.cl blogspot.co.at blogspot.co.id blogspot.co.il blogspot.co.ke blogspot.co.nz blogspot.co.uk blogspot.co.za blogspot.com blogspot.com.ar blogspot.com.au blogspot.com.br blogspot.com.by blogspot.com.co blogspot.com.cy blogspot.com.ee blogspot.com.eg blogspot.com.es blogspot.com.mt blogspot.com.ng blogspot.com.tr blogspot.com.uy blogspot.cv blogspot.cz blogspot.de blogspot.dk blogspot.fi blogspot.fr blogspot.gr blogspot.hk blogspot.hr blogspot.hu blogspot.ie blogspot.in blogspot.is blogspot.it blogspot.jp blogspot.kr blogspot.li blogspot.lt blogspot.lu blogspot.md blogspot.mk blogspot.mr blogspot.mx blogspot.my blogspot.nl blogspot.no blogspot.pe blogspot.pt blogspot.qa blogspot.re blogspot.ro blogspot.rs blogspot.ru blogspot.se blogspot.sg blogspot.si blogspot.sk blogspot.sn blogspot.td blogspot.tw blogspot.ug blogspot.vn cloudfunctions.net codespot.com googleapis.com googlecode.com pagespeedmobilizer.com publishproxy.com withgoogle.com withyoutube.com // Hashbang : https://hashbang.sh hashbang.sh // Hasura : https://hasura.io // Submitted by Shahidh K Muhammed <shahidh@hasura.io> hasura-app.io // Hepforge : https://www.hepforge.org // Submitted by David Grellscheid <admin@hepforge.org> hepforge.org // Heroku : https://www.heroku.com/ // Submitted by Tom Maher <tmaher@heroku.com> herokuapp.com herokussl.com // Ici la Lune : http://www.icilalune.com/ // Submitted by Simon Morvan <simon@icilalune.com> moonscale.net // iki.fi // Submitted by Hannu Aronsson <haa@iki.fi> iki.fi // info.at : http://www.info.at/ biz.at info.at // Interlegis : http://www.interlegis.leg.br // Submitted by Gabriel Ferreira <registrobr@interlegis.leg.br> ac.leg.br al.leg.br am.leg.br ap.leg.br ba.leg.br ce.leg.br df.leg.br es.leg.br go.leg.br ma.leg.br mg.leg.br ms.leg.br mt.leg.br pa.leg.br pb.leg.br pe.leg.br pi.leg.br pr.leg.br rj.leg.br rn.leg.br ro.leg.br rr.leg.br rs.leg.br sc.leg.br se.leg.br sp.leg.br to.leg.br // IPiFony Systems, Inc. : https://www.ipifony.com/ // Submitted by Matthew Hardeman <mhardeman@ipifony.com> ipifony.net // Joyent : https://www.joyent.com/ // Submitted by Brian Bennett <brian.bennett@joyent.com> *.triton.zone *.cns.joyent.com // JS.ORG : http://dns.js.org // Submitted by Stefan Keim <admin@js.org> js.org // Keyweb AG : https://www.keyweb.de // Submitted by Martin Dannehl <postmaster@keymachine.de> keymachine.de // KnightPoint Systems, LLC : http://www.knightpoint.com/ // Submitted by Roy Keene <rkeene@knightpoint.com> knightpoint.systems // .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf co.krd edu.krd // Magento Commerce // Submitted by Damien Tournoud <dtournoud@magento.cloud> *.magentosite.cloud // Mail.Ru Group : https://hb.cldmail.ru // Submitted by Ilya Zaretskiy <zaretskiy@corp.mail.ru> hb.cldmail.ru // Meteor Development Group : https://www.meteor.com/hosting // Submitted by Pierre Carrier <pierre@meteor.com> meteorapp.com eu.meteorapp.com // Michau Enterprises Limited : http://www.co.pl/ co.pl // Microsoft : http://microsoft.com // Submitted by Barry Dorrans <bdorrans@microsoft.com> azurewebsites.net azure-mobile.net cloudapp.net // Mozilla Foundation : https://mozilla.org/ // Submitted by glob <glob@mozilla.com> bmoattachments.org // Neustar Inc. // Submitted by Trung Tran <Trung.Tran@neustar.biz> 4u.com // ngrok : https://ngrok.com/ // Submitted by Alan Shreve <alan@ngrok.com> ngrok.io // NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ // Submitted by Jeff Wheelhouse <support@nearlyfreespeech.net> nfshost.com // nsupdate.info : https://www.nsupdate.info/ // Submitted by Thomas Waldmann <info@nsupdate.info> nsupdate.info nerdpol.ovh // No-IP.com : https://noip.com/ // Submitted by Deven Reza <publicsuffixlist@noip.com> blogsyte.com brasilia.me cable-modem.org ciscofreak.com collegefan.org couchpotatofries.org damnserver.com ddns.me ditchyourip.com dnsfor.me dnsiskinky.com dvrcam.info dynns.com eating-organic.net fantasyleague.cc geekgalaxy.com golffan.us health-carereform.com homesecuritymac.com homesecuritypc.com hopto.me ilovecollege.info loginto.me mlbfan.org mmafan.biz myactivedirectory.com mydissent.net myeffect.net mymediapc.net mypsx.net mysecuritycamera.com mysecuritycamera.net mysecuritycamera.org net-freaks.com nflfan.org nhlfan.net no-ip.ca no-ip.co.uk no-ip.net noip.us onthewifi.com pgafan.net point2this.com pointto.us privatizehealthinsurance.net quicksytes.com read-books.org securitytactics.com serveexchange.com servehumour.com servep2p.com servesarcasm.com stufftoread.com ufcfan.org unusualperson.com workisboring.com 3utilities.com bounceme.net ddns.net ddnsking.com gotdns.ch hopto.org myftp.biz myftp.org myvnc.com no-ip.biz no-ip.info no-ip.org noip.me redirectme.net servebeer.com serveblog.net servecounterstrike.com serveftp.com servegame.com servehalflife.com servehttp.com serveirc.com serveminecraft.net servemp3.com servepics.com servequake.com sytes.net webhop.me zapto.org // NYC.mn : http://www.information.nyc.mn // Submitted by Matthew Brown <mattbrown@nyc.mn> nyc.mn // Octopodal Solutions, LLC. : https://ulterius.io/ // Submitted by Andrew Sampson <andrew@ulterius.io> cya.gg // One Fold Media : http://www.onefoldmedia.com/ // Submitted by Eddie Jones <eddie@onefoldmedia.com> nid.io // OpenCraft GmbH : http://opencraft.com/ // Submitted by Sven Marnach <sven@opencraft.com> opencraft.hosting // Opera Software, A.S.A. // Submitted by Yngve Pettersen <yngve@opera.com> operaunite.com // OutSystems // Submitted by Duarte Santos <domain-admin@outsystemscloud.com> outsystemscloud.com // OwnProvider : http://www.ownprovider.com // Submitted by Jan Moennich <jan.moennich@ownprovider.com> ownprovider.com // oy.lc // Submitted by Charly Coste <changaco@changaco.oy.lc> oy.lc // Pagefog : https://pagefog.com/ // Submitted by Derek Myers <derek@pagefog.com> pgfog.com // Pagefront : https://www.pagefronthq.com/ // Submitted by Jason Kriss <jason@pagefronthq.com> pagefrontapp.com // .pl domains (grandfathered) art.pl gliwice.pl krakow.pl poznan.pl wroc.pl zakopane.pl // Pantheon Systems, Inc. : https://pantheon.io/ // Submitted by Gary Dylina <gary@pantheon.io> pantheonsite.io gotpantheon.com // Peplink | Pepwave : http://peplink.com/ // Submitted by Steve Leung <steveleung@peplink.com> mypep.link // Planet-Work : https://www.planet-work.com/ // Submitted by Frédéric VANNIÈRE <f.vanniere@planet-work.com> on-web.fr // Platform.sh : https://platform.sh // Submitted by Nikola Kotur <nikola@platform.sh> *.platform.sh *.platformsh.site // prgmr.com : https://prgmr.com/ // Submitted by Sarah Newman <owner@prgmr.com> xen.prgmr.com // priv.at : http://www.nic.priv.at/ // Submitted by registry <lendl@nic.at> priv.at // Protonet GmbH : http://protonet.io // Submitted by Martin Meier <admin@protonet.io> protonet.io // Publication Presse Communication SARL : https://ppcom.fr // Submitted by Yaacov Akiba Slama <admin@chirurgiens-dentistes-en-france.fr> chirurgiens-dentistes-en-france.fr // QA2 // Submitted by Daniel Dent (https://www.danieldent.com/) qa2.com // QNAP System Inc : https://www.qnap.com // Submitted by Nick Chang <nickchang@qnap.com> dev-myqnapcloud.com alpha-myqnapcloud.com myqnapcloud.com // Quip : https://quip.com // Submitted by Patrick Linehan <plinehan@quip.com> *.quipelements.com // Qutheory LLC : http://qutheory.io // Submitted by Jonas Schwartz <jonas@qutheory.io> vapor.cloud vaporcloud.io // Rackmaze LLC : https://www.rackmaze.com // Submitted by Kirill Pertsev <kika@rackmaze.com> rackmaze.com rackmaze.net // Red Hat, Inc. OpenShift : https://openshift.redhat.com/ // Submitted by Tim Kramer <tkramer@rhcloud.com> rhcloud.com // RethinkDB : https://www.rethinkdb.com/ // Submitted by Chris Kastorff <info@rethinkdb.com> hzc.io // Revitalised Limited : http://www.revitalised.co.uk // Submitted by Jack Price <jack@revitalised.co.uk> wellbeingzone.eu ptplus.fit wellbeingzone.co.uk // Sandstorm Development Group, Inc. : https://sandcats.io/ // Submitted by Asheesh Laroia <asheesh@sandstorm.io> sandcats.io // SBE network solutions GmbH : https://www.sbe.de/ // Submitted by Norman Meilick <nm@sbe.de> logoip.de logoip.com // Securepoint GmbH : https://www.securepoint.de // Submitted by Erik Anders <erik.anders@securepoint.de> firewall-gateway.com firewall-gateway.de my-gateway.de my-router.de spdns.de spdns.eu firewall-gateway.net my-firewall.org myfirewall.org spdns.org // SensioLabs, SAS : https://sensiolabs.com/ // Submitted by Fabien Potencier <fabien.potencier@sensiolabs.com> *.sensiosite.cloud // Service Online LLC : http://drs.ua/ // Submitted by Serhii Bulakh <support@drs.ua> biz.ua co.ua pp.ua // ShiftEdit : https://shiftedit.net/ // Submitted by Adam Jimenez <adam@shiftcreate.com> shiftedit.io // Shopblocks : http://www.shopblocks.com/ // Submitted by Alex Bowers <alex@shopblocks.com> myshopblocks.com // SinaAppEngine : http://sae.sina.com.cn/ // Submitted by SinaAppEngine <saesupport@sinacloud.com> 1kapp.com appchizi.com applinzi.com sinaapp.com vipsinaapp.com // Skyhat : http://www.skyhat.io // Submitted by Shante Adam <shante@skyhat.io> bounty-full.com alpha.bounty-full.com beta.bounty-full.com // staticland : https://static.land // Submitted by Seth Vincent <sethvincent@gmail.com> static.land dev.static.land sites.static.land // SourceLair PC : https://www.sourcelair.com // Submitted by Antonis Kalipetis <akalipetis@sourcelair.com> apps.lair.io *.stolos.io // SpaceKit : https://www.spacekit.io/ // Submitted by Reza Akhavan <spacekit.io@gmail.com> spacekit.io // Stackspace : https://www.stackspace.io/ // Submitted by Lina He <info@stackspace.io> stackspace.space // Storj Labs Inc. : https://storj.io/ // Submitted by Philip Hutchins <hostmaster@storj.io> storj.farm // Synology, Inc. : https://www.synology.com/ // Submitted by Rony Weng <ronyweng@synology.com> diskstation.me dscloud.biz dscloud.me dscloud.mobi dsmynas.com dsmynas.net dsmynas.org familyds.com familyds.net familyds.org i234.me myds.me synology.me vpnplus.to // TAIFUN Software AG : http://taifun-software.de // Submitted by Bjoern Henke <dev-server@taifun-software.de> taifun-dns.de // TASK geographical domains (www.task.gda.pl/uslugi/dns) gda.pl gdansk.pl gdynia.pl med.pl sopot.pl // TownNews.com : http://www.townnews.com // Submitted by Dustin Ward <dward@townnews.com> bloxcms.com townnews-staging.com // TransIP : htts://www.transip.nl // Submitted by Rory Breuk <rbreuk@transip.nl> *.transurl.be *.transurl.eu *.transurl.nl // TuxFamily : http://tuxfamily.org // Submitted by TuxFamily administrators <adm@staff.tuxfamily.org> tuxfamily.org // TwoDNS : https://www.twodns.de/ // Submitted by TwoDNS-Support <support@two-dns.de> dd-dns.de diskstation.eu diskstation.org dray-dns.de draydns.de dyn-vpn.de dynvpn.de mein-vigor.de my-vigor.de my-wan.de syno-ds.de synology-diskstation.de synology-ds.de // Uberspace : https://uberspace.de // Submitted by Moritz Werner <mwerner@jonaspasche.com> uber.space // UDR Limited : http://www.udr.hk.com // Submitted by registry <hostmaster@udr.hk.com> hk.com hk.org ltd.hk inc.hk // .US // Submitted by Ed Moore <Ed.Moore@lib.de.us> lib.de.us // Viprinet Europe GmbH : http://www.viprinet.com // Submitted by Simon Kissel <hostmaster@viprinet.com> router.management // Western Digital Technologies, Inc : https://www.wdc.com // Submitted by Jung Jin <jungseok.jin@wdc.com> remotewd.com // Wikimedia Labs : https://wikitech.wikimedia.org // Submitted by Yuvi Panda <yuvipanda@wikimedia.org> wmflabs.org // XS4ALL Internet bv : https://www.xs4all.nl/ // Submitted by Daniel Mostertman <unixbeheer+publicsuffix@xs4all.net> xs4all.space // Yola : https://www.yola.com/ // Submitted by Stefano Rivera <stefano@yola.com> yolasite.com // Yombo : https://yombo.net // Submitted by Mitch Schwenk <mitch@yombo.net> ybo.faith yombo.me homelink.one ybo.party ybo.review ybo.science ybo.trade // ZaNiC : http://www.za.net/ // Submitted by registry <hostmaster@nic.za.net> za.net za.org // Zeit, Inc. : https://zeit.domains/ // Submitted by Olli Vanhoja <olli@zeit.co> now.sh // 1GB LLC : https://www.1gb.ua/ // Submitted by 1GB LLC <noc@1gb.com.ua> cc.ua inf.ua ltd.ua // ===END PRIVATE DOMAINS=== { "name": "amphp/cache", "homepage": "https://github.com/amphp/cache", "description": "A promise-aware caching API for Amp.", "license": "MIT", "support": { "issues": "https://github.com/amphp/cache/issues", "irc": "irc://irc.freenode.org/amphp" }, "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" }, { "name": "Daniel Lowrey", "email": "rdlowrey@php.net" } ], "require": { "amphp/amp": "^2" }, "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", "friendsofphp/php-cs-fixer": "^2.3" }, "autoload": { "psr-4": { "Amp\\Cache\\": "lib" } }, "autoload-dev": { "psr-4": { "Amp\\Cache\\Test\\": "test" } } } <?php namespace Amp\Cache; /** * MUST be thrown in case a cache operation fails. */ class CacheException extends \Exception { } <?php namespace Amp\Cache; use Amp\Promise; final class PrefixCache implements Cache { private $cache; private $keyPrefix; public function __construct(Cache $cache, string $keyPrefix) { $this->cache = $cache; $this->keyPrefix = $keyPrefix; } /** * Gets the specified key prefix. * * @return string */ public function getKeyPrefix(): string { return $this->keyPrefix; } /** @inheritdoc */ public function get(string $key): Promise { return $this->cache->get($this->keyPrefix . $key); } /** @inheritdoc */ public function set(string $key, string $value, int $ttl = null): Promise { return $this->cache->set($this->keyPrefix . $key, $value, $ttl); } /** @inheritdoc */ public function delete(string $key): Promise { return $this->cache->delete($this->keyPrefix . $key); } } <?php namespace Amp\Cache; use Amp\Loop; use Amp\Promise; use Amp\Struct; use Amp\Success; final class ArrayCache implements Cache { private $sharedState; private $ttlWatcherId; private $maxSize; /** * @param int $gcInterval The frequency in milliseconds at which expired cache entries should be garbage collected. * @param int $maxSize The maximum size of cache array (number of elements). */ public function __construct(int $gcInterval = 5000, int $maxSize = null) { // By using a shared state object we're able to use `__destruct()` for "normal" garbage collection of both this // instance and the loop's watcher. Otherwise this object could only be GC'd when the TTL watcher was cancelled // at the loop layer. $this->sharedState = $sharedState = new class { use Struct; public $cache = []; public $cacheTimeouts = []; public $isSortNeeded = false; public function collectGarbage() { $now = \time(); if ($this->isSortNeeded) { \asort($this->cacheTimeouts); $this->isSortNeeded = false; } foreach ($this->cacheTimeouts as $key => $expiry) { if ($now <= $expiry) { break; } unset( $this->cache[$key], $this->cacheTimeouts[$key] ); } } }; $this->ttlWatcherId = Loop::repeat($gcInterval, [$sharedState, "collectGarbage"]); $this->maxSize = $maxSize; Loop::unreference($this->ttlWatcherId); } public function __destruct() { $this->sharedState->cache = []; $this->sharedState->cacheTimeouts = []; Loop::cancel($this->ttlWatcherId); } /** @inheritdoc */ public function get(string $key): Promise { if (!isset($this->sharedState->cache[$key])) { return new Success(null); } if (isset($this->sharedState->cacheTimeouts[$key]) && \time() > $this->sharedState->cacheTimeouts[$key]) { unset( $this->sharedState->cache[$key], $this->sharedState->cacheTimeouts[$key] ); return new Success(null); } return new Success($this->sharedState->cache[$key]); } /** @inheritdoc */ public function set(string $key, string $value, int $ttl = null): Promise { if ($ttl === null) { unset($this->sharedState->cacheTimeouts[$key]); } elseif (\is_int($ttl) && $ttl >= 0) { $expiry = \time() + $ttl; $this->sharedState->cacheTimeouts[$key] = $expiry; $this->sharedState->isSortNeeded = true; } else { throw new \Error("Invalid cache TTL ({$ttl}; integer >= 0 or null required"); } unset($this->sharedState->cache[$key]); if (count($this->sharedState->cache) === $this->maxSize) { array_shift($this->sharedState->cache); } $this->sharedState->cache[$key] = $value; return new Success; } /** @inheritdoc */ public function delete(string $key): Promise { $exists = isset($this->sharedState->cache[$key]); unset( $this->sharedState->cache[$key], $this->sharedState->cacheTimeouts[$key] ); return new Success($exists); } } <?php namespace Amp\Cache; use Amp\Promise; interface Cache { /** * Gets a value associated with the given key. * * If the specified key doesn't exist implementations MUST succeed the resulting promise with `null`. * * @param $key string Cache key. * * @return Promise Resolves to the cached value nor `null` if it doesn't exist or fails with a CacheException on * failure. */ public function get(string $key): Promise; /** * Sets a value associated with the given key. Overrides existing values (if they exist). * * The eventual resolution value of the resulting promise is unimportant. The success or failure of the promise * indicates the operation's success. * * @param $key string Cache key. * @param $value string Value to cache. * @param $ttl int Timeout in seconds. The default `null` $ttl value indicates no timeout. Values less than 0 MUST * throw an \Error. * * @return Promise Resolves either successfully or fails with a CacheException on failure. */ public function set(string $key, string $value, int $ttl = null): Promise; /** * Deletes a value associated with the given key if it exists. * * Implementations SHOULD return boolean `true` or `false` to indicate whether the specified key existed at the time * the delete operation was requested. If such information is not available, the implementation MUST resolve the * promise with `null`. * * Implementations MUST transparently succeed operations for non-existent keys. * * @param $key string Cache key. * * @return Promise Resolves to `true` / `false` / `null` to indicate whether the key existed or fails with a * CacheException on failure. */ public function delete(string $key): Promise; } <?php namespace Amp\Cache; use Amp\Promise; use Amp\Success; /** * Cache implementation that just ignores all operations and always resolves to `null`. */ class NullCache implements Cache { /** @inheritdoc */ public function get(string $key): Promise { return new Success; } /** @inheritdoc */ public function set(string $key, string $value, int $ttl = null): Promise { return new Success; } /** @inheritdoc */ public function delete(string $key): Promise { return new Success(false); } } <?php /** * Pure-PHP implementation of Twofish. * * Uses mcrypt, if available, and an internal implementation, otherwise. * * PHP version 5 * * Useful resources are as follows: * * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish} * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $twofish = new \phpseclib\Crypt\Twofish(); * * $twofish->setKey('12345678901234567890123456789012'); * * $plaintext = str_repeat('a', 1024); * * echo $twofish->decrypt($twofish->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package Twofish * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\BlockCipher; use phpseclib\Exception\BadModeException; /** * Pure-PHP implementation of Twofish. * * @package Twofish * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @access public */ class Twofish extends BlockCipher { /** * The mcrypt specific name of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @var string * @access private */ protected $cipher_name_mcrypt = 'twofish'; /** * Optimizing value while CFB-encrypting * * @see \phpseclib\Crypt\Common\SymmetricKey::cfb_init_len * @var int * @access private */ protected $cfb_init_len = 800; /** * Q-Table * * @var array * @access private */ private static $q0 = [ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 ]; /** * Q-Table * * @var array * @access private */ private static $q1 = [ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 ]; /** * M-Table * * @var array * @access private */ private static $m0 = [ 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 ]; /** * M-Table * * @var array * @access private */ private static $m1 = [ 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 ]; /** * M-Table * * @var array * @access private */ private static $m2 = [ 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF ]; /** * M-Table * * @var array * @access private */ private static $m3 = [ 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 ]; /** * The Key Schedule Array * * @var array * @access private */ private $K = []; /** * The Key depended S-Table 0 * * @var array * @access private */ private $S0 = []; /** * The Key depended S-Table 1 * * @var array * @access private */ private $S1 = []; /** * The Key depended S-Table 2 * * @var array * @access private */ private $S2 = []; /** * The Key depended S-Table 3 * * @var array * @access private */ private $S3 = []; /** * Holds the last used key * * @var array * @access private */ private $kl; /** * The Key Length (in bytes) * * @see Crypt_Twofish::setKeyLength() * @var int * @access private */ protected $key_length = 16; /** * Default Constructor. * * @param int $mode * @access public * @throws BadModeException if an invalid / unsupported mode is provided */ public function __construct($mode) { if ($mode == self::MODE_STREAM) { throw new BadModeException('Block ciphers cannot be ran in stream mode'); } parent::__construct($mode); } /** * Sets the key length. * * Valid key lengths are 128, 192 or 256 bits * * @access public * @param int $length */ public function setKeyLength($length) { switch ($length) { case 128: case 192: case 256: break; default: throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported'); } parent::setKeyLength($length); } /** * Sets the key. * * Rijndael supports five different key lengths * * @see setKeyLength() * @access public * @param string $key * @throws \LengthException if the key length isn't supported */ public function setKey($key) { switch (strlen($key)) { case 16: case 24: case 32: break; default: throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported'); } parent::setKey($key); } /** * Setup the key (expansion) * * @see \phpseclib\Crypt\Common\SymmetricKey::_setupKey() * @access private */ protected function setupKey() { if (isset($this->kl['key']) && $this->key === $this->kl['key']) { // already expanded return; } $this->kl = ['key' => $this->key]; /* Key expanding and generating the key-depended s-boxes */ $le_longs = unpack('V*', $this->key); $key = unpack('C*', $this->key); $m0 = self::$m0; $m1 = self::$m1; $m2 = self::$m2; $m3 = self::$m3; $q0 = self::$q0; $q1 = self::$q1; $K = $S0 = $S1 = $S2 = $S3 = []; switch (strlen($this->key)) { case 16: list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[1], $le_longs[2]); list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[3], $le_longs[4]); for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^ $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^ $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^ $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]]; $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^ $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^ $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^ $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]]; $B = ($B << 8) | ($B >> 24 & 0xff); $A = self::safe_intval($A + $B); $K[] = $A; $A = self::safe_intval($A + $B); $K[] = ($A << 9 | $A >> 23 & 0x1ff); } for ($i = 0; $i < 256; ++$i) { $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0]; $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1]; $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2]; $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3]; } break; case 24: list($sb, $sa, $s9, $s8) = $this->mdsrem($le_longs[1], $le_longs[2]); list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[3], $le_longs[4]); list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[5], $le_longs[6]); for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^ $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]]; $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^ $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^ $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^ $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]]; $B = ($B << 8) | ($B >> 24 & 0xff); $A = self::safe_intval($A + $B); $K[] = $A; $A = self::safe_intval($A + $B); $K[] = ($A << 9 | $A >> 23 & 0x1ff); } for ($i = 0; $i < 256; ++$i) { $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0]; $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1]; $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2]; $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3]; } break; default: // 32 list($sf, $se, $sd, $sc) = $this->mdsrem($le_longs[1], $le_longs[2]); list($sb, $sa, $s9, $s8) = $this->mdsrem($le_longs[3], $le_longs[4]); list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[5], $le_longs[6]); list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[7], $le_longs[8]); for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) { $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^ $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^ $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^ $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]]; $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^ $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^ $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^ $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]]; $B = ($B << 8) | ($B >> 24 & 0xff); $A = self::safe_intval($A + $B); $K[] = $A; $A = self::safe_intval($A + $B); $K[] = ($A << 9 | $A >> 23 & 0x1ff); } for ($i = 0; $i < 256; ++$i) { $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0]; $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1]; $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2]; $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3]; } } $this->K = $K; $this->S0 = $S0; $this->S1 = $S1; $this->S2 = $S2; $this->S3 = $S3; } /** * _mdsrem function using by the twofish cipher algorithm * * @access private * @param string $A * @param string $B * @return array */ private function mdsrem($A, $B) { // No gain by unrolling this loop. for ($i = 0; $i < 8; ++$i) { // Get most significant coefficient. $t = 0xff & ($B >> 24); // Shift the others up. $B = ($B << 8) | (0xff & ($A >> 24)); $A<<= 8; $u = $t << 1; // Subtract the modular polynomial on overflow. if ($t & 0x80) { $u^= 0x14d; } // Remove t * (a * x^2 + 1). $B ^= $t ^ ($u << 16); // Form u = a*t + t/a = t*(a + 1/a). $u^= 0x7fffffff & ($t >> 1); // Add the modular polynomial on underflow. if ($t & 0x01) { $u^= 0xa6 ; } // Remove t * (a + 1/a) * (x^3 + x). $B^= ($u << 24) | ($u << 8); } return [ 0xff & $B >> 24, 0xff & $B >> 16, 0xff & $B >> 8, 0xff & $B]; } /** * Encrypts a block * * @access private * @param string $in * @return string */ protected function encryptBlock($in) { $S0 = $this->S0; $S1 = $this->S1; $S2 = $this->S2; $S3 = $this->S3; $K = $this->K; $in = unpack("V4", $in); $R0 = $K[0] ^ $in[1]; $R1 = $K[1] ^ $in[2]; $R2 = $K[2] ^ $in[3]; $R3 = $K[3] ^ $in[4]; $ki = 7; while ($ki < 39) { $t0 = $S0[ $R0 & 0xff] ^ $S1[($R0 >> 8) & 0xff] ^ $S2[($R0 >> 16) & 0xff] ^ $S3[($R0 >> 24) & 0xff]; $t1 = $S0[($R1 >> 24) & 0xff] ^ $S1[ $R1 & 0xff] ^ $S2[($R1 >> 8) & 0xff] ^ $S3[($R1 >> 16) & 0xff]; $R2^= self::safe_intval($t0 + $t1 + $K[++$ki]); $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ self::safe_intval($t0 + ($t1 << 1) + $K[++$ki]); $t0 = $S0[ $R2 & 0xff] ^ $S1[($R2 >> 8) & 0xff] ^ $S2[($R2 >> 16) & 0xff] ^ $S3[($R2 >> 24) & 0xff]; $t1 = $S0[($R3 >> 24) & 0xff] ^ $S1[ $R3 & 0xff] ^ $S2[($R3 >> 8) & 0xff] ^ $S3[($R3 >> 16) & 0xff]; $R0^= self::safe_intval($t0 + $t1 + $K[++$ki]); $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ self::safe_intval($t0 + ($t1 << 1) + $K[++$ki]); } // @codingStandardsIgnoreStart return pack("V4", $K[4] ^ $R2, $K[5] ^ $R3, $K[6] ^ $R0, $K[7] ^ $R1); // @codingStandardsIgnoreEnd } /** * Decrypts a block * * @access private * @param string $in * @return string */ protected function decryptBlock($in) { $S0 = $this->S0; $S1 = $this->S1; $S2 = $this->S2; $S3 = $this->S3; $K = $this->K; $in = unpack("V4", $in); $R0 = $K[4] ^ $in[1]; $R1 = $K[5] ^ $in[2]; $R2 = $K[6] ^ $in[3]; $R3 = $K[7] ^ $in[4]; $ki = 40; while ($ki > 8) { $t0 = $S0[$R0 & 0xff] ^ $S1[$R0 >> 8 & 0xff] ^ $S2[$R0 >> 16 & 0xff] ^ $S3[$R0 >> 24 & 0xff]; $t1 = $S0[$R1 >> 24 & 0xff] ^ $S1[$R1 & 0xff] ^ $S2[$R1 >> 8 & 0xff] ^ $S3[$R1 >> 16 & 0xff]; $R3^= self::safe_intval($t0 + ($t1 << 1) + $K[--$ki]); $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ self::safe_intval($t0 + $t1 + $K[--$ki]); $t0 = $S0[$R2 & 0xff] ^ $S1[$R2 >> 8 & 0xff] ^ $S2[$R2 >> 16 & 0xff] ^ $S3[$R2 >> 24 & 0xff]; $t1 = $S0[$R3 >> 24 & 0xff] ^ $S1[$R3 & 0xff] ^ $S2[$R3 >> 8 & 0xff] ^ $S3[$R3 >> 16 & 0xff]; $R1^= self::safe_intval($t0 + ($t1 << 1) + $K[--$ki]); $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ self::safe_intval($t0 + $t1 + $K[--$ki]); } // @codingStandardsIgnoreStart return pack("V4", $K[0] ^ $R2, $K[1] ^ $R3, $K[2] ^ $R0, $K[3] ^ $R1); // @codingStandardsIgnoreEnd } /** * Setup the performance-optimized function for de/encrypt() * * @see \phpseclib\Crypt\Common\SymmetricKey::_setupInlineCrypt() * @access private */ protected function setupInlineCrypt() { $K = $this->K; $init_crypt = ' static $S0, $S1, $S2, $S3; if (!$S0) { for ($i = 0; $i < 256; ++$i) { $S0[] = (int)$this->S0[$i]; $S1[] = (int)$this->S1[$i]; $S2[] = (int)$this->S2[$i]; $S3[] = (int)$this->S3[$i]; } } '; $safeint = self::safe_intval_inline(); // Generating encrypt code: $encrypt_block = ' $in = unpack("V4", $in); $R0 = '.$K[0].' ^ $in[1]; $R1 = '.$K[1].' ^ $in[2]; $R2 = '.$K[2].' ^ $in[3]; $R3 = '.$K[3].' ^ $in[4]; '; for ($ki = 7, $i = 0; $i < 8; ++$i) { $encrypt_block.= ' $t0 = $S0[ $R0 & 0xff] ^ $S1[($R0 >> 8) & 0xff] ^ $S2[($R0 >> 16) & 0xff] ^ $S3[($R0 >> 24) & 0xff]; $t1 = $S0[($R1 >> 24) & 0xff] ^ $S1[ $R1 & 0xff] ^ $S2[($R1 >> 8) & 0xff] ^ $S3[($R1 >> 16) & 0xff]; $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . '; $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . '; $t0 = $S0[ $R2 & 0xff] ^ $S1[($R2 >> 8) & 0xff] ^ $S2[($R2 >> 16) & 0xff] ^ $S3[($R2 >> 24) & 0xff]; $t1 = $S0[($R3 >> 24) & 0xff] ^ $S1[ $R3 & 0xff] ^ $S2[($R3 >> 8) & 0xff] ^ $S3[($R3 >> 16) & 0xff]; $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . '; $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . '; '; } $encrypt_block.= ' $in = pack("V4", '.$K[4].' ^ $R2, '.$K[5].' ^ $R3, '.$K[6].' ^ $R0, '.$K[7].' ^ $R1); '; // Generating decrypt code: $decrypt_block = ' $in = unpack("V4", $in); $R0 = '.$K[4].' ^ $in[1]; $R1 = '.$K[5].' ^ $in[2]; $R2 = '.$K[6].' ^ $in[3]; $R3 = '.$K[7].' ^ $in[4]; '; for ($ki = 40, $i = 0; $i < 8; ++$i) { $decrypt_block.= ' $t0 = $S0[$R0 & 0xff] ^ $S1[$R0 >> 8 & 0xff] ^ $S2[$R0 >> 16 & 0xff] ^ $S3[$R0 >> 24 & 0xff]; $t1 = $S0[$R1 >> 24 & 0xff] ^ $S1[$R1 & 0xff] ^ $S2[$R1 >> 8 & 0xff] ^ $S3[$R1 >> 16 & 0xff]; $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . '; $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . '; $t0 = $S0[$R2 & 0xff] ^ $S1[$R2 >> 8 & 0xff] ^ $S2[$R2 >> 16 & 0xff] ^ $S3[$R2 >> 24 & 0xff]; $t1 = $S0[$R3 >> 24 & 0xff] ^ $S1[$R3 & 0xff] ^ $S2[$R3 >> 8 & 0xff] ^ $S3[$R3 >> 16 & 0xff]; $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . '; $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . '; '; } $decrypt_block.= ' $in = pack("V4", '.$K[0].' ^ $R2, '.$K[1].' ^ $R3, '.$K[2].' ^ $R0, '.$K[3].' ^ $R1); '; $this->inline_crypt = $this->createInlineCryptFunction( [ 'init_crypt' => $init_crypt, 'init_encrypt' => '', 'init_decrypt' => '', 'encrypt_block' => $encrypt_block, 'decrypt_block' => $decrypt_block ] ); } } <?php /** * Pure-PHP implementation of AES. * * Uses mcrypt, if available/possible, and an internal implementation, otherwise. * * PHP version 5 * * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of * to save one include_once(). * * If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()} * is called, again, at which point, it'll be recalculated. * * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, some functions are available to be called that, in the context of AES, don't * make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function, * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one). * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $aes = new \phpseclib\Crypt\AES(); * * $aes->setKey('abcdefghijklmnop'); * * $size = 10 * 1024; * $plaintext = ''; * for ($i = 0; $i < $size; $i++) { * $plaintext.= 'a'; * } * * echo $aes->decrypt($aes->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package AES * @author Jim Wigginton <terrafrost@php.net> * @copyright 2008 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; /** * Pure-PHP implementation of AES. * * @package AES * @author Jim Wigginton <terrafrost@php.net> * @access public */ class AES extends Rijndael { /** * Dummy function * * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything. * * @see \phpseclib\Crypt\Rijndael::setBlockLength() * @access public * @param int $length * @throws \BadMethodCallException anytime it's called */ public function setBlockLength($length) { throw new \BadMethodCallException('The block length cannot be set for AES.'); } /** * Sets the key length * * Valid key lengths are 128, 192, and 256. Set the link to bool(false) to disable a fixed key length * * @see \phpseclib\Crypt\Rijndael:setKeyLength() * @access public * @param int $length * @throws \LengthException if the key length isn't supported */ public function setKeyLength($length) { switch ($length) { case 128: case 192: case 256: break; default: throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported'); } parent::setKeyLength($length); } /** * Sets the key. * * Rijndael supports five different key lengths, AES only supports three. * * @see \phpseclib\Crypt\Rijndael:setKey() * @see setKeyLength() * @access public * @param string $key * @throws \LengthException if the key length isn't supported */ public function setKey($key) { switch (strlen($key)) { case 16: case 24: case 32: break; default: throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported'); } parent::setKey($key); } } <?php /** * Pure-PHP implementation of Triple DES. * * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt). * * PHP version 5 * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $des = new \phpseclib\Crypt\TripleDES(); * * $des->setKey('abcdefghijklmnopqrstuvwx'); * * $size = 10 * 1024; * $plaintext = ''; * for ($i = 0; $i < $size; $i++) { * $plaintext.= 'a'; * } * * echo $des->decrypt($des->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package TripleDES * @author Jim Wigginton <terrafrost@php.net> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; /** * Pure-PHP implementation of Triple DES. * * @package TripleDES * @author Jim Wigginton <terrafrost@php.net> * @access public */ class TripleDES extends DES { /** * Encrypt / decrypt using inner chaining * * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (self::MODE_CBC3). */ const MODE_3CBC = -2; /** * Encrypt / decrypt using outer chaining * * Outer chaining is used by SSH-2 and when the mode is set to \phpseclib\Crypt\Common\BlockCipher::MODE_CBC. */ const MODE_CBC3 = self::MODE_CBC; /** * Key Length (in bytes) * * @see \phpseclib\Crypt\TripleDES::setKeyLength() * @var int * @access private */ protected $key_length = 24; /** * The mcrypt specific name of the cipher * * @see \phpseclib\Crypt\DES::cipher_name_mcrypt * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @var string * @access private */ protected $cipher_name_mcrypt = 'tripledes'; /** * Optimizing value while CFB-encrypting * * @see \phpseclib\Crypt\Common\SymmetricKey::cfb_init_len * @var int * @access private */ protected $cfb_init_len = 750; /** * max possible size of $key * * @see self::setKey() * @see \phpseclib\Crypt\DES::setKey() * @var string * @access private */ protected $key_length_max = 24; /** * Internal flag whether using self::MODE_3CBC or not * * @var bool * @access private */ private $mode_3cbc; /** * The \phpseclib\Crypt\DES objects * * Used only if $mode_3cbc === true * * @var array * @access private */ private $des; /** * Default Constructor. * * Determines whether or not the mcrypt or OpenSSL extensions should be used. * * $mode could be: * * - ecb * * - cbc * * - ctr * * - cfb * * - ofb * * - 3cbc * * - cbc3 (same as cbc) * * @see \phpseclib\Crypt\DES::__construct() * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @param int $mode * @access public */ public function __construct($mode) { switch (strtolower($mode)) { // In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC // and additional flag us internally as 3CBC case '3cbc': $mode = self::MODE_3CBC; parent::__construct('cbc'); $this->mode_3cbc = true; // This three $des'es will do the 3CBC work (if $key > 64bits) $this->des = [ new DES('cbc'), new DES('cbc'), new DES('cbc'), ]; // we're going to be doing the padding, ourselves, so disable it in the \phpseclib\Crypt\DES objects $this->des[0]->disablePadding(); $this->des[1]->disablePadding(); $this->des[2]->disablePadding(); break; case 'cbc3': $mode = 'cbc'; // If not 3CBC, we init as usual default: parent::__construct($mode); } } /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { if ($engine == self::ENGINE_OPENSSL) { self::$cipher_name_openssl_ecb = 'des-ede3'; $mode = $this->openssl_translate_mode(); $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode; } return parent::isValidEngineHelper($engine); } /** * Sets the initialization vector. * * SetIV is not required when \phpseclib\Crypt\Common\SymmetricKey::MODE_ECB is being used. * * @see \phpseclib\Crypt\Common\SymmetricKey::setIV() * @access public * @param string $iv */ public function setIV($iv) { parent::setIV($iv); if ($this->mode_3cbc) { $this->des[0]->setIV($iv); $this->des[1]->setIV($iv); $this->des[2]->setIV($iv); } } /** * Sets the key length. * * Valid key lengths are 128 and 192 bits. * * If you want to use a 64-bit key use DES.php * * @see \phpseclib\Crypt\Common\SymmetricKey:setKeyLength() * @access public * @throws \LengthException if the key length is invalid * @param int $length */ public function setKeyLength($length) { switch ($length) { case 128: case 192: break; default: throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128 or 192 bits are supported'); } parent::setKeyLength($length); } /** * Sets the key. * * Triple DES can use 128-bit (eg. strlen($key) == 16) or 192-bit (eg. strlen($key) == 24) keys. * * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. * * @access public * @see \phpseclib\Crypt\DES::setKey() * @see \phpseclib\Crypt\Common\SymmetricKey::setKey() * @throws \LengthException if the key length is invalid * @param string $key */ public function setKey($key) { if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) { throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes'); } switch (strlen($key)) { case 16: $key.= substr($key, 0, 8); break; case 24: break; default: throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported'); } // copied from self::setKey() $this->key = $key; $this->key_length = strlen($key); $this->changed = true; $this->setEngine(); if ($this->mode_3cbc) { $this->des[0]->setKey(substr($key, 0, 8)); $this->des[1]->setKey(substr($key, 8, 8)); $this->des[2]->setKey(substr($key, 16, 8)); } } /** * Encrypts a message. * * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @access public * @param string $plaintext * @return string $cipertext */ public function encrypt($plaintext) { // parent::en/decrypt() is able to do all the work for all modes and keylengths, // except for: self::MODE_3CBC (inner chaining CBC) with a key > 64bits // if the key is smaller then 8, do what we'd normally do if ($this->mode_3cbc && strlen($this->key) > 8) { return $this->des[2]->encrypt( $this->des[1]->decrypt( $this->des[0]->encrypt( $this->pad($plaintext) ) ) ); } return parent::encrypt($plaintext); } /** * Decrypts a message. * * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() * @access public * @param string $ciphertext * @return string $plaintext */ public function decrypt($ciphertext) { if ($this->mode_3cbc && strlen($this->key) > 8) { return $this->unpad( $this->des[0]->decrypt( $this->des[1]->encrypt( $this->des[2]->decrypt( str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0") ) ) ) ); } return parent::decrypt($ciphertext); } /** * Treat consecutive "packets" as if they are a continuous buffer. * * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets * will yield different outputs: * * <code> * echo $des->encrypt(substr($plaintext, 0, 8)); * echo $des->encrypt(substr($plaintext, 8, 8)); * </code> * <code> * echo $des->encrypt($plaintext); * </code> * * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates * another, as demonstrated with the following: * * <code> * $des->encrypt(substr($plaintext, 0, 8)); * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); * </code> * <code> * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); * </code> * * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different * outputs. The reason is due to the fact that the initialization vector's change after every encryption / * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. * * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\DES() object changes after each * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), * however, they are also less intuitive and more likely to cause you problems. * * @see \phpseclib\Crypt\Common\SymmetricKey::enableContinuousBuffer() * @see self::disableContinuousBuffer() * @access public */ public function enableContinuousBuffer() { parent::enableContinuousBuffer(); if ($this->mode_3cbc) { $this->des[0]->enableContinuousBuffer(); $this->des[1]->enableContinuousBuffer(); $this->des[2]->enableContinuousBuffer(); } } /** * Treat consecutive packets as if they are a discontinuous buffer. * * The default behavior. * * @see \phpseclib\Crypt\Common\SymmetricKey::disableContinuousBuffer() * @see self::enableContinuousBuffer() * @access public */ public function disableContinuousBuffer() { parent::disableContinuousBuffer(); if ($this->mode_3cbc) { $this->des[0]->disableContinuousBuffer(); $this->des[1]->disableContinuousBuffer(); $this->des[2]->disableContinuousBuffer(); } } /** * Creates the key schedule * * @see \phpseclib\Crypt\DES::setupKey() * @see \phpseclib\Crypt\Common\SymmetricKey::setupKey() * @access private */ protected function setupKey() { switch (true) { // if $key <= 64bits we configure our internal pure-php cipher engine // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same. case strlen($this->key) <= 8: $this->des_rounds = 1; break; // otherwise, if $key > 64bits, we configure our engine to work as 3DES. default: $this->des_rounds = 3; // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately. if ($this->mode_3cbc) { $this->des[0]->setupKey(); $this->des[1]->setupKey(); $this->des[2]->setupKey(); // because $des[0-2] will, now, do all the work we can return here // not need unnecessary stress parent::setupKey() with our, now unused, $key. return; } } // setup our key parent::setupKey(); } /** * Sets the internal crypt engine * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @see \phpseclib\Crypt\Common\SymmetricKey::setPreferredEngine() * @param int $engine * @access public */ public function setPreferredEngine($engine) { if ($this->mode_3cbc) { $this->des[0]->setPreferredEngine($engine); $this->des[1]->setPreferredEngine($engine); $this->des[2]->setPreferredEngine($engine); } parent::setPreferredEngine($engine); } } <?php /** * Pure-PHP implementation of Salsa20. * * PHP version 5 * * @category Crypt * @package Salsa20 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2019 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\StreamCipher; use phpseclib\Exception\InsufficientSetupException; use phpseclib\Exception\BadDecryptionException; use phpseclib\Common\Functions\Strings; /** * Pure-PHP implementation of Salsa20. * * @package Salsa20 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Salsa20 extends StreamCipher { /** * Part 1 of the state * * @var string|false */ protected $p1 = false; /** * Part 2 of the state * * @var string|false */ protected $p2 = false; /** * Key Length (in bytes) * * @var int */ protected $key_length = 32; // = 256 bits /** * Block Length of the cipher * * Salsa20 is a stream cipher * so we the block_size to 0 * * @var int */ protected $block_size = 0; /**#@+ * @access private * @see \phpseclib\Crypt\Salsa20::crypt() */ const ENCRYPT = 0; const DECRYPT = 1; /**#@-*/ /** * Encryption buffer for continuous mode * * @var array */ protected $enbuffer; /** * Decryption buffer for continuous mode * * @var array */ protected $debuffer; /** * Counter * * @var int */ protected $counter = 0; /** * Using Generated Poly1305 Key * * @var boolean */ protected $usingGeneratedPoly1305Key = false; /** * Default Constructor. * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @return \phpseclib\Crypt\Salsa20 */ public function __construct() { parent::__construct('stream'); } /** * Salsa20 does not use an IV * * @return bool */ public function usesIV() { return false; } /** * Salsa20 uses a nonce * * @return bool */ public function usesNonce() { return true; } /** * Sets the key. * * @param string $key * @throws \LengthException if the key length isn't supported */ public function setKey($key) { switch (strlen($key)) { case 16: case 32: break; default: throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 32 are supported'); } parent::setKey($key); } /** * Sets the nonce. * * @param string $nonce */ public function setNonce($nonce) { if (strlen($nonce) != 8) { throw new \LengthException('Nonce of size ' . strlen($key) . ' not supported by this algorithm. Only an 64-bit nonce is supported'); } $this->nonce = $nonce; $this->changed = true; $this->setEngine(); } /** * Sets the counter. * * @param int $counter */ public function setCounter($counter) { $this->counter = $counter; $this->setEngine(); } /** * Creates a Poly1305 key using the method discussed in RFC8439 * * See https://tools.ietf.org/html/rfc8439#section-2.6.1 */ protected function createPoly1305Key() { if ($this->nonce === false) { throw new InsufficientSetupException('No nonce has been defined'); } if ($this->key === false) { throw new InsufficientSetupException('No key has been defined'); } $c = clone $this; $c->setCounter(0); $c->usePoly1305 = false; $block = $c->encrypt(str_repeat("\0", 256)); $this->setPoly1305Key(substr($block, 0, 32)); if ($this->counter == 0) { $this->counter++; } } /** * Setup the self::ENGINE_INTERNAL $engine * * (re)init, if necessary, the internal cipher $engine * * _setup() will be called each time if $changed === true * typically this happens when using one or more of following public methods: * * - setKey() * * - setNonce() * * - First run of encrypt() / decrypt() with no init-settings * * @see self::setKey() * @see self::setNonce() * @see self::disableContinuousBuffer() */ protected function setup() { if (!$this->changed) { return; } $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'counter' => $this->counter]; $this->changed = false; if ($this->nonce === false) { throw new InsufficientSetupException('No nonce has been defined'); } if ($this->key === false) { throw new InsufficientSetupException('No key has been defined'); } if ($this->usePoly1305 && !isset($this->poly1305Key)) { $this->usingGeneratedPoly1305Key = true; $this->createPoly1305Key(); } $key = $this->key; if (strlen($key) == 16) { $constant = 'expand 16-byte k'; $key.= $key; } else { $constant = 'expand 32-byte k'; } $this->p1 = substr($constant, 0, 4) . substr($key, 0, 16) . substr($constant, 4, 4) . $this->nonce . "\0\0\0\0"; $this->p2 = substr($constant, 8, 4) . substr($key, 16, 16) . substr($constant, 12, 4); } /** * Setup the key (expansion) */ protected function setupKey() { // Salsa20 does not utilize this method } /** * Encrypts a message. * * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() * @see self::crypt() * @param string $plaintext * @return string $ciphertext */ public function encrypt($plaintext) { $ciphertext = $this->crypt($plaintext, self::ENCRYPT); if (isset($this->poly1305Key)) { $this->newtag = $this->poly1305($ciphertext); } return $ciphertext; } /** * Decrypts a message. * * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * At least if the continuous buffer is disabled. * * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @see self::crypt() * @param string $ciphertext * @return string $plaintext */ public function decrypt($ciphertext) { if (isset($this->poly1305Key)) { if ($this->oldtag === false) { throw new InsufficientSetupException('Authentication Tag has not been set'); } $newtag = $this->poly1305($ciphertext); if ($this->oldtag != substr($newtag, 0, strlen($this->oldtag))) { $this->oldtag = false; throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match'); } $this->oldtag = false; } return $this->crypt($ciphertext, self::DECRYPT); } /** * Encrypts a block * * @param string $in */ protected function encryptBlock($in) { // Salsa20 does not utilize this method } /** * Decrypts a block * * @param string $in */ protected function decryptBlock($in) { // Salsa20 does not utilize this method } /** * Encrypts or decrypts a message. * * @see self::encrypt() * @see self::decrypt() * @param string $text * @param int $mode * @return string $text */ private function crypt($text, $mode) { $this->setup(); if (!$this->continuousBuffer) { if ($this->engine == self::ENGINE_OPENSSL) { $iv = pack('V', $this->counter) . $this->p2; return openssl_encrypt( $text, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA, $iv ); } $i = $this->counter; $blocks = str_split($text, 64); foreach ($blocks as &$block) { $block^= static::salsa20($this->p1 . pack('V', $i++) . $this->p2); } return implode('', $blocks); } if ($mode == self::ENCRYPT) { $buffer = &$this->enbuffer; } else { $buffer = &$this->debuffer; } if (strlen($buffer['ciphertext'])) { $ciphertext = $text ^ Strings::shift($buffer['ciphertext'], strlen($text)); $text = substr($text, strlen($ciphertext)); if (!strlen($text)) { return $ciphertext; } } $overflow = strlen($text) % 64; // & 0x3F if ($overflow) { $text2 = Strings::pop($text, $overflow); if ($this->engine == self::ENGINE_OPENSSL) { $iv = pack('V', $buffer['counter']) . $this->p2; // at this point $text should be a multiple of 64 $buffer['counter']+= (strlen($text) >> 6) + 1; // ie. divide by 64 $encrypted = openssl_encrypt( $text . str_repeat("\0", 64), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA, $iv ); $temp = Strings::pop($encrypted, 64); } else { $blocks = str_split($text, 64); if (strlen($text)) { foreach ($blocks as &$block) { $block^= static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2); } } $encrypted = implode('', $blocks); $temp = static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2); } $ciphertext.= $encrypted . ($text2 ^ $temp); $buffer['ciphertext'] = substr($temp, $overflow); } elseif (!strlen($buffer['ciphertext'])) { if ($this->engine == self::ENGINE_OPENSSL) { $iv = pack('V', $buffer['counter']) . $this->p2; $buffer['counter']+= (strlen($text) >> 6); $ciphertext.= openssl_encrypt( $text, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA, $iv ); } else { $blocks = str_split($text, 64); foreach ($blocks as &$block) { $block^= static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2); } $ciphertext.= implode('', $blocks); } } return $ciphertext; } /** * Left Rotate * * @param int $x * @param int $n * @return int */ protected static function leftRotate($x, $n) { $r1 = $x << $n; if (PHP_INT_SIZE == 8) { $r1&= 0xFFFFFFFF; $r2 = ($x & 0xFFFFFFFF) >> (32 - $n); } else { $r2 = $x >> (32 - $n); $r2&= (1 << $n) - 1; } return $r1 | $r2; } /** * The quarterround function * * @param int $a * @param int $b * @param int $c * @param int $d */ protected static function quarterRound(&$a, &$b, &$c, &$d) { $b^= self::leftRotate($a + $d, 7); $c^= self::leftRotate($b + $a, 9); $d^= self::leftRotate($c + $b, 13); $a^= self::leftRotate($d + $c, 18); } /** * The doubleround function * * @param int $x0...$x16 */ protected static function doubleRound(&$x0, &$x1, &$x2, &$x3, &$x4, &$x5, &$x6, &$x7, &$x8, &$x9, &$x10, &$x11, &$x12, &$x13, &$x14, &$x15) { // columnRound static::quarterRound( $x0, $x4, $x8, $x12); static::quarterRound( $x5, $x9, $x13, $x1); static::quarterRound($x10, $x14, $x2, $x6); static::quarterRound($x15, $x3, $x7, $x11); // rowRound static::quarterRound( $x0, $x1, $x2, $x3); static::quarterRound( $x5, $x6, $x7, $x4); static::quarterRound($x10, $x11, $x8, $x9); static::quarterRound($x15, $x12, $x13, $x14); } /** * The Salsa20 hash function function * * @param string $x */ protected static function salsa20($x) { $z = $x = unpack('V*', $x); for ($i = 0; $i < 10; $i++) { static::doubleRound(...$z); } for ($i = 1; $i <= 16; $i++) { $x[$i]+= $z[$i]; } return pack('V*',...$x); } /** * Calculates Poly1305 MAC * * @see self::decrypt() * @see self::encrypt() * @access private * @param string $text * @return string */ protected function poly1305($ciphertext) { if (!$this->usingGeneratedPoly1305Key) { return parent::poly1305($this->aad . $ciphertext); } else { /* sodium_crypto_aead_chacha20poly1305_encrypt does not calculate the poly1305 tag the same way sodium_crypto_aead_chacha20poly1305_ietf_encrypt does. you can see how the latter encrypts it in Salsa20::encrypt(). here's how the former encrypts it: $this->newtag = $this->poly1305( $this->aad . pack('V', strlen($this->aad)) . "\0\0\0\0" . $ciphertext . pack('V', strlen($ciphertext)) . "\0\0\0\0" ); phpseclib opts to use the IETF construction, even when the nonce is 64-bits instead of 96-bits */ return parent::poly1305( self::nullPad128($this->aad) . self::nullPad128($ciphertext) . pack('V', strlen($this->aad)) . "\0\0\0\0" . pack('V', strlen($ciphertext)) . "\0\0\0\0" ); } } } <?php /** * RSA Private Key * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA; use phpseclib\Crypt\RSA; use phpseclib\Math\BigInteger; use phpseclib\File\ASN1; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Hash; use phpseclib\Exceptions\NoKeyLoadedException; use phpseclib\Exception\UnsupportedFormatException; use phpseclib\Crypt\Random; use phpseclib\Crypt\Common; use phpseclib\Crypt\RSA\Keys\PSS; /** * Raw RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PrivateKey extends RSA implements Common\PrivateKey { use Common\PasswordProtected; /** * Primes for Chinese Remainder Theorem (ie. p and q) * * @var array * @access private */ protected $primes; /** * Exponents for Chinese Remainder Theorem (ie. dP and dQ) * * @var array * @access private */ protected $exponents; /** * Coefficients for Chinese Remainder Theorem (ie. qInv) * * @var array * @access private */ protected $coefficients; /** * Public Exponent * * @var mixed * @access private */ protected $publicExponent = false; /** * RSADP * * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}. * * @access private * @param \phpseclib\Math\BigInteger $c * @return bool|\phpseclib\Math\BigInteger */ private function rsadp($c) { if ($c->compare(self::$zero) < 0 || $c->compare($this->modulus) > 0) { return false; } return $this->exponentiate($c); } /** * RSASP1 * * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}. * * @access private * @param \phpseclib\Math\BigInteger $m * @return bool|\phpseclib\Math\BigInteger */ private function rsasp1($m) { if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) { return false; } return $this->exponentiate($m); } /** * Exponentiate * * @param \phpseclib\Math\BigInteger $x * @return \phpseclib\Math\BigInteger */ protected function exponentiate(BigInteger $x) { switch (true) { case empty($this->primes): case $this->primes[1]->equals(self::$zero): case empty($this->coefficients): case $this->coefficients[2]->equals(self::$zero): case empty($this->exponents): case $this->exponents[1]->equals(self::$zero): return $x->modPow($this->exponent, $this->modulus); } $num_primes = count($this->primes); if (!static::$enableBlinding) { $m_i = [ 1 => $x->modPow($this->exponents[1], $this->primes[1]), 2 => $x->modPow($this->exponents[2], $this->primes[2]) ]; $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } else { $smallest = $this->primes[1]; for ($i = 2; $i <= $num_primes; $i++) { if ($smallest->compare($this->primes[$i]) > 0) { $smallest = $this->primes[$i]; } } $r = BigInteger::randomRange(self::$one, $smallest->subtract(self::$one)); $m_i = [ 1 => $this->blind($x, $r, 1), 2 => $this->blind($x, $r, 2) ]; $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $this->blind($x, $r, $i); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } return $m; } /** * Performs RSA Blinding * * Protects against timing attacks by employing RSA Blinding. * Returns $x->modPow($this->exponents[$i], $this->primes[$i]) * * @access private * @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $r * @param int $i * @return \phpseclib\Math\BigInteger */ private function blind($x, $r, $i) { $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); $x = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->modInverse($this->primes[$i]); $x = $x->multiply($r); list(, $x) = $x->divide($this->primes[$i]); return $x; } /** * EMSA-PSS-ENCODE * * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}. * * @return string * @access private * @param string $m * @throws \RuntimeException on encoding error * @param int $emBits */ private function emsa_pss_encode($m, $emBits) { // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { return false; } $salt = Random::string($sLen); $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h = $this->hash->hash($m2); $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2); $db = $ps . chr(1) . $salt; $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; $em = $maskedDB . $h . chr(0xBC); return $em; } /** * RSASSA-PSS-SIGN * * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}. * * @access private * @param string $m * @return bool|string */ private function rsassa_pss_sign($m) { // EMSA-PSS encoding $em = $this->emsa_pss_encode($m, 8 * $this->k - 1); // RSA signature $m = $this->os2ip($em); $s = $this->rsasp1($m); $s = $this->i2osp($s, $this->k); // Output the signature S return $s; } /** * RSASSA-PKCS1-V1_5-SIGN * * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}. * * @access private * @param string $m * @throws \LengthException if the RSA modulus is too short * @return bool|string */ private function rsassa_pkcs1_v1_5_sign($m) { // EMSA-PKCS1-v1_5 encoding // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus // too short" and stop. try { $em = $this->emsa_pkcs1_v1_5_encode($m, $this->k); } catch (\LengthException $e) { throw new \LengthException('RSA modulus too short'); } // RSA signature $m = $this->os2ip($em); $s = $this->rsasp1($m); $s = $this->i2osp($s, $this->k); // Output the signature S return $s; } /** * Create a signature * * @see self::verify() * @access public * @param string $message * @return string */ public function sign($message) { switch ($this->signaturePadding) { case self::SIGNATURE_PKCS1: case self::SIGNATURE_RELAXED_PKCS1: return $this->rsassa_pkcs1_v1_5_sign($message); //case self::SIGNATURE_PSS: default: return $this->rsassa_pss_sign($message); } } /** * RSAES-PKCS1-V1_5-DECRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. * * For compatibility purposes, this function departs slightly from the description given in RFC3447. * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. * * As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but * not private key encrypted ciphertext's. * * @access private * @param string $c * @return bool|string */ private function rsaes_pkcs1_v1_5_decrypt($c) { // Length checking if (strlen($c) != $this->k) { // or if k < 11 return false; } // RSA decryption $c = $this->os2ip($c); $m = $this->rsadp($c); $em = $this->i2osp($m, $this->k); if ($em === false) { return false; } // EME-PKCS1-v1_5 decoding if (ord($em[0]) != 0 || ord($em[1]) > 2) { return false; } $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); $m = substr($em, strlen($ps) + 3); if (strlen($ps) < 8) { return false; } // Output M return $m; } /** * RSAES-OAEP-DECRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: * * Note. Care must be taken to ensure that an opponent cannot * distinguish the different error conditions in Step 3.g, whether by * error message or timing, or, more generally, learn partial * information about the encoded message EM. Otherwise an opponent may * be able to obtain useful information about the decryption of the * ciphertext C, leading to a chosen-ciphertext attack such as the one * observed by Manger [36]. * * @access private * @param string $c * @return bool|string */ private function rsaes_oaep_decrypt($c) { // Length checking // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { return false; } // RSA decryption $c = $this->os2ip($c); $m = $this->rsadp($c); $em = $this->i2osp($m, $this->k); if ($em === false) { return false; } // EME-OAEP decoding $lHash = $this->hash->hash($this->label); $y = ord($em[0]); $maskedSeed = substr($em, 1, $this->hLen); $maskedDB = substr($em, $this->hLen + 1); $seedMask = $this->mgf1($maskedDB, $this->hLen); $seed = $maskedSeed ^ $seedMask; $dbMask = $this->mgf1($seed, $this->k - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $lHash2 = substr($db, 0, $this->hLen); $m = substr($db, $this->hLen); $hashesMatch = hash_equals($lHash, $lHash2); $leadingZeros = 1; $patternMatch = 0; $offset = 0; for ($i = 0; $i < strlen($m); $i++) { $patternMatch|= $leadingZeros & ($m[$i] === "\1"); $leadingZeros&= $m[$i] === "\0"; $offset+= $patternMatch ? 0 : 1; } // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation // to protect against timing attacks if (!$hashesMatch & !$patternMatch) { return false; } // Output the message M return substr($m, $offset + 1); } /** * Raw Encryption / Decryption * * Doesn't use padding and is not recommended. * * @access private * @param string $m * @return bool|string * @throws \LengthException if strlen($m) > $this->k */ private function raw_encrypt($m) { if (strlen($m) > $this->k) { throw new \LengthException('Message too long'); } $temp = $this->os2ip($m); $temp = $this->rsadp($temp); return $this->i2osp($temp, $this->k); } /** * Decryption * * @see self::encrypt() * @access public * @param string $ciphertext * @param int $padding optional * @return bool|string */ public function decrypt($ciphertext) { switch ($this->encryptionPadding) { case self::ENCRYPTION_NONE: return $this->raw_encrypt($ciphertext); case self::ENCRYPTION_PKCS1: return $this->rsaes_pkcs1_v1_5_decrypt($ciphertext); //case self::ENCRYPTION_OAEP: default: return $this->rsaes_oaep_decrypt($ciphertext); } } /** * Returns the public key * * @access public * @param string $type optional * @return mixed */ public function getPublicKey() { $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey'); if (empty($this->modulus) || empty($this->publicExponent)) { return false; } $key = $type::savePublicKey($this->modulus, $this->publicExponent); return RSA::load($key, 'PKCS8') ->withHash($this->hash->getHash()) ->withMGFHash($this->mgfHash->getHash()) ->withSaltLength($this->sLen) ->withLabel($this->label) ->withPadding($this->signaturePadding | $this->encryptionPadding); } /** * Returns the private key * * @param string $type * @param array $options optional * @return string */ public function toString($type, array $options = []) { $type = self::validatePlugin( 'Keys', $type, empty($this->primes) ? 'savePublicKey' : 'savePrivateKey' ); if ($type == PSS::class) { if ($this->signaturePadding == self::SIGNATURE_PSS) { $options+= [ 'hash' => $this->hash->getHash(), 'MGFHash' => $this->mgfHash->getHash(), 'saltLength' => $this->sLen ]; } else { throw new UnsupportedFormatException('The PSS format can only be used when the signature method has been explicitly set to PSS'); } } if (empty($this->primes)) { return $type::savePublicKey($this->modulus, $this->exponent, $options); } return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options); /* $key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options); if ($key !== false || count($this->primes) == 2) { return $key; } $nSize = $this->getSize() >> 1; $primes = [1 => clone self::$one, clone self::$one]; $i = 1; foreach ($this->primes as $prime) { $primes[$i] = $primes[$i]->multiply($prime); if ($primes[$i]->getLength() >= $nSize) { $i++; } } $exponents = []; $coefficients = [2 => $primes[2]->modInverse($primes[1])]; foreach ($primes as $i => $prime) { $temp = $prime->subtract(self::$one); $exponents[$i] = $this->modulus->modInverse($temp); } return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password, $options); */ } } <?php /** * Miccrosoft BLOB Formatted RSA Key Handler * * More info: * * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx * * PHP version 5 * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; /** * Microsoft BLOB Formatted RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class MSBLOB { /**#@+ * @access private */ /** * Public/Private Key Pair */ const PRIVATEKEYBLOB = 0x7; /** * Public Key */ const PUBLICKEYBLOB = 0x6; /** * Public Key */ const PUBLICKEYBLOBEX = 0xA; /** * RSA public key exchange algorithm */ const CALG_RSA_KEYX = 0x0000A400; /** * RSA public key exchange algorithm */ const CALG_RSA_SIGN = 0x00002400; /** * Public Key */ const RSA1 = 0x31415352; /** * Private Key */ const RSA2 = 0x32415352; /**#@-*/ /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $key = Base64::decode($key); if (!is_string($key)) { throw new \UnexpectedValueException('Base64 decoding produced an error'); } if (strlen($key) < 20) { throw new \UnexpectedValueException('Key appears to be malformed'); } // PUBLICKEYSTRUC publickeystruc // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx extract(unpack('atype/aversion/vreserved/Valgo', Strings::shift($key, 8))); /** * @var string $type * @var string $version * @var integer $reserved * @var integer $algo */ switch (ord($type)) { case self::PUBLICKEYBLOB: case self::PUBLICKEYBLOBEX: $publickey = true; break; case self::PRIVATEKEYBLOB: $publickey = false; break; default: throw new \UnexpectedValueException('Key appears to be malformed'); } $components = ['isPublicKey' => $publickey]; // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx switch ($algo) { case self::CALG_RSA_KEYX: case self::CALG_RSA_SIGN: break; default: throw new \UnexpectedValueException('Key appears to be malformed'); } // RSAPUBKEY rsapubkey // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx // could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit extract(unpack('Vmagic/Vbitlen/a4pubexp', Strings::shift($key, 12))); /** * @var integer $magic * @var integer $bitlen * @var string $pubexp */ switch ($magic) { case self::RSA2: $components['isPublicKey'] = false; case self::RSA1: break; default: throw new \UnexpectedValueException('Key appears to be malformed'); } $baseLength = $bitlen / 16; if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) { throw new \UnexpectedValueException('Key appears to be malformed'); } $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256); // BYTE modulus[rsapubkey.bitlen/8] $components['modulus'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256); if ($publickey) { return $components; } $components['isPublicKey'] = false; // BYTE prime1[rsapubkey.bitlen/16] $components['primes'] = [1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)]; // BYTE prime2[rsapubkey.bitlen/16] $components['primes'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256); // BYTE exponent1[rsapubkey.bitlen/16] $components['exponents'] = [1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)]; // BYTE exponent2[rsapubkey.bitlen/16] $components['exponents'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256); // BYTE coefficient[rsapubkey.bitlen/16] $components['coefficients'] = [2 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)]; if (isset($components['privateExponent'])) { $components['publicExponent'] = $components['privateExponent']; } // BYTE privateExponent[rsapubkey.bitlen/8] $components['privateExponent'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256); return $components; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '') { if (count($primes) != 2) { throw new \InvalidArgumentException('MSBLOB does not support multi-prime RSA keys'); } $n = strrev($n->toBytes()); $e = str_pad(strrev($e->toBytes()), 4, "\0"); $key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX); $key.= pack('VVa*', self::RSA2, 8 * strlen($n), $e); $key.= $n; $key.= strrev($primes[1]->toBytes()); $key.= strrev($primes[2]->toBytes()); $key.= strrev($exponents[1]->toBytes()); $key.= strrev($exponents[2]->toBytes()); $key.= strrev($coefficients[1]->toBytes()); $key.= strrev($d->toBytes()); return Base64::encode($key); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e) { $n = strrev($n->toBytes()); $e = str_pad(strrev($e->toBytes()), 4, "\0"); $key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX); $key.= pack('VVa*', self::RSA1, 8 * strlen($n), $e); $key.= $n; return Base64::encode($key); } } <?php /** * Raw RSA Key Handler * * PHP version 5 * * An array containing two \phpseclib\Math\BigInteger objects. * * The exponent can be indexed with any of the following: * * 0, e, exponent, publicExponent * * The modulus can be indexed with any of the following: * * 1, n, modulo, modulus * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use phpseclib\Math\BigInteger; /** * Raw RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Raw { /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_array($key)) { throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key)); } if (isset($key['isPublicKey']) && isset($key['modulus'])) { if (isset($key['privateExponent']) || isset($key['publicExponent'])) { if (!isset($key['primes'])) { return $key; } if (isset($key['exponents']) && isset($key['coefficients']) && isset($key['publicExponent']) && isset($key['privateExponent'])) { return $key; } } } $components = ['isPublicKey' => true]; switch (true) { case isset($key['e']): $components['publicExponent'] = $key['e']; break; case isset($key['exponent']): $components['publicExponent'] = $key['exponent']; break; case isset($key['publicExponent']): $components['publicExponent'] = $key['publicExponent']; break; case isset($key[0]): $components['publicExponent'] = $key[0]; } switch (true) { case isset($key['n']): $components['modulus'] = $key['n']; break; case isset($key['modulo']): $components['modulus'] = $key['modulo']; break; case isset($key['modulus']): $components['modulus'] = $key['modulus']; break; case isset($key[1]): $components['modulus'] = $key[1]; } if (isset($components['modulus']) && isset($components['publicExponent'])) { return $components; } throw new \UnexpectedValueException('Modulus / exponent not present'); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return array */ public static function savePublicKey(BigInteger $n, BigInteger $e) { return ['e' => clone $e, 'n' => clone $n]; } } <?php /** * XML Formatted RSA Key Handler * * More info: * * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue * http://www.w3.org/TR/xkms2/#XKMS_2_0_Paragraph_269 * http://en.wikipedia.org/wiki/XML_Signature * http://en.wikipedia.org/wiki/XKMS * * PHP version 5 * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; /** * XML Formatted RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class XML { /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $components = [ 'isPublicKey' => false, 'primes' => [], 'exponents' => [], 'coefficients' => [] ]; $use_errors = libxml_use_internal_errors(true); $dom = new \DOMDocument(); if (substr($key, 0, 5) != '<?xml') { $key = '<xml>' . $key . '</xml>'; } if (!$dom->loadXML($key)) { throw new \UnexpectedValueException('Key does not appear to contain XML'); } $xpath = new \DOMXPath($dom); $keys = ['modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd']; foreach ($keys as $key) { // $dom->getElementsByTagName($key) is case-sensitive $temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']"); if (!$temp->length) { continue; } $value = new BigInteger(Base64::decode($temp->item(0)->nodeValue), 256); switch ($key) { case 'modulus': $components['modulus'] = $value; break; case 'exponent': $components['publicExponent'] = $value; break; case 'p': $components['primes'][1] = $value; break; case 'q': $components['primes'][2] = $value; break; case 'dp': $components['exponents'][1] = $value; break; case 'dq': $components['exponents'][2] = $value; break; case 'inverseq': $components['coefficients'][2] = $value; break; case 'd': $components['privateExponent'] = $value; } } libxml_use_internal_errors($use_errors); foreach ($components as $key => $value) { if (is_array($value) && !count($value)) { unset($components[$key]); } } if (isset($components['modulus']) && isset($components['publicExponent'])) { if (count($components) == 3) { $components['isPublicKey'] = true; } return $components; } throw new \UnexpectedValueException('Modulus / exponent not present'); } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '') { if (count($primes) != 2) { throw new \InvalidArgumentException('XML does not support multi-prime RSA keys'); } return "<RSAKeyPair>\r\n" . ' <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" . ' <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" . ' <P>' . Base64::encode($primes[1]->toBytes()) . "</P>\r\n" . ' <Q>' . Base64::encode($primes[2]->toBytes()) . "</Q>\r\n" . ' <DP>' . Base64::encode($exponents[1]->toBytes()) . "</DP>\r\n" . ' <DQ>' . Base64::encode($exponents[2]->toBytes()) . "</DQ>\r\n" . ' <InverseQ>' . Base64::encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" . ' <D>' . Base64::encode($d->toBytes()) . "</D>\r\n" . '</RSAKeyPair>'; } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e) { return "<RSAKeyValue>\r\n" . ' <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" . ' <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" . '</RSAKeyValue>'; } } <?php /** * OpenSSH Formatted RSA Key Handler * * PHP version 5 * * Place in $HOME/.ssh/authorized_keys * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\OpenSSH as Progenitor; /** * OpenSSH Formatted RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSH extends Progenitor { /** * Supported Key Types * * @var array */ protected static $types = ['ssh-rsa']; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { static $one; if (!isset($one)) { $one = new BigInteger(1); } $parsed = parent::load($key, $password); if (isset($parsed['paddedKey'])) { list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']); if ($type != $parsed['type']) { throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])"); } $primes = $coefficients = []; list( $modulus, $publicExponent, $privateExponent, $coefficients[2], $primes[1], $primes[2], $comment, ) = Strings::unpackSSH2('i6s', $parsed['paddedKey']); $temp = $primes[1]->subtract($one); $exponents = [1 => $publicExponent->modInverse($temp)]; $temp = $primes[2]->subtract($one); $exponents[] = $publicExponent->modInverse($temp); $isPublicKey = false; return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey'); } list($publicExponent, $modulus) = Strings::unpackSSH2('ii', $parsed['publicKey']); return [ 'isPublicKey' => true, 'modulus' => $modulus, 'publicExponent' => $publicExponent, 'comment' => $parsed['comment'] ]; } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param array $options optional * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = []) { $RSAPublicKey = Strings::packSSH2('sii', 'ssh-rsa', $e, $n); if (isset($options['binary']) ? $options['binary'] : self::$binary) { return $RSAPublicKey; } $comment = isset($options['comment']) ? $options['comment'] : self::$comment; $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $comment; return $RSAPublicKey; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = []) { $publicKey = self::savePublicKey($n, $e, ['binary' => true]); $privateKey = Strings::packSSH2('si6', 'ssh-rsa', $n, $e, $d, $coefficients[2], $primes[1], $primes[2]); return self::wrapPrivateKey($publicKey, $privateKey, $options); } } <?php /** * PKCS#8 Formatted RSA Key Handler * * PHP version 5 * * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) * * Processes keys with the following headers: * * -----BEGIN ENCRYPTED PRIVATE KEY----- * -----BEGIN PRIVATE KEY----- * -----BEGIN PUBLIC KEY----- * * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 * is specific to private keys it's basically creating a DER-encoded wrapper * for keys. This just extends that same concept to public keys (much like ssh-keygen) * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor; use phpseclib\File\ASN1; /** * PKCS#8 Formatted RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS8 extends Progenitor { /** * OID Name * * @var string * @access private */ const OID_NAME = 'rsaEncryption'; /** * OID Value * * @var string * @access private */ const OID_VALUE = '1.2.840.113549.1.1.1'; /** * Child OIDs loaded * * @var bool * @access private */ protected static $childOIDsLoaded = false; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false]; $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'private' : 'public'; $result = $components + PKCS1::load($key[$type . 'Key']); if (isset($key['meta'])) { $result['meta'] = $key['meta']; } return $result; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = []) { $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients); $key = ASN1::extractBER($key); return self::wrapPrivateKey($key, [], null, $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param array $options optional * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = []) { $key = PKCS1::savePublicKey($n, $e); $key = ASN1::extractBER($key); return self::wrapPublicKey($key, null); } } <?php /** * PKCS#8 Formatted RSA-PSS Key Handler * * PHP version 5 * * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) * * Processes keys with the following headers: * * -----BEGIN ENCRYPTED PRIVATE KEY----- * -----BEGIN PRIVATE KEY----- * -----BEGIN PUBLIC KEY----- * * Analogous to "openssl genpkey -algorithm rsa-pss". * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; /** * PKCS#8 Formatted RSA-PSS Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PSS extends Progenitor { /** * OID Name * * @var string * @access private */ const OID_NAME = 'id-RSASSA-PSS'; /** * OID Value * * @var string * @access private */ const OID_VALUE = '1.2.840.113549.1.1.10'; /** * OIDs loaded * * @var bool * @access private */ private static $oidsLoaded = false; /** * Child OIDs loaded * * @var bool * @access private */ protected static $childOIDsLoaded = false; /** * Initialize static variables */ private static function initialize_static_variables() { if (!self::$oidsLoaded) { ASN1::loadOIDs([ 'md2' => '1.2.840.113549.2.2', 'md4' => '1.2.840.113549.2.4', 'md5' => '1.2.840.113549.2.5', 'id-sha1' => '1.3.14.3.2.26', 'id-sha256' => '2.16.840.1.101.3.4.2.1', 'id-sha384' => '2.16.840.1.101.3.4.2.2', 'id-sha512' => '2.16.840.1.101.3.4.2.3', 'id-sha224' => '2.16.840.1.101.3.4.2.4', 'id-sha512/224' => '2.16.840.1.101.3.4.2.5', 'id-sha512/256' => '2.16.840.1.101.3.4.2.6', 'id-mgf1' => '1.2.840.113549.1.1.8' ]); self::$oidsLoaded = true; } } /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { self::initialize_static_variables(); if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false]; $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'private' : 'public'; $result = $components + PKCS1::load($key[$type . 'Key']); $decoded = ASN1::decodeBER($key[$type . 'KeyAlgorithm']['parameters']); if ($decoded === false) { throw new \UnexpectedValueException('Unable to decode parameters'); } $params = ASN1::asn1map($decoded[0], Maps\RSASSA_PSS_params::MAP); if (isset($params['maskGenAlgorithm']['parameters'])) { $decoded = ASN1::decodeBER($params['maskGenAlgorithm']['parameters']); if ($decoded === false) { throw new \UnexpectedValueException('Unable to decode parameters'); } $params['maskGenAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], Maps\HashAlgorithm::MAP); } else { $params['maskGenAlgorithm'] = [ 'algorithm' => 'id-mgf1', 'parameters' => ['algorithm' => 'id-sha1'] ]; } if (!isset($params['hashAlgorithm']['algorithm'])) { $params['hashAlgorithm']['algorithm'] = 'id-sha1'; } $result['hash'] = str_replace('id-', '', $params['hashAlgorithm']['algorithm']); $result['MGFHash'] = str_replace('id-', '', $params['maskGenAlgorithm']['parameters']['algorithm']); $result['saltLength'] = (int) $params['saltLength']->toString(); if (isset($key['meta'])) { $result['meta'] = $key['meta']; } return $result; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = []) { self::initialize_static_variables(); $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients); $key = ASN1::extractBER($key); $params = self::savePSSParams($options); return self::wrapPrivateKey($key, [], $params, $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param array $options optional * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = []) { $key = PKCS1::savePublicKey($n, $e); $key = ASN1::extractBER($key); $params = self::savePSSParams($options); return self::wrapPublicKey($key, $params); } /** * Encodes PSS parameters * * @access public * @param array $options * @return string */ private static function savePSSParams(array $options) { /* The trailerField field is an integer. It provides compatibility with IEEE Std 1363a-2004 [P1363A]. The value MUST be 1, which represents the trailer field with hexadecimal value 0xBC. Other trailer fields, including the trailer field composed of HashID concatenated with 0xCC that is specified in IEEE Std 1363a, are not supported. Implementations that perform signature generation MUST omit the trailerField field, indicating that the default trailer field value was used. Implementations that perform signature validation MUST recognize both a present trailerField field with value 1 and an absent trailerField field. source: https://tools.ietf.org/html/rfc4055#page-9 */ $params = [ 'trailerField' => new BigInteger(1) ]; if (isset($options['hash'])) { $params['hashAlgorithm']['algorithm'] = 'id-' . $options['hash']; } if (isset($options['MGFHash'])) { $temp = ['algorithm' => 'id-' . $options['MGFHash']]; $temp = ASN1::encodeDER($temp, Maps\HashAlgorithm::MAP); $params['maskGenAlgorithm'] = [ 'algorithm' => 'id-mgf1', 'parameters' => new ASN1\Element($temp) ]; } if (isset($options['saltLength'])) { $params['saltLength'] = new BigInteger($options['saltLength']); } return new ASN1\Element(ASN1::encodeDER($params, Maps\RSASSA_PSS_params::MAP)); } } <?php /** * PKCS#1 Formatted RSA Key Handler * * PHP version 5 * * Used by File/X509.php * * Processes keys with the following headers: * * -----BEGIN RSA PRIVATE KEY----- * -----BEGIN RSA PUBLIC KEY----- * * Analogous to ssh-keygen's pem format (as specified by -m) * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common\Keys\PKCS1 as Progenitor; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; /** * PKCS#1 Formatted RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS1 extends Progenitor { /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false]; $key = parent::load($key, $password); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER'); } $key = ASN1::asn1map($decoded[0], Maps\RSAPrivateKey::MAP); if (is_array($key)) { $components+= [ 'modulus' => $key['modulus'], 'publicExponent' => $key['publicExponent'], 'privateExponent' => $key['privateExponent'], 'primes' => [1 => $key['prime1'], $key['prime2']], 'exponents' => [1 => $key['exponent1'], $key['exponent2']], 'coefficients' => [2 => $key['coefficient']] ]; if ($key['version'] == 'multi') { foreach ($key['otherPrimeInfos'] as $primeInfo) { $components['primes'][] = $primeInfo['prime']; $components['exponents'][] = $primeInfo['exponent']; $components['coefficients'][] = $primeInfo['coefficient']; } } return $components; } $key = ASN1::asn1map($decoded[0], Maps\RSAPublicKey::MAP); if (!is_array($key)) { throw new \RuntimeException('Unable to perform ASN1 mapping'); } return $components + $key; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = []) { $num_primes = count($primes); $key = [ 'version' => $num_primes == 2 ? 'two-prime' : 'multi', 'modulus' => $n, 'publicExponent' => $e, 'privateExponent' => $d, 'prime1' => $primes[1], 'prime2' => $primes[2], 'exponent1' => $exponents[1], 'exponent2' => $exponents[2], 'coefficient' => $coefficients[2] ]; for ($i = 3; $i <= $num_primes; $i++) { $key['otherPrimeInfos'][] = [ 'prime' => $primes[$i], 'exponent' => $exponents[$i], 'coefficient' => $coefficients[$i] ]; } $key = ASN1::encodeDER($key, Maps\RSAPrivateKey::MAP); return self::wrapPrivateKey($key, 'RSA', $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e) { $key = [ 'modulus' => $n, 'publicExponent' => $e ]; $key = ASN1::encodeDER($key, Maps\RSAPublicKey::MAP); return self::wrapPublicKey($key, 'RSA'); } } <?php /** * PuTTY Formatted RSA Key Handler * * PHP version 5 * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\PuTTY as Progenitor; /** * PuTTY Formatted RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PuTTY extends Progenitor { /** * Public Handler * * @var string * @access private */ const PUBLIC_HANDLER = 'phpseclib\Crypt\RSA\Keys\OpenSSH'; /** * Algorithm Identifier * * @var array * @access private */ protected static $types = ['ssh-rsa']; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { static $one; if (!isset($one)) { $one = new BigInteger(1); } $components = parent::load($key, $password); if (!isset($components['private'])) { return $components; } extract($components); unset($components['public'], $components['private']); $isPublicKey = false; $result = Strings::unpackSSH2('ii', $public); if ($result === false) { throw new \UnexpectedValueException('Key appears to be malformed'); } list($publicExponent, $modulus) = $result; $result = Strings::unpackSSH2('iiii', $private); if ($result === false) { throw new \UnexpectedValueException('Key appears to be malformed'); } $primes = $coefficients = []; list($privateExponent, $primes[1], $primes[2], $coefficients[2]) = $result; $temp = $primes[1]->subtract($one); $exponents = [1 => $publicExponent->modInverse($temp)]; $temp = $primes[2]->subtract($one); $exponents[] = $publicExponent->modInverse($temp); return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey'); } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = []) { if (count($primes) != 2) { throw new \InvalidArgumentException('PuTTY does not support multi-prime RSA keys'); } $public = Strings::packSSH2('ii', $e, $n); $private = Strings::packSSH2('iiii', $d, $primes[1], $primes[2], $coefficients[2]); return self::wrapPrivateKey($public, $private, 'ssh-rsa', $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ public static function savePublicKey(BigInteger $n, BigInteger $e) { return self::wrapPublicKey(Strings::packSSH2($e, $n), 'ssh-rsa'); } } <?php /** * RSA Public Key * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\RSA; use phpseclib\Crypt\RSA; use phpseclib\Math\BigInteger; use phpseclib\File\ASN1; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Hash; use phpseclib\Exceptions\NoKeyLoadedException; use phpseclib\Crypt\Random; use phpseclib\Crypt\Common; use phpseclib\File\ASN1\Maps\DigestInfo; use phpseclib\Crypt\RSA\Keys\PSS; /** * Raw RSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PublicKey extends RSA implements Common\PublicKey { use Common\Fingerprint; /** * Exponentiate * * @param \phpseclib\Math\BigInteger $x * @return \phpseclib\Math\BigInteger */ private function exponentiate(BigInteger $x) { return $x->modPow($this->exponent, $this->modulus); } /** * RSAVP1 * * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}. * * @access private * @param \phpseclib\Math\BigInteger $s * @return bool|\phpseclib\Math\BigInteger */ private function rsavp1($s) { if ($s->compare(self::$zero) < 0 || $s->compare($this->modulus) > 0) { return false; } return $this->exponentiate($s); } /** * RSASSA-PKCS1-V1_5-VERIFY * * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}. * * @access private * @param string $m * @param string $s * @throws \LengthException if the RSA modulus is too short * @return bool */ private function rsassa_pkcs1_v1_5_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { return false; } // RSA verification $s = $this->os2ip($s); $m2 = $this->rsavp1($s); $em = $this->i2osp($m2, $this->k); if ($em === false) { return false; } // EMSA-PKCS1-v1_5 encoding // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus // too short" and stop. try { $em2 = $this->emsa_pkcs1_v1_5_encode($m, $this->k); } catch (\LengthException $e) { throw new \LengthException('RSA modulus too short'); } // Compare return hash_equals($em, $em2); } /** * RSASSA-PKCS1-V1_5-VERIFY (relaxed matching) * * Per {@link http://tools.ietf.org/html/rfc3447#page-43 RFC3447#page-43} PKCS1 v1.5 * specified the use BER encoding rather than DER encoding that PKCS1 v2.0 specified. * This means that under rare conditions you can have a perfectly valid v1.5 signature * that fails to validate with _rsassa_pkcs1_v1_5_verify(). PKCS1 v2.1 also recommends * that if you're going to validate these types of signatures you "should indicate * whether the underlying BER encoding is a DER encoding and hence whether the signature * is valid with respect to the specification given in [PKCS1 v2.0+]". so if you do * $rsa->getLastPadding() and get RSA::PADDING_RELAXED_PKCS1 back instead of * RSA::PADDING_PKCS1... that means BER encoding was used. * * @access private * @param string $m * @param string $s * @return bool */ private function rsassa_pkcs1_v1_5_relaxed_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { return false; } // RSA verification $s = $this->os2ip($s); $m2 = $this->rsavp1($s); if ($m2 === false) { return false; } $em = $this->i2osp($m2, $this->k); if ($em === false) { return false; } if (Strings::shift($em, 2) != "\0\1") { return false; } $em = ltrim($em, "\xFF"); if (Strings::shift($em) != "\0") { return false; } $decoded = ASN1::decodeBER($em); if (!is_array($decoded) || empty($decoded[0]) || strlen($em) > $decoded[0]['length']) { return false; } static $oids; if (!isset($oids)) { $oids = [ 'md2' => '1.2.840.113549.2.2', 'md4' => '1.2.840.113549.2.4', // from PKCS1 v1.5 'md5' => '1.2.840.113549.2.5', 'id-sha1' => '1.3.14.3.2.26', 'id-sha256' => '2.16.840.1.101.3.4.2.1', 'id-sha384' => '2.16.840.1.101.3.4.2.2', 'id-sha512' => '2.16.840.1.101.3.4.2.3', // from PKCS1 v2.2 'id-sha224' => '2.16.840.1.101.3.4.2.4', 'id-sha512/224' => '2.16.840.1.101.3.4.2.5', 'id-sha512/256' => '2.16.840.1.101.3.4.2.6', ]; ASN1::loadOIDs($oids); } $decoded = ASN1::asn1map($decoded[0], DigestInfo::MAP); if (!isset($decoded) || $decoded === false) { return false; } if (!isset($oids[$decoded['digestAlgorithm']['algorithm']])) { return false; } $hash = $decoded['digestAlgorithm']['algorithm']; $hash = substr($hash, 0, 3) == 'id-' ? substr($hash, 3) : $hash; $hash = new Hash($hash); $em = $hash->hash($m); $em2 = $decoded['digest']; return hash_equals($em, $em2); } /** * EMSA-PSS-VERIFY * * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}. * * @access private * @param string $m * @param string $em * @param int $emBits * @return string */ private function emsa_pss_verify($m, $em, $emBits) { // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8); $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { return false; } if ($em[strlen($em) - 1] != chr(0xBC)) { return false; } $maskedDB = substr($em, 0, -$this->hLen - 1); $h = substr($em, -$this->hLen - 1, $this->hLen); $temp = chr(0xFF << ($emBits & 7)); if ((~$maskedDB[0] & $temp) != $temp) { return false; } $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; $temp = $emLen - $this->hLen - $sLen - 2; if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { return false; } $salt = substr($db, $temp + 1); // should be $sLen long $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h2 = $this->hash->hash($m2); return hash_equals($h, $h2); } /** * RSASSA-PSS-VERIFY * * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}. * * @access private * @param string $m * @param string $s * @return bool|string */ private function rsassa_pss_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { return false; } // RSA verification $modBits = 8 * $this->k; $s2 = $this->os2ip($s); $m2 = $this->rsavp1($s2); $em = $this->i2osp($m2, $modBits >> 3); if ($em === false) { return false; } // EMSA-PSS verification return $this->emsa_pss_verify($m, $em, $modBits - 1); } /** * Verifies a signature * * @see self::sign() * @param string $message * @param string $signature * @return bool */ public function verify($message, $signature) { switch ($this->signaturePadding) { case self::SIGNATURE_RELAXED_PKCS1: return $this->rsassa_pkcs1_v1_5_relaxed_verify($message, $signature); case self::SIGNATURE_PKCS1: return $this->rsassa_pkcs1_v1_5_verify($message, $signature); //case self::SIGNATURE_PSS: default: return $this->rsassa_pss_verify($message, $signature); } } /** * RSAES-PKCS1-V1_5-ENCRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}. * * @access private * @param string $m * @param bool $pkcs15_compat optional * @throws \LengthException if strlen($m) > $this->k - 11 * @return bool|string */ private function rsaes_pkcs1_v1_5_encrypt($m, $pkcs15_compat = false) { $mLen = strlen($m); // Length checking if ($mLen > $this->k - 11) { throw new \LengthException('Message too long'); } // EME-PKCS1-v1_5 encoding $psLen = $this->k - $mLen - 3; $ps = ''; while (strlen($ps) != $psLen) { $temp = Random::string($psLen - strlen($ps)); $temp = str_replace("\x00", '', $temp); $ps.= $temp; } $type = 2; // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done if ($pkcs15_compat && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { $type = 1; // "The padding string PS shall consist of k-3-||D|| octets.... for block type 01, they shall have value FF" $ps = str_repeat("\xFF", $psLen); } $em = chr(0) . chr($type) . $ps . chr(0) . $m; // RSA encryption $m = $this->os2ip($em); $c = $this->rsaep($m); $c = $this->i2osp($c, $this->k); // Output the ciphertext C return $c; } /** * RSAES-OAEP-ENCRYPT * * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}. * * @access private * @param string $m * @throws \LengthException if strlen($m) > $this->k - 2 * $this->hLen - 2 * @return string */ private function rsaes_oaep_encrypt($m) { $mLen = strlen($m); // Length checking // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error // be output. if ($mLen > $this->k - 2 * $this->hLen - 2) { throw new \LengthException('Message too long'); } // EME-OAEP encoding $lHash = $this->hash->hash($this->label); $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2); $db = $lHash . $ps . chr(1) . $m; $seed = Random::string($this->hLen); $dbMask = $this->mgf1($seed, $this->k - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $seedMask = $this->mgf1($maskedDB, $this->hLen); $maskedSeed = $seed ^ $seedMask; $em = chr(0) . $maskedSeed . $maskedDB; // RSA encryption $m = $this->os2ip($em); $c = $this->rsaep($m); $c = $this->i2osp($c, $this->k); // Output the ciphertext C return $c; } /** * RSAEP * * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}. * * @access private * @param \phpseclib\Math\BigInteger $m * @return bool|\phpseclib\Math\BigInteger */ private function rsaep($m) { if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) { return false; } return $this->exponentiate($m); } /** * Raw Encryption / Decryption * * Doesn't use padding and is not recommended. * * @access private * @param string $m * @return bool|string * @throws \LengthException if strlen($m) > $this->k */ private function raw_encrypt($m) { if (strlen($m) > $this->k) { throw new \LengthException('Message too long'); } $temp = $this->os2ip($m); $temp = $this->rsaep($temp); return $this->i2osp($temp, $this->k); } /** * Encryption * * Both self::PADDING_OAEP and self::PADDING_PKCS1 both place limits on how long $plaintext can be. * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will * be concatenated together. * * @see self::decrypt() * @access public * @param string $plaintext * @return bool|string * @throws \LengthException if the RSA modulus is too short */ public function encrypt($plaintext) { switch ($this->encryptionPadding) { case self::ENCRYPTION_NONE: return $this->raw_encrypt($plaintext); case self::ENCRYPTION_PKCS15_COMPAT: case self::ENCRYPTION_PKCS1: $pkcs15_compat = $this->encryptionPadding & self::ENCRYPTION_PKCS15_COMPAT; return $this->rsaes_pkcs1_v1_5_encrypt($plaintext, $pkcs15_compat); //case self::ENCRYPTION_OAEP: default: return $this->rsaes_oaep_encrypt($plaintext); } } /** * Returns the public key * * The public key is only returned under two circumstances - if the private key had the public key embedded within it * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this * function won't return it since this library, for the most part, doesn't distinguish between public and private keys. * * @param string $type * @param array $options optional * @return mixed */ public function toString($type, array $options = []) { $type = self::validatePlugin('Keys', $type, 'savePublicKey'); if ($type == PSS::class) { if ($this->signaturePadding == self::SIGNATURE_PSS) { $options+= [ 'hash' => $this->hash->getHash(), 'MGFHash' => $this->mgfHash->getHash(), 'saltLength' => $this->sLen ]; } else { throw new UnsupportedFormatException('The PSS format can only be used when the signature method has been explicitly set to PSS'); } } return $type::savePublicKey($this->modulus, $this->publicExponent, $options); } /** * Converts a public key to a private key * * @return RSA */ public function asPrivateKey() { $new = new PrivateKey; $new->exponent = $this->exponent; $new->modulus = $this->modulus; $new->k = $this->k; $new->format = $this->format; return $new ->withHash($this->hash->getHash()) ->withMGFHash($this->mgfHash->getHash()) ->withSaltLength($this->sLen) ->withLabel($this->label) ->withPadding($this->signaturePadding | $this->encryptionPadding); } } <?php /** * Wrapper around hash() and hash_hmac() functions supporting truncated hashes * such as sha256-96. Any hash algorithm returned by hash_algos() (and * truncated versions thereof) are supported. * * If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will * return the HMAC as opposed to the hash. * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $hash = new \phpseclib\Crypt\Hash('sha512'); * * $hash->setKey('abcdefg'); * * echo base64_encode($hash->hash('abcdefg')); * ?> * </code> * * @category Crypt * @package Hash * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @author Andreas Fischer <bantu@phpbb.com> * @copyright 2015 Andreas Fischer * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Math\BigInteger; use phpseclib\Exception\UnsupportedAlgorithmException; use phpseclib\Common\Functions\Strings; /** * @package Hash * @author Jim Wigginton <terrafrost@php.net> * @author Andreas Fischer <bantu@phpbb.com> * @access public */ class Hash { /**#@+ * Padding Types * * @access private */ //const PADDING_KECCAK = 1; const PADDING_SHA3 = 2; const PADDING_SHAKE = 3; /**#@-*/ /** * Padding Type * * Only used by SHA3 * * @var int * @access private */ private $paddingType = 0; /** * Hash Parameter * * @see self::setHash() * @var int * @access private */ private $hashParam; /** * Byte-length of hash output (Internal HMAC) * * @see self::setHash() * @var int * @access private */ private $length; /** * Hash Algorithm * * @see self::setHash() * @var string * @access private */ private $hash; /** * Key * * @see self::setKey() * @var string * @access private */ private $key = false; /** * Hash Parameters * * @var array * @access private */ private $parameters = []; /** * Computed Key * * @see self::_computeKey() * @var string * @access private */ private $computedKey = false; /** * Outer XOR (Internal HMAC) * * Used only for sha512/* * * @see self::hash() * @var string * @access private */ private $opad; /** * Inner XOR (Internal HMAC) * * Used only for sha512/* * * @see self::hash() * @var string * @access private */ private $ipad; /** * Default Constructor. * * @param string $hash * @access public */ public function __construct($hash = 'sha256') { $this->setHash($hash); } /** * Sets the key for HMACs * * Keys can be of any length. * * @access public * @param string $key */ public function setKey($key = false) { $this->key = $key; $this->computeKey(); } /** * Pre-compute the key used by the HMAC * * Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes * will first hash the key using H and then use the resultant L byte string as the actual key to HMAC." * * As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/ * when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during * every call * * @access private */ private function computeKey() { if ($this->key === false) { $this->computedKey = false; return; } if (strlen($this->key) <= $this->getBlockLengthInBytes()) { $this->computedKey = $this->key; return; } $this->computedKey = is_array($this->hash) ? call_user_func($this->hash, $this->key) : hash($this->hash, $this->key, true); } /** * Gets the hash function. * * As set by the constructor or by the setHash() method. * * @access public * @return string */ public function getHash() { return $this->hashParam; } /** * Sets the hash function. * * @access public * @param string $hash */ public function setHash($hash) { $this->hashParam = $hash = strtolower($hash); switch ($hash) { case 'md2-96': case 'md5-96': case 'sha1-96': case 'sha224-96': case 'sha256-96': case 'sha384-96': case 'sha512-96': case 'sha512/224-96': case 'sha512/256-96': $hash = substr($hash, 0, -3); $this->length = 12; // 96 / 8 = 12 break; case 'md2': case 'md5': $this->length = 16; break; case 'sha1': $this->length = 20; break; case 'sha224': case 'sha512/224': case 'sha3-224': $this->length = 28; break; case 'sha256': case 'sha512/256': case 'sha3-256': $this->length = 32; break; case 'sha384': case 'sha3-384': $this->length = 48; break; case 'sha512': case 'sha3-512': $this->length = 64; break; default: if (preg_match('#^(shake(?:128|256))-(\d+)$#', $hash, $matches)) { $this->paddingType = self::PADDING_SHAKE; $hash = $matches[1]; $this->length = $matches[2] >> 3; } else { throw new UnsupportedAlgorithmException( "$hash is not a supported algorithm" ); } } switch ($hash) { case 'md2': case 'md2-96': $this->blockSize = 128; break; case 'md5-96': case 'sha1-96': case 'sha224-96': case 'sha256-96': case 'md5': case 'sha1': case 'sha224': case 'sha256': $this->blockSize = 512; break; case 'sha3-224': $this->blockSize = 1152; // 1600 - 2*224 break; case 'sha3-256': case 'shake256': $this->blockSize = 1088; // 1600 - 2*256 break; case 'sha3-384': $this->blockSize = 832; // 1600 - 2*384 break; case 'sha3-512': $this->blockSize = 576; // 1600 - 2*512 break; case 'shake128': $this->blockSize = 1344; // 1600 - 2*128 break; default: $this->blockSize = 1024; } if (in_array(substr($hash, 0, 5), ['sha3-', 'shake'])) { // PHP 7.1.0 introduced support for "SHA3 fixed mode algorithms": // http://php.net/ChangeLog-7.php#7.1.0 if (version_compare(PHP_VERSION, '7.1.0') < 0 || substr($hash, 0,5) == 'shake') { //preg_match('#(\d+)$#', $hash, $matches); //$this->parameters['capacity'] = 2 * $matches[1]; // 1600 - $this->blockSize //$this->parameters['rate'] = 1600 - $this->parameters['capacity']; // == $this->blockSize if (!$this->paddingType) { $this->paddingType = self::PADDING_SHA3; } $this->parameters = [ 'capacity' => 1600 - $this->blockSize, 'rate' => $this->blockSize, 'length' => $this->length, 'padding' => $this->paddingType ]; $hash = ['phpseclib\Crypt\Hash', PHP_INT_SIZE == 8 ? 'sha3_64' : 'sha3_32']; } } if ($hash == 'sha512/224' || $hash == 'sha512/256') { // PHP 7.1.0 introduced sha512/224 and sha512/256 support: // http://php.net/ChangeLog-7.php#7.1.0 if (version_compare(PHP_VERSION, '7.1.0') < 0) { // from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24 $initial = $hash == 'sha512/256' ? [ '22312194FC2BF72C', '9F555FA3C84C64C2', '2393B86B6F53B151', '963877195940EABD', '96283EE2A88EFFE3', 'BE5E1E2553863992', '2B0199FC2C85B8AA', '0EB72DDC81C52CA2' ] : [ '8C3D37C819544DA2', '73E1996689DCD4D6', '1DFAB7AE32FF9C82', '679DD514582F9FCF', '0F6D2B697BD44DA8', '77E36F7304C48942', '3F9D85A86A1D36C8', '1112E6AD91D692A1' ]; for ($i = 0; $i < 8; $i++) { $initial[$i] = new BigInteger($initial[$i], 16); $initial[$i]->setPrecision(64); } $this->parameters = compact('initial'); $hash = ['phpseclib\Crypt\Hash', 'sha512']; } } if (is_array($hash)) { $b = $this->blockSize >> 3; $this->ipad = str_repeat(chr(0x36), $b); $this->opad = str_repeat(chr(0x5C), $b); } $this->hash = $hash; $this->computeKey(); } /** * Compute the HMAC. * * @access public * @param string $text * @return string */ public function hash($text) { if (is_array($this->hash)) { if (empty($this->key) || !is_string($this->key)) { return substr(call_user_func($this->hash, $text,...array_values($this->parameters)), 0, $this->length); } // SHA3 HMACs are discussed at https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf#page=30 $key = str_pad($this->computedKey, $b, chr(0)); $temp = $this->ipad ^ $key; $temp .= $text; $temp = substr(call_user_func($this->hash, $temp,...array_values($this->parameters)), 0, $this->length); $output = $this->opad ^ $key; $output.= $temp; $output = call_user_func($this->hash, $output,...array_values($this->parameters)); return substr($output, 0, $this->length); } $output = !empty($this->key) || is_string($this->key) ? hash_hmac($this->hash, $text, $this->computedKey, true) : hash($this->hash, $text, true); return strlen($output) > $this->length ? substr($output, 0, $this->length) : $output; } /** * Returns the hash length (in bits) * * @access public * @return int */ public function getLength() { return $this->length << 3; } /** * Returns the hash length (in bytes) * * @access public * @return int */ public function getLengthInBytes() { return $this->length; } /** * Returns the block length (in bits) * * @access public * @return int */ public function getBlockLength() { return $this->blockSize; } /** * Returns the block length (in bytes) * * @access public * @return int */ public function getBlockLengthInBytes() { return $this->blockSize >> 3; } /** * Pads SHA3 based on the mode * * @access private * @param int $padLength * @param int $padType * @return string */ private static function sha3_pad($padLength, $padType) { switch ($padType) { //case self::PADDING_KECCAK: // $temp = chr(0x06) . str_repeat("\0", $padLength - 1); // $temp[$padLength - 1] = $temp[$padLength - 1] | chr(0x80); // return $temp case self::PADDING_SHAKE: $temp = chr(0x1F) . str_repeat("\0", $padLength - 1); $temp[$padLength - 1] = $temp[$padLength - 1] | chr(0x80); return $temp; //case self::PADDING_SHA3: default: // from https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf#page=36 return $padLength == 1 ? chr(0x86) : chr(0x06) . str_repeat("\0", $padLength - 2) . chr(0x80); } } /** * Pure-PHP 32-bit implementation of SHA3 * * Whereas BigInteger.php's 32-bit engine works on PHP 64-bit this 32-bit implementation * of SHA3 will *not* work on PHP 64-bit. This is because this implementation * employees bitwise NOTs and bitwise left shifts. And the round constants only work * on 32-bit PHP. eg. dechex(-2147483648) returns 80000000 on 32-bit PHP and * FFFFFFFF80000000 on 64-bit PHP. Sure, we could do bitwise ANDs but that would slow * things down. * * SHA512 requires BigInteger to simulate 64-bit unsigned integers because SHA2 employees * addition whereas SHA3 just employees bitwise operators. PHP64 only supports signed * 64-bit integers, which complicates addition, whereas that limitation isn't an issue * for SHA3. * * In https://ws680.nist.gov/publication/get_pdf.cfm?pub_id=919061#page=16 KECCAK[C] is * defined as "the KECCAK instance with KECCAK-f[1600] as the underlying permutation and * capacity c". This is relevant because, altho the KECCAK standard defines a mode * (KECCAK-f[800]) designed for 32-bit machines that mode is incompatible with SHA3 * * @access private * @param string $p * @param int $c * @param int $r * @param int $d * @param int $padType */ private static function sha3_32($p, $c, $r, $d, $padType) { $block_size = $r >> 3; $padLength = $block_size - (strlen($p) % $block_size); $num_ints = $block_size >> 2; $p.= static::sha3_pad($padLength, $padType); $n = strlen($p) / $r; // number of blocks $s = [ [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]] ]; $p = str_split($p, $block_size); foreach ($p as $pi) { $pi = unpack('V*', $pi); $x = $y = 0; for ($i = 1; $i <= $num_ints; $i+=2) { $s[$x][$y][0]^= $pi[$i + 1]; $s[$x][$y][1]^= $pi[$i]; if (++$y == 5) { $y = 0; $x++; } } static::processSHA3Block32($s); } $z = ''; $i = $j = 0; while (strlen($z) < $d) { $z.= pack('V2', $s[$i][$j][1], $s[$i][$j++][0]); if ($j == 5) { $j = 0; $i++; if ($i == 5) { $i = 0; static::processSHA3Block32($s); } } } return $z; } /** * 32-bit block processing method for SHA3 * * @access private * @param array $s */ private static function processSHA3Block32(&$s) { static $rotationOffsets = [ [ 0, 1, 62, 28, 27], [36, 44, 6, 55, 20], [ 3, 10, 43, 25, 39], [41, 45, 15, 21, 8], [18, 2, 61, 56, 14] ]; // the standards give these constants in hexadecimal notation. it's tempting to want to use // that same notation, here, however, we can't, because 0x80000000, on PHP32, is a positive // float - not the negative int that we need to be in PHP32. so we use -2147483648 instead static $roundConstants = [ [0, 1], [0, 32898], [-2147483648, 32906], [-2147483648, -2147450880], [0, 32907], [0, -2147483647], [-2147483648, -2147450751], [-2147483648, 32777], [0, 138], [0, 136], [0, -2147450871], [0, -2147483638], [0, -2147450741], [-2147483648, 139], [-2147483648, 32905], [-2147483648, 32771], [-2147483648, 32770], [-2147483648, 128], [0, 32778], [-2147483648, -2147483638], [-2147483648, -2147450751], [-2147483648, 32896], [0, -2147483647], [-2147483648, -2147450872] ]; for ($round = 0; $round < 24; $round++) { // theta step $parity = $rotated = []; for ($i = 0; $i < 5; $i++) { $parity[] = [ $s[0][$i][0] ^ $s[1][$i][0] ^ $s[2][$i][0] ^ $s[3][$i][0] ^ $s[4][$i][0], $s[0][$i][1] ^ $s[1][$i][1] ^ $s[2][$i][1] ^ $s[3][$i][1] ^ $s[4][$i][1] ]; $rotated[] = static::rotateLeft32($parity[$i], 1); } $temp = [ [$parity[4][0] ^ $rotated[1][0], $parity[4][1] ^ $rotated[1][1]], [$parity[0][0] ^ $rotated[2][0], $parity[0][1] ^ $rotated[2][1]], [$parity[1][0] ^ $rotated[3][0], $parity[1][1] ^ $rotated[3][1]], [$parity[2][0] ^ $rotated[4][0], $parity[2][1] ^ $rotated[4][1]], [$parity[3][0] ^ $rotated[0][0], $parity[3][1] ^ $rotated[0][1]] ]; for ($i = 0; $i < 5; $i++) { for ($j = 0; $j < 5; $j++) { $s[$i][$j][0]^= $temp[$j][0]; $s[$i][$j][1]^= $temp[$j][1]; } } $st = $s; // rho and pi steps for ($i = 0; $i < 5; $i++) { for ($j = 0; $j < 5; $j++) { $st[(2 * $i + 3 * $j) % 5][$j] = static::rotateLeft32($s[$j][$i], $rotationOffsets[$j][$i]); } } // chi step for ($i = 0; $i < 5; $i++) { $s[$i][0] = [ $st[$i][0][0] ^ (~$st[$i][1][0] & $st[$i][2][0]), $st[$i][0][1] ^ (~$st[$i][1][1] & $st[$i][2][1]) ]; $s[$i][1] = [ $st[$i][1][0] ^ (~$st[$i][2][0] & $st[$i][3][0]), $st[$i][1][1] ^ (~$st[$i][2][1] & $st[$i][3][1]) ]; $s[$i][2] = [ $st[$i][2][0] ^ (~$st[$i][3][0] & $st[$i][4][0]), $st[$i][2][1] ^ (~$st[$i][3][1] & $st[$i][4][1]) ]; $s[$i][3] = [ $st[$i][3][0] ^ (~$st[$i][4][0] & $st[$i][0][0]), $st[$i][3][1] ^ (~$st[$i][4][1] & $st[$i][0][1]) ]; $s[$i][4] = [ $st[$i][4][0] ^ (~$st[$i][0][0] & $st[$i][1][0]), $st[$i][4][1] ^ (~$st[$i][0][1] & $st[$i][1][1]) ]; } // iota step $s[0][0][0]^= $roundConstants[$round][0]; $s[0][0][1]^= $roundConstants[$round][1]; } } /** * Rotate 32-bit int * * @access private * @param array $x * @param int $shift */ private static function rotateLeft32($x, $shift) { if ($shift < 32) { list($hi, $lo) = $x; } else { $shift-= 32; list($lo, $hi) = $x; } return [ ($hi << $shift) | (($lo >> (32 - $shift)) & (1 << $shift) - 1), ($lo << $shift) | (($hi >> (32 - $shift)) & (1 << $shift) - 1) ]; } /** * Pure-PHP 64-bit implementation of SHA3 * * @access private * @param string $p * @param int $c * @param int $r * @param int $d * @param int $padType */ private static function sha3_64($p, $c, $r, $d, $padType) { $block_size = $r >> 3; $padLength = $block_size - (strlen($p) % $block_size); $num_ints = $block_size >> 2; $p.= static::sha3_pad($padLength, $padType); $n = strlen($p) / $r; // number of blocks $s = [ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ]; $p = str_split($p, $block_size); foreach ($p as $pi) { $pi = unpack('P*', $pi); $x = $y = 0; foreach ($pi as $subpi) { $s[$x][$y++]^= $subpi; if ($y == 5) { $y = 0; $x++; } } static::processSHA3Block64($s); } $z = ''; $i = $j = 0; while (strlen($z) < $d) { $z.= pack('P', $s[$i][$j++]); if ($j == 5) { $j = 0; $i++; if ($i == 5) { $i = 0; static::processSHA3Block64($s); } } } return $z; } /** * 64-bit block processing method for SHA3 * * @access private * @param array $s */ private static function processSHA3Block64(&$s) { static $rotationOffsets = [ [ 0, 1, 62, 28, 27], [36, 44, 6, 55, 20], [ 3, 10, 43, 25, 39], [41, 45, 15, 21, 8], [18, 2, 61, 56, 14] ]; static $roundConstants = [ 1, 32898, -9223372036854742902, -9223372034707259392, 32907, 2147483649, -9223372034707259263, -9223372036854743031, 138, 136, 2147516425, 2147483658, 2147516555, -9223372036854775669, -9223372036854742903, -9223372036854743037, -9223372036854743038, -9223372036854775680, 32778, -9223372034707292150, -9223372034707259263, -9223372036854742912, 2147483649, -9223372034707259384 ]; for ($round = 0; $round < 24; $round++) { // theta step $parity = []; for ($i = 0; $i < 5; $i++) { $parity[] = $s[0][$i] ^ $s[1][$i] ^ $s[2][$i] ^ $s[3][$i] ^ $s[4][$i]; } $temp = [ $parity[4] ^ static::rotateLeft64($parity[1], 1), $parity[0] ^ static::rotateLeft64($parity[2], 1), $parity[1] ^ static::rotateLeft64($parity[3], 1), $parity[2] ^ static::rotateLeft64($parity[4], 1), $parity[3] ^ static::rotateLeft64($parity[0], 1) ]; for ($i = 0; $i < 5; $i++) { for ($j = 0; $j < 5; $j++) { $s[$i][$j]^= $temp[$j]; } } $st = $s; // rho and pi steps for ($i = 0; $i < 5; $i++) { for ($j = 0; $j < 5; $j++) { $st[(2 * $i + 3 * $j) % 5][$j] = static::rotateLeft64($s[$j][$i], $rotationOffsets[$j][$i]); } } // chi step for ($i = 0; $i < 5; $i++) { $s[$i] = [ $st[$i][0] ^ (~$st[$i][1] & $st[$i][2]), $st[$i][1] ^ (~$st[$i][2] & $st[$i][3]), $st[$i][2] ^ (~$st[$i][3] & $st[$i][4]), $st[$i][3] ^ (~$st[$i][4] & $st[$i][0]), $st[$i][4] ^ (~$st[$i][0] & $st[$i][1]) ]; } // iota step $s[0][0]^= $roundConstants[$round]; } } /** * Rotate 64-bit int * * @access private * @param int $x * @param int $shift */ private static function rotateLeft64($x, $shift) { return ($x << $shift) | (($x >> (64 - $shift)) & ((1 << $shift) - 1)); } /** * Pure-PHP implementation of SHA512 * * @access private * @param string $m * @param array $hash * @return string */ private static function sha512($m, $hash) { static $k; if (!isset($k)) { // Initialize table of round constants // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) $k = [ '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' ]; for ($i = 0; $i < 80; $i++) { $k[$i] = new BigInteger($k[$i], 16); } } // Pre-processing $length = strlen($m); // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); $m[$length] = chr(0x80); // we don't support hashing strings 512MB long $m.= pack('N4', 0, 0, 0, $length << 3); // Process the message in successive 1024-bit chunks $chunks = str_split($m, 128); foreach ($chunks as $chunk) { $w = []; for ($i = 0; $i < 16; $i++) { $temp = new BigInteger(Strings::shift($chunk, 8), 256); $temp->setPrecision(64); $w[] = $temp; } // Extend the sixteen 32-bit words into eighty 32-bit words for ($i = 16; $i < 80; $i++) { $temp = [ $w[$i - 15]->bitwise_rightRotate(1), $w[$i - 15]->bitwise_rightRotate(8), $w[$i - 15]->bitwise_rightShift(7) ]; $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = [ $w[$i - 2]->bitwise_rightRotate(19), $w[$i - 2]->bitwise_rightRotate(61), $w[$i - 2]->bitwise_rightShift(6) ]; $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $w[$i] = clone $w[$i - 16]; $w[$i] = $w[$i]->add($s0); $w[$i] = $w[$i]->add($w[$i - 7]); $w[$i] = $w[$i]->add($s1); } // Initialize hash value for this chunk $a = clone $hash[0]; $b = clone $hash[1]; $c = clone $hash[2]; $d = clone $hash[3]; $e = clone $hash[4]; $f = clone $hash[5]; $g = clone $hash[6]; $h = clone $hash[7]; // Main loop for ($i = 0; $i < 80; $i++) { $temp = [ $a->bitwise_rightRotate(28), $a->bitwise_rightRotate(34), $a->bitwise_rightRotate(39) ]; $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = [ $a->bitwise_and($b), $a->bitwise_and($c), $b->bitwise_and($c) ]; $maj = $temp[0]->bitwise_xor($temp[1]); $maj = $maj->bitwise_xor($temp[2]); $t2 = $s0->add($maj); $temp = [ $e->bitwise_rightRotate(14), $e->bitwise_rightRotate(18), $e->bitwise_rightRotate(41) ]; $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $temp = [ $e->bitwise_and($f), $g->bitwise_and($e->bitwise_not()) ]; $ch = $temp[0]->bitwise_xor($temp[1]); $t1 = $h->add($s1); $t1 = $t1->add($ch); $t1 = $t1->add($k[$i]); $t1 = $t1->add($w[$i]); $h = clone $g; $g = clone $f; $f = clone $e; $e = $d->add($t1); $d = clone $c; $c = clone $b; $b = clone $a; $a = $t1->add($t2); } // Add this chunk's hash to result so far $hash = [ $hash[0]->add($a), $hash[1]->add($b), $hash[2]->add($c), $hash[3]->add($d), $hash[4]->add($e), $hash[5]->add($f), $hash[6]->add($g), $hash[7]->add($h) ]; } // Produce the final hash value (big-endian) // (\phpseclib\Crypt\Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . $hash[4]->toBytes() . $hash[5]->toBytes() . $hash[6]->toBytes() . $hash[7]->toBytes(); return $temp; } } <?php /** * ECDSA Private Key * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA; use phpseclib\Crypt\ECDSA; use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature; use phpseclib\Math\BigInteger; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Crypt\Hash; use phpseclib\Crypt\ECDSA\Curves\Ed25519; use phpseclib\Crypt\ECDSA\Keys\PKCS8; use phpseclib\Crypt\Common; /** * ECDSA Private Key * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PrivateKey extends ECDSA implements Common\PrivateKey { use Common\PasswordProtected; /** * Private Key dA * * sign() converts this to a BigInteger so one might wonder why this is a FiniteFieldInteger instead of * a BigInteger. That's because a FiniteFieldInteger, when converted to a byte string, is null padded by * a certain amount whereas a BigInteger isn't. * * @var object */ protected $dA; /** * Create a signature * * @see self::verify() * @access public * @param string $message * @return mixed */ public function sign($message) { $dA = $this->dA->toBigInteger(); $order = $this->curve->getOrder(); if ($this->curve instanceof TwistedEdwardsCurve) { if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) { return sodium_crypto_sign_detached($message, $this->toString('libsodium')); } // contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not. // quoting https://tools.ietf.org/html/rfc8032#section-8.5 , // "The Ed25519ph and Ed448ph ... SHOULD NOT be used" $A = $this->curve->encodePoint($this->QA); $curve = $this->curve; $hash = new Hash($curve::HASH); $secret = substr($hash->hash($this->dA->secret), $curve::SIZE); if ($curve instanceof Ed25519) { $dom = !isset($this->context) ? '' : 'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context; } else { $context = isset($this->context) ? $this->context : ''; $dom = 'SigEd448' . "\0" . chr(strlen($context)) . $context; } // SHA-512(dom2(F, C) || prefix || PH(M)) $r = $hash->hash($dom . $secret . $message); $r = strrev($r); $r = new BigInteger($r, 256); list(, $r) = $r->divide($order); $R = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($r)); $R = $curve->encodePoint($R); $k = $hash->hash($dom . $R . $A . $message); $k = strrev($k); $k = new BigInteger($k, 256); list(, $k) = $k->divide($order); $S = $k->multiply($dA)->add($r); list(, $S) = $S->divide($order); $S = str_pad(strrev($S->toBytes()), $curve::SIZE, "\0"); return $R . $S; } $shortFormat = $this->shortFormat; $format = $this->format; if ($format === false) { return false; } if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { $signature = ''; // altho PHP's OpenSSL bindings only supported ECDSA key creation in PHP 7.1 they've long // supported signing / verification // we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve; // doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even // has curve-specific optimizations $result = openssl_sign($message, $signature, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); if ($result) { if ($shortFormat == 'ASN1') { return $signature; } extract(ASN1Signature::load($signature)); return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s); } } $e = $this->hash->hash($message); $e = new BigInteger($e, 256); $Ln = $this->hash->getLength() - $order->getLength(); $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e; while (true) { $k = BigInteger::randomRange(self::$one, $order->subtract(self::$one)); list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $this->curve->convertInteger($k)); $x = $x->toBigInteger(); list(, $r) = $x->divide($order); if ($r->equals(self::$zero)) { continue; } $kinv = $k->modInverse($order); $temp = $z->add($dA->multiply($r)); $temp = $kinv->multiply($temp); list(, $s) = $temp->divide($order); if (!$s->equals(self::$zero)) { break; } } // the following is an RFC6979 compliant implementation of deterministic ECDSA // it's unused because it's mainly intended for use when a good CSPRNG isn't // available. if phpseclib's CSPRNG isn't good then even key generation is // suspect /* // if this were actually being used it'd probably be better if this lived in load() and createKey() $this->q = $this->curve->getOrder(); $dA = $this->dA->toBigInteger(); $this->x = $dA; $h1 = $this->hash->hash($message); $k = $this->computek($h1); list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $this->curve->convertInteger($k)); $x = $x->toBigInteger(); list(, $r) = $x->divide($this->q); $kinv = $k->modInverse($this->q); $h1 = $this->bits2int($h1); $temp = $h1->add($dA->multiply($r)); $temp = $kinv->multiply($temp); list(, $s) = $temp->divide($this->q); */ return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s); } /** * Returns the private key * * @param string $type * @param array $options optional * @return string */ public function toString($type, array $options = []) { $type = self::validatePlugin('Keys', $type, 'savePrivateKey'); return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->password, $options); } /** * Returns the public key * * @see self::getPrivateKey() * @access public * @return mixed */ public function getPublicKey() { $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey'); $key = $type::savePublicKey($this->curve, $this->QA); $key = ECDSA::load($key, 'PKCS8') ->withHash($this->hash->getHash()) ->withSignatureFormat($this->shortFormat); if ($this->curve instanceof TwistedEdwardsCurve) { $key = $key->withContext($this->context); } return $key; } } <?php /** * sect571k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect571k1 extends Binary { public function __construct() { $this->setModulo(571, 10, 5, 2, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000000000000000000' . '000000000000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000000000000000000000000000000000000000000000000000' . '000000000000000000000000000000000000000000000000000000000000000000000001' ); $this->setBasePoint( '026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA443709584' . '93B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972', '0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0' . 'AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3' ); $this->setOrder(new BigInteger( '020000000000000000000000000000000000000000000000000000000000000000000000' . '131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001', 16 )); } } <?php /** * brainpoolP320t1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP320t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F9' . '2B9EC7893EC28FCD412B1F1B32E27', 16)); $this->setCoefficients( new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28' . 'FCD412B1F1B32E24', 16), // eg. -3 new BigInteger('A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CE' . 'B5B4FEF422340353', 16) ); $this->setBasePoint( new BigInteger('925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF' . '3357F624A21BED52', 16), new BigInteger('63BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B' . '1B9BC0455FB0D2C3', 16) ); $this->setOrder(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D4' . '82EC7EE8658E98691555B44C59311', 16)); } }<?php /** * sect283r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect283r1 extends Binary { public function __construct() { $this->setModulo(283, 12, 7, 5, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000000000000000001', '027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5' ); $this->setBasePoint( '05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053', '03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4' ); $this->setOrder(new BigInteger('03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307', 16)); } } <?php /** * secp224r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp224r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001', 16)); $this->setCoefficients( new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE', 16), new BigInteger('B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4', 16) ); $this->setBasePoint( new BigInteger('B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21', 16), new BigInteger('BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34', 16) ); $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D', 16)); } } <?php /** * prime192v3 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class prime192v3 extends Prime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16), new BigInteger('22123DC2395A05CAA7423DAECCC94760A7D462256BD56916', 16) ); $this->setBasePoint( new BigInteger('7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896', 16), new BigInteger('38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0', 16) ); $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13', 16)); } }<?php /** * nistp192 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistp192 extends secp192r1 { }<?php /** * nistp384 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistp384 extends secp384r1 { }<?php /** * sect239k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect239k1 extends Binary { public function __construct() { $this->setModulo(239, 158, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000000000000000000000000000000000000001' ); $this->setBasePoint( '29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC', '76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA' ); $this->setOrder(new BigInteger('2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5', 16)); } } <?php /** * sect409k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect409k1 extends Binary { public function __construct() { $this->setModulo(409, 87, 0); $this->setCoefficients( '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' ); $this->setBasePoint( '0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746', '01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B' ); $this->setOrder(new BigInteger( '7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F' . '83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF', 16 )); } } <?php /** * sect193r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect193r2 extends Binary { public function __construct() { $this->setModulo(193, 15, 0); $this->setCoefficients( '0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B', '00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE' ); $this->setBasePoint( '00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F', '01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C' ); $this->setOrder(new BigInteger('010000000000000000000000015AAB561B005413CCD4EE99D5', 16)); } } <?php /** * brainpoolP256t1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP256t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', 16)); $this->setCoefficients( new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374', 16), // eg. -3 new BigInteger('662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04', 16) ); $this->setBasePoint( new BigInteger('A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4', 16), new BigInteger('2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE', 16) ); $this->setOrder(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', 16)); } } <?php /** * sect163r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect163r2 extends Binary { public function __construct() { $this->setModulo(163, 7, 6, 3, 0); $this->setCoefficients( '000000000000000000000000000000000000000001', '020A601907B8C953CA1481EB10512F78744A3205FD' ); $this->setBasePoint( '03F0EBA16286A2D57EA0991168D4994637E8343E36', '00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1' ); $this->setOrder(new BigInteger('040000000000000000000292FE77E70C12A4234C33', 16)); } } <?php /** * nistp256 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistp256 extends secp256r1 { }<?php /** * secp224k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime; use phpseclib\Math\BigInteger; class secp224k1 extends KoblitzPrime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D', 16)); $this->setCoefficients( new BigInteger('00000000000000000000000000000000000000000000000000000000', 16), new BigInteger('00000000000000000000000000000000000000000000000000000005', 16) ); $this->setBasePoint( new BigInteger('A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C', 16), new BigInteger('7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5', 16) ); $this->setOrder(new BigInteger('010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7', 16)); $this->basis = []; $this->basis[] = [ 'a' => new BigInteger('00B8ADF1378A6EB73409FA6C9C637D', -16), 'b' => new BigInteger('94730F82B358A3776A826298FA6F', -16) ]; $this->basis[] = [ 'a' => new BigInteger('01DCE8D2EC6184CAF0A972769FCC8B', -16), 'b' => new BigInteger('4D2100BA3DC75AAB747CCF355DEC', -16) ]; $this->beta = $this->factory->newInteger(new BigInteger('01F178FFA4B17C89E6F73AECE2AAD57AF4C0A748B63C830947B27E04', -16)); } }<?php /** * brainpoolP160r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP160r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16)); $this->setCoefficients( new BigInteger('340E7BE2A280EB74E2BE61BADA745D97E8F7C300', 16), new BigInteger('1E589A8595423412134FAA2DBDEC95C8D8675E58', 16) ); $this->setBasePoint( new BigInteger('BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3', 16), new BigInteger('1667CB477A1A8EC338F94741669C976316DA6321', 16) ); $this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16)); } }<?php /** * nistt571 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistt571 extends sect571k1 { }<?php /** * sect113r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect113r2 extends Binary { public function __construct() { $this->setModulo(113, 9, 0); $this->setCoefficients( '00689918DBEC7E5A0DD6DFC0AA55C7', '0095E9A9EC9B297BD4BF36E059184F' ); $this->setBasePoint( '01A57A6A7B26CA5EF52FCDB8164797', '00B3ADC94ED1FE674C06E695BABA1D' ); $this->setOrder(new BigInteger('010000000000000108789B2496AF93', 16)); } }<?php /** * nistb233 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistb233 extends sect233r1 { }<?php /** * prime256v1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class prime256v1 extends secp256r1 { }<?php /** * sect283k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistk283 extends sect283k1 { }<?php /** * secp192r1 * * This is the NIST P-192 curve * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp192r1 extends Prime { public function __construct() { $modulo = new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16); $this->setModulo($modulo); // algorithm 2.27 from http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=66 /* in theory this should be faster than regular modular reductions save for one small issue. to convert to / from base-2**8 with BCMath you have to call bcmul() and bcdiv() a lot. to convert to / from base-2**8 with PHP64 you have to call base256_rshift() a lot. in short, converting to / from base-2**8 is pretty expensive and that expense is enough to offset whatever else might be gained by a simplified reduction algorithm. now, if PHP supported unsigned integers things might be different. no bit-shifting would be required for the PHP engine and it'd be a lot faster. but as is, BigInteger uses base-2**31 or base-2**26 depending on whether or not the system is has a 32-bit or a 64-bit OS. */ /* $m_length = $this->getLengthInBytes(); $this->setReduction(function($c) use ($m_length) { $cBytes = $c->toBytes(); $className = $this->className; if (strlen($cBytes) > 2 * $m_length) { list(, $r) = $c->divide($className::$modulo); return $r; } $c = str_pad($cBytes, 48, "\0", STR_PAD_LEFT); $c = array_reverse(str_split($c, 8)); $null = "\0\0\0\0\0\0\0\0"; $s1 = new BigInteger($c[2] . $c[1] . $c[0], 256); $s2 = new BigInteger($null . $c[3] . $c[3], 256); $s3 = new BigInteger($c[4] . $c[4] . $null, 256); $s4 = new BigInteger($c[5] . $c[5] . $c[5], 256); $r = $s1->add($s2)->add($s3)->add($s4); while ($r->compare($className::$modulo) >= 0) { $r = $r->subtract($className::$modulo); } return $r; }); */ $this->setCoefficients( new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16), new BigInteger('64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1', 16) ); $this->setBasePoint( new BigInteger('188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012', 16), new BigInteger('07192B95FFC8DA78631011ED6B24CDD573F977A11E794811', 16) ); $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831', 16)); } }<?php /** * secp256k1 * * This is the curve used in Bitcoin * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; //use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime; use phpseclib\Math\BigInteger; //class secp256k1 extends Prime class secp256k1 extends KoblitzPrime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16)); $this->setCoefficients( new BigInteger('0000000000000000000000000000000000000000000000000000000000000000', 16), new BigInteger('0000000000000000000000000000000000000000000000000000000000000007', 16) ); $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16)); $this->setBasePoint( new BigInteger('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16), new BigInteger('483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8', 16) ); $this->basis = []; $this->basis[] = [ 'a' => new BigInteger('3086D221A7D46BCDE86C90E49284EB15', -16), 'b' => new BigInteger('FF1BBC8129FEF177D790AB8056F5401B3D', -16) ]; $this->basis[] = [ 'a' => new BigInteger('114CA50F7A8E2F3F657C1108D9D44CFD8', -16), 'b' => new BigInteger('3086D221A7D46BCDE86C90E49284EB15', -16) ]; $this->beta = $this->factory->newInteger(new BigInteger('7AE96A2B657C07106E64479EAC3434E99CF0497512F58995C1396C28719501EE', -16)); } }<?php /** * sect571r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect571r1 extends Binary { public function __construct() { $this->setModulo(571, 10, 5, 2, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000000000000000000' . '000000000000000000000000000000000000000000000000000000000000000000000001', '02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD' . '8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A' ); $this->setBasePoint( '0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950' . 'F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19', '037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43' . 'BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B' ); $this->setOrder(new BigInteger( '03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . 'E661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47', 16 )); } } <?php /** * nistk409 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistk409 extends sect409k1 { }<?php /** * Ed448 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Hash; use phpseclib\Crypt\Random; class Ed448 extends TwistedEdwards { const HASH = 'shake256-912'; const SIZE = 57; public function __construct() { // 2^448 - 2^224 - 1 $this->setModulo(new BigInteger( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger(1), // -39081 new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6756', 16) ); $this->setBasePoint( new BigInteger('4F1970C66BED0DED221D15A622BF36DA9E146570470F1767EA6DE324' . 'A3D3A46412AE1AF72AB66511433B80E18B00938E2626A82BC70CC05E', 16), new BigInteger('693F46716EB6BC248876203756C9C7624BEA73736CA3984087789C1E' . '05A0C2D73AD3FF1CE67C39C4FDBD132C4ED7C8AD9808795BF230FA14', 16) ); $this->setOrder(new BigInteger( '3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . '7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3', 16)); } /** * Recover X from Y * * Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.2.3 * * Used by ECDSA\Keys\Common.php * * @param BigInteger $x * @param boolean $sign * @return object[] */ public function recoverX(BigInteger $y, $sign) { $y = $this->factory->newInteger($y); $y2 = $y->multiply($y); $u = $y2->subtract($this->one); $v = $this->d->multiply($y2)->subtract($this->one); $x2 = $u->divide($v); if ($x2->equals($this->zero)) { if ($sign) { throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)'); } return clone $this->zero; } // find the square root $exp = $this->getModulo()->add(new BigInteger(1)); $exp = $exp->bitwise_rightShift(2); $x = $x2->pow($exp); if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) { throw new \RuntimeException('Unable to recover X coordinate'); } if ($x->isOdd() != $sign) { $x = $x->negate(); } return [$x, $y]; } /** * Extract Secret Scalar * * Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.2.5 * * Used by the various key handlers * * @param string $str * @return \phpseclib\Math\PrimeField\Integer */ public function extractSecret($str) { if (strlen($str) != 57) { throw new \LengthException('Private Key should be 57-bytes long'); } // 1. Hash the 57-byte private key using SHAKE256(x, 114), storing the // digest in a 114-octet large buffer, denoted h. Only the lower 57 // bytes are used for generating the public key. $hash = new Hash('shake256-912'); $h = $hash->hash($str); $h = substr($h, 0, 57); // 2. Prune the buffer: The two least significant bits of the first // octet are cleared, all eight bits the last octet are cleared, and // the highest bit of the second to last octet is set. $h[0] = $h[0] & chr(0xFC); $h = strrev($h); $h[0] = "\0"; $h[1] = $h[1] | chr(0x80); // 3. Interpret the buffer as the little-endian integer, forming a // secret scalar s. $dA = new BigInteger($h, 256); $dA = $this->factory->newInteger($dA); $dA->secret = $str; return $dA; } /** * Encode a point as a string * * @param string $str * @return string */ public function encodePoint($point) { list($x, $y) = $point; $y = "\0" . $y->toBytes(); if ($x->isOdd()) { $y[0] = $y[0] | chr(0x80); } $y = strrev($y); return $y; } /** * Creates a random scalar multiplier * * @return \phpseclib\Math\PrimeField\Integer */ public function createRandomMultiplier() { return $this->extractSecret(Random::string(57)); } /** * Converts an affine point to an extended homogeneous coordinate * * From https://tools.ietf.org/html/rfc8032#section-5.2.4 : * * A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T), * with x = X/Z, y = Y/Z, x * y = T/Z. * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToInternal(array $p) { if (empty($p)) { return [clone $this->zero, clone $this->one, clone $this->one]; } if (isset($p[2])) { return $p; } $p[2] = clone $this->one; return $p; } /** * Doubles a point on a curve * * @return FiniteField[] */ public function doublePoint(array $p) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p)) { return []; } if (!isset($p[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa'); } // from https://tools.ietf.org/html/rfc8032#page-18 list($x1, $y1, $z1) = $p; $b = $x1->add($y1); $b = $b->multiply($b); $c = $x1->multiply($x1); $d = $y1->multiply($y1); $e = $c->add($d); $h = $z1->multiply($z1); $j = $e->subtract($this->two->multiply($h)); $x3 = $b->subtract($e)->multiply($j); $y3 = $c->subtract($d)->multiply($e); $z3 = $e->multiply($j); return [$x3, $y3, $z3]; } /** * Adds two points on the curve * * @return FiniteField[] */ public function addPoint(array $p, array $q) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p) || !count($q)) { if (count($q)) { return $q; } if (count($p)) { return $p; } return []; } if (!isset($p[2]) || !isset($q[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa'); } if ($p[0]->equals($q[0])) { return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p); } // from https://tools.ietf.org/html/rfc8032#page-17 list($x1, $y1, $z1) = $p; list($x2, $y2, $z2) = $q; $a = $z1->multiply($z2); $b = $a->multiply($a); $c = $x1->multiply($x2); $d = $y1->multiply($y2); $e = $this->d->multiply($c)->multiply($d); $f = $b->subtract($e); $g = $b->add($e); $h = $x1->add($y1)->multiply($x2->add($y2)); $x3 = $a->multiply($f)->multiply($h->subtract($c)->subtract($d)); $y3 = $a->multiply($g)->multiply($d->subtract($c)); $z3 = $f->multiply($g); return [$x3, $y3, $z3]; } }<?php /** * nistk233 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistk233 extends sect233k1 { }<?php /** * brainpoolP256r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP256r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', 16)); $this->setCoefficients( new BigInteger('7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9', 16), new BigInteger('26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6', 16) ); $this->setBasePoint( new BigInteger('8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262', 16), new BigInteger('547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997', 16) ); $this->setOrder(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', 16)); } }<?php /** * brainpoolP512t1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP512t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger( 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' . '66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3', 16)); $this->setCoefficients( new BigInteger( 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' . '66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0', 16), // eg. -3 new BigInteger( '7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA23049' . '76540F6450085F2DAE145C22553B465763689180EA2571867423E', 16) ); $this->setBasePoint( new BigInteger( '640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CD' . 'B3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA', 16), new BigInteger( '5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEE' . 'F216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332', 16) ); $this->setOrder(new BigInteger( 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA' . '92619418661197FAC10471DB1D381085DDADDB58796829CA90069', 16)); } }<?php /** * secp192k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime; use phpseclib\Math\BigInteger; class secp192k1 extends KoblitzPrime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37', 16)); $this->setCoefficients( new BigInteger('000000000000000000000000000000000000000000000000', 16), new BigInteger('000000000000000000000000000000000000000000000003', 16) ); $this->setBasePoint( new BigInteger('DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D', 16), new BigInteger('9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D', 16) ); $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D', 16)); $this->basis = []; $this->basis[] = [ 'a' => new BigInteger('00B3FB3400DEC5C4ADCEB8655C', -16), 'b' => new BigInteger('8EE96418CCF4CFC7124FDA0F', -16) ]; $this->basis[] = [ 'a' => new BigInteger('01D90D03E8F096B9948B20F0A9', -16), 'b' => new BigInteger('42E49819ABBA9474E1083F6B', -16) ]; $this->beta = $this->factory->newInteger(new BigInteger('447A96E6C647963E2F7809FEAAB46947F34B0AA3CA0BBA74', -16)); } }<?php /** * nistp521 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistp521 extends secp521r1 { }<?php /** * brainpoolP512r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP512r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger( 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' . '66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3', 16)); $this->setCoefficients( new BigInteger( '7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA82' . '53AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA', 16), new BigInteger( '3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C' . '1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723', 16) ); $this->setBasePoint( new BigInteger( '81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D' . '0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822', 16), new BigInteger( '7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5' . 'F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892', 16) ); $this->setOrder(new BigInteger( 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA' . '92619418661197FAC10471DB1D381085DDADDB58796829CA90069', 16)); } }<?php /** * sect163k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect163k1 extends Binary { public function __construct() { $this->setModulo(163, 7, 6, 3, 0); $this->setCoefficients( '000000000000000000000000000000000000000001', '000000000000000000000000000000000000000001' ); $this->setBasePoint( '02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8', '0289070FB05D38FF58321F2E800536D538CCDAA3D9' ); $this->setOrder(new BigInteger('04000000000000000000020108A2E0CC0D99F8A5EF', 16)); } }<?php /** * secp160r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp160r2 extends Prime { public function __construct() { // same as secp160k1 $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73', 16)); $this->setCoefficients( new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70', 16), new BigInteger('B4E134D3FB59EB8BAB57274904664D5AF50388BA', 16) ); $this->setBasePoint( new BigInteger('52DCB034293A117E1F4FF11B30F7199D3144CE6D', 16), new BigInteger('FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E', 16) ); $this->setOrder(new BigInteger('0100000000000000000000351EE786A818F3A1A16B', 16)); } }<?php /** * nistp224 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistp224 extends secp224r1 { }<?php /** * nistk163 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistk163 extends sect163k1 { }<?php /** * sect409r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect409r1 extends Binary { public function __construct() { $this->setModulo(409, 87, 0); $this->setCoefficients( '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001', '0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F' ); $this->setBasePoint( '015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7', '0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706' ); $this->setOrder(new BigInteger( '010000000000000000000000000000000000000000000000000001E2' . 'AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173', 16 )); } } <?php /** * nistb409 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class nistb409 extends sect409r1 { }<?php /** * brainpoolP160t1 * * This curve is a twisted version of brainpoolP160r1 with A = -3. With brainpool, * the curves ending in r1 are the "regular" curves and the curves ending in "t1" * are the twisted version of the r1 curves. Per https://tools.ietf.org/html/rfc5639#page-7 * you can convert a point on an r1 curve to a point on a t1 curve thusly: * * F(x,y) := (x*Z^2, y*Z^3) * * The advantage of A = -3 is that some of the point doubling and point addition can be * slightly optimized. See http://hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html * vs http://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html for example. * * phpseclib does not currently take advantage of this optimization opportunity * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP160t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16)); $this->setCoefficients( new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620C', 16), // eg. -3 new BigInteger('7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380', 16) ); $this->setBasePoint( new BigInteger('B199B13B9B34EFC1397E64BAEB05ACC265FF2378', 16), new BigInteger('ADD6718B7C7C1961F0991B842443772152C9E0AD', 16) ); $this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16)); } }<?php /** * secp112r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp112r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('DB7C2ABF62E35E668076BEAD208B', 16)); $this->setCoefficients( new BigInteger('DB7C2ABF62E35E668076BEAD2088', 16), new BigInteger('659EF8BA043916EEDE8911702B22', 16) ); $this->setBasePoint( new BigInteger('09487239995A5EE76B55F9C2F098', 16), new BigInteger('A89CE5AF8724C0A23E0E0FF77500', 16) ); $this->setOrder(new BigInteger('DB7C2ABF62E35E7628DFAC6561C5', 16)); } }<?php /** * brainpoolP384t1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP384t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger( '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A7' . '1874700133107EC53', 16)); $this->setCoefficients( new BigInteger( '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901' . 'D1A71874700133107EC50', 16), // eg. -3 new BigInteger( '7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B8' . '8805CED70355A33B471EE', 16) ); $this->setBasePoint( new BigInteger( '18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946' . 'A5F54D8D0AA2F418808CC', 16), new BigInteger( '25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC' . '2B2912675BF5B9E582928', 16) ); $this->setOrder(new BigInteger( '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC31' . '03B883202E9046565', 16)); } }<?php /** * brainpoolP224t1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP224t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF', 16)); $this->setCoefficients( new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC', 16), // eg. -3 new BigInteger('4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D', 16) ); $this->setBasePoint( new BigInteger('6AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D580', 16), new BigInteger('0374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C', 16) ); $this->setOrder(new BigInteger('D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F', 16)); } }<?php /** * sect131r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect131r2 extends Binary { public function __construct() { $this->setModulo(131, 8, 3, 2, 0); $this->setCoefficients( '03E5A88919D7CAFCBF415F07C2176573B2', '04B8266A46C55657AC734CE38F018F2192' ); $this->setBasePoint( '0356DCD8F2F95031AD652D23951BB366A8', '0648F06D867940A5366D9E265DE9EB240F' ); $this->setOrder(new BigInteger('0400000000000000016954A233049BA98F', 16)); } }<?php /** * secp384r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp384r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF', 16 )); $this->setCoefficients( new BigInteger( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC', 16 ), new BigInteger( 'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF', 16 ) ); $this->setBasePoint( new BigInteger( 'AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7', 16 ), new BigInteger( '3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F', 16 ) ); $this->setOrder(new BigInteger( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973', 16 )); } }<?php /** * secp128r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp128r2 extends Prime { public function __construct() { // same as secp128r1 $this->setModulo(new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('D6031998D1B3BBFEBF59CC9BBFF9AEE1', 16), new BigInteger('5EEEFCA380D02919DC2C6558BB6D8A5D', 16) ); $this->setBasePoint( new BigInteger('7B6AA5D85E572983E6FB32A7CDEBC140', 16), new BigInteger('27B6916A894D3AEE7106FE805FC34B44', 16) ); $this->setOrder(new BigInteger('3FFFFFFF7FFFFFFFBE0024720613B5A3', 16)); } }<?php /** * secp160r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp160r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF', 16)); $this->setCoefficients( new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC', 16), new BigInteger('1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45', 16) ); $this->setBasePoint( new BigInteger('4A96B5688EF573284664698968C38BB913CBFC82', 16), new BigInteger('23A628553168947D59DCC912042351377AC5FB32', 16) ); $this->setOrder(new BigInteger('0100000000000000000001F4C8F927AED3CA752257', 16)); } }<?php /** * secp160k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime; use phpseclib\Math\BigInteger; class secp160k1 extends KoblitzPrime { public function __construct() { // same as secp160r2 $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73', 16)); $this->setCoefficients( new BigInteger('0000000000000000000000000000000000000000', 16), new BigInteger('0000000000000000000000000000000000000007', 16) ); $this->setBasePoint( new BigInteger('3B4C382CE37AA192A4019E763036F4F5DD4D7EBB', 16), new BigInteger('938CF935318FDCED6BC28286531733C3F03C4FEE', 16) ); $this->setOrder(new BigInteger('0100000000000000000001B8FA16DFAB9ACA16B6B3', 16)); $this->basis = []; $this->basis[] = [ 'a' => new BigInteger('0096341F1138933BC2F505', -16), 'b' => new BigInteger('FF6E9D0418C67BB8D5F562', -16) ]; $this->basis[] = [ 'a' => new BigInteger('01BDCB3A09AAAABEAFF4A8', -16), 'b' => new BigInteger('04D12329FF0EF498EA67', -16) ]; $this->beta = $this->factory->newInteger(new BigInteger('645B7345A143464942CC46D7CF4D5D1E1E6CBB68', -16)); } }<?php /** * prime192v1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; final class prime192v1 extends secp192r1 { }<?php /** * secp256r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp256r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', 16), new BigInteger('5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', 16) ); $this->setBasePoint( new BigInteger('6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296', 16), new BigInteger('4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', 16) ); $this->setOrder(new BigInteger('FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', 16)); } } <?php /** * brainpoolP224r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP224r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF', 16)); $this->setCoefficients( new BigInteger('68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43', 16), new BigInteger('2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B', 16) ); $this->setBasePoint( new BigInteger('0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D', 16), new BigInteger('58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD', 16) ); $this->setOrder(new BigInteger('D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F', 16)); } }<?php /** * prime239v2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class prime239v2 extends Prime { public function __construct() { $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16), new BigInteger('617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C', 16) ); $this->setBasePoint( new BigInteger('38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7', 16), new BigInteger('5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA', 16) ); $this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063', 16)); } }<?php /** * secp128r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp128r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC', 16), new BigInteger('E87579C11079F43DD824993C2CEE5ED3', 16) ); $this->setBasePoint( new BigInteger('161FF7528B899B2D0C28607CA52C5B86', 16), new BigInteger('CF5AC8395BAFEB13C02DA292DDED7A83', 16) ); $this->setOrder(new BigInteger('FFFFFFFE0000000075A30D1B9038A115', 16)); } }<?php /** * secp112r2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp112r2 extends Prime { public function __construct() { // same modulo as secp112r1 $this->setModulo(new BigInteger('DB7C2ABF62E35E668076BEAD208B', 16)); $this->setCoefficients( new BigInteger('6127C24C05F38A0AAAF65C0EF02C', 16), new BigInteger('51DEF1815DB5ED74FCC34C85D709', 16) ); $this->setBasePoint( new BigInteger('4BA30AB5E892B4E1649DD0928643', 16), new BigInteger('ADCD46F5882E3747DEF36E956E97', 16) ); $this->setOrder(new BigInteger('36DF0AAFD8B8D7597CA10520D04B', 16)); } }<?php /** * sect193r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect193r1 extends Binary { public function __construct() { $this->setModulo(193, 15, 0); $this->setCoefficients( '0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01', '00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814' ); $this->setBasePoint( '01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1', '0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05' ); $this->setOrder(new BigInteger('01000000000000000000000000C7F34A778F443ACC920EBA49', 16)); } } <?php /** * sect131r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect131r1 extends Binary { public function __construct() { $this->setModulo(131, 8, 3, 2, 0); $this->setCoefficients( '07A11B09A76B562144418FF3FF8C2570B8', '0217C05610884B63B9C6C7291678F9D341' ); $this->setBasePoint( '0081BAF91FDF9833C40F9C181343638399', '078C6E7EA38C001F73C8134B1B4EF9E150' ); $this->setOrder(new BigInteger('0400000000000000023123953A9464B54D', 16)); } }<?php /** * sect233r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect233r1 extends Binary { public function __construct() { $this->setModulo(233, 74, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000001', '0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD' ); $this->setBasePoint( '00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B', '01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052' ); $this->setOrder(new BigInteger('01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7', 16)); } } <?php /** * Ed25519 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Hash; use phpseclib\Crypt\Random; class Ed25519 extends TwistedEdwards { const HASH = 'sha512'; /* Per https://tools.ietf.org/html/rfc8032#page-6 EdDSA has several parameters, one of which is b: 2. An integer b with 2^(b-1) > p. EdDSA public keys have exactly b bits, and EdDSA signatures have exactly 2*b bits. b is recommended to be a multiple of 8, so public key and signature lengths are an integral number of octets. SIZE corresponds to b */ const SIZE = 32; public function __construct() { // 2^255 - 19 $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED', 16)); $this->setCoefficients( // -1 new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC', 16), // a // -121665/121666 new BigInteger('52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3', 16) // d ); $this->setBasePoint( new BigInteger('216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A', 16), new BigInteger('6666666666666666666666666666666666666666666666666666666666666658', 16) ); $this->setOrder(new BigInteger('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED', 16)); // algorithm 14.47 from http://cacr.uwaterloo.ca/hac/about/chap14.pdf#page=16 /* $this->setReduction(function($x) { $parts = $x->bitwise_split(255); $className = $this->className; if (count($parts) > 2) { list(, $r) = $x->divide($className::$modulo); return $r; } $zero = new BigInteger(); $c = new BigInteger(19); switch (count($parts)) { case 2: list($qi, $ri) = $parts; break; case 1: $qi = $zero; list($ri) = $parts; break; case 0: return $zero; } $r = $ri; while ($qi->compare($zero) > 0) { $temp = $qi->multiply($c)->bitwise_split(255); if (count($temp) == 2) { list($qi, $ri) = $temp; } else { $qi = $zero; list($ri) = $temp; } $r = $r->add($ri); } while ($r->compare($className::$modulo) > 0) { $r = $r->subtract($className::$modulo); } return $r; }); */ } /** * Recover X from Y * * Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.1.3 * * Used by ECDSA\Keys\Common.php * * @param BigInteger $x * @param boolean $sign * @return object[] */ public function recoverX(BigInteger $y, $sign) { $y = $this->factory->newInteger($y); $y2 = $y->multiply($y); $u = $y2->subtract($this->one); $v = $this->d->multiply($y2)->add($this->one); $x2 = $u->divide($v); if ($x2->equals($this->zero)) { if ($sign) { throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)'); } return clone $this->zero; } // find the square root /* we don't do $x2->squareRoot() because, quoting from https://tools.ietf.org/html/rfc8032#section-5.1.1: "For point decoding or "decompression", square roots modulo p are needed. They can be computed using the Tonelli-Shanks algorithm or the special case for p = 5 (mod 8). To find a square root of a, first compute the candidate root x = a^((p+3)/8) (mod p)." */ $exp = $this->getModulo()->add(new BigInteger(3)); $exp = $exp->bitwise_rightShift(3); $x = $x2->pow($exp); // If v x^2 = -u (mod p), set x <-- x * 2^((p-1)/4), which is a square root. if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) { $temp = $this->getModulo()->subtract(new BigInteger(1)); $temp = $temp->bitwise_rightShift(2); $temp = $this->two->pow($temp); $x = $x->multiply($temp); if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) { throw new \RuntimeException('Unable to recover X coordinate'); } } if ($x->isOdd() != $sign) { $x = $x->negate(); } return [$x, $y]; } /** * Extract Secret Scalar * * Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.1.5 * * Used by the various key handlers * * @param string $str * @return \phpseclib\Math\PrimeField\Integer */ public function extractSecret($str) { if (strlen($str) != 32) { throw new \LengthException('Private Key should be 32-bytes long'); } // 1. Hash the 32-byte private key using SHA-512, storing the digest in // a 64-octet large buffer, denoted h. Only the lower 32 bytes are // used for generating the public key. $hash = new Hash('sha512'); $h = $hash->hash($str); $h = substr($h, 0, 32); // 2. Prune the buffer: The lowest three bits of the first octet are // cleared, the highest bit of the last octet is cleared, and the // second highest bit of the last octet is set. $h[0] = $h[0] & chr(0xF8); $h = strrev($h); $h[0] = ($h[0] & chr(0x3F)) | chr(0x40); // 3. Interpret the buffer as the little-endian integer, forming a // secret scalar s. $dA = new BigInteger($h, 256); $dA = $this->factory->newInteger($dA); $dA->secret = $str; return $dA; } /** * Encode a point as a string * * @param string $str * @return string */ public function encodePoint($point) { list($x, $y) = $point; $y = $y->toBytes(); $y[0] = $y[0] & chr(0x7F); if ($x->isOdd()) { $y[0] = $y[0] | chr(0x80); } $y = strrev($y); return $y; } /** * Creates a random scalar multiplier * * @return \phpseclib\Math\PrimeField\Integer */ public function createRandomMultiplier() { return $this->extractSecret(Random::string(32)); } /** * Converts an affine point to an extended homogeneous coordinate * * From https://tools.ietf.org/html/rfc8032#section-5.1.4 : * * A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T), * with x = X/Z, y = Y/Z, x * y = T/Z. * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToInternal(array $p) { if (empty($p)) { return [clone $this->zero, clone $this->one, clone $this->one, clone $this->zero]; } if (isset($p[2])) { return $p; } $p[2] = clone $this->one; $p[3] = $p[0]->multiply($p[1]); return $p; } /** * Doubles a point on a curve * * @return FiniteField[] */ public function doublePoint(array $p) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p)) { return []; } if (!isset($p[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa'); } // from https://tools.ietf.org/html/rfc8032#page-12 list($x1, $y1, $z1, $t1) = $p; $a = $x1->multiply($x1); $b = $y1->multiply($y1); $c = $this->two->multiply($z1)->multiply($z1); $h = $a->add($b); $temp = $x1->add($y1); $e = $h->subtract($temp->multiply($temp)); $g = $a->subtract($b); $f = $c->add($g); $x3 = $e->multiply($f); $y3 = $g->multiply($h); $t3 = $e->multiply($h); $z3 = $f->multiply($g); return [$x3, $y3, $z3, $t3]; } /** * Adds two points on the curve * * @return FiniteField[] */ public function addPoint(array $p, array $q) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p) || !count($q)) { if (count($q)) { return $q; } if (count($p)) { return $p; } return []; } if (!isset($p[2]) || !isset($q[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa'); } if ($p[0]->equals($q[0])) { return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p); } // from https://tools.ietf.org/html/rfc8032#page-12 list($x1, $y1, $z1, $t1) = $p; list($x2, $y2, $z2, $t2) = $q; $a = $y1->subtract($x1)->multiply($y2->subtract($x2)); $b = $y1->add($x1)->multiply($y2->add($x2)); $c = $t1->multiply($this->two)->multiply($this->d)->multiply($t2); $d = $z1->multiply($this->two)->multiply($z2); $e = $b->subtract($a); $f = $d->subtract($c); $g = $d->add($c); $h = $b->add($a); $x3 = $e->multiply($f); $y3 = $g->multiply($h); $t3 = $e->multiply($h); $z3 = $f->multiply($g); return [$x3, $y3, $z3, $t3]; } }<?php /** * prime239v3 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class prime239v3 extends Prime { public function __construct() { $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16), new BigInteger('255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E', 16) ); $this->setBasePoint( new BigInteger('6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A', 16), new BigInteger('1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3', 16) ); $this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551', 16)); } }<?php /** * sect113r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect113r1 extends Binary { public function __construct() { $this->setModulo(113, 9, 0); $this->setCoefficients( '003088250CA6E7C7FE649CE85820F7', '00E8BEE4D3E2260744188BE0E9C723' ); $this->setBasePoint( '009D73616F35F4AB1407D73562C10F', '00A52830277958EE84D1315ED31886' ); $this->setOrder(new BigInteger('0100000000000000D9CCEC8A39E56F', 16)); } }<?php /** * brainpoolP192t1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP192t1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297', 16)); $this->setCoefficients( new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294', 16), // eg. -3 new BigInteger('13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79', 16) ); $this->setBasePoint( new BigInteger('3AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129', 16), new BigInteger('097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9', 16) ); $this->setOrder(new BigInteger('C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1', 16)); } }<?php /** * brainpoolP192r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP192r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297', 16)); $this->setCoefficients( new BigInteger('6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF', 16), new BigInteger('469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9', 16) ); $this->setBasePoint( new BigInteger('C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6', 16), new BigInteger('14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F', 16) ); $this->setOrder(new BigInteger('C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1', 16)); } }<?php /** * brainpoolP320r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP320r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F9' . '2B9EC7893EC28FCD412B1F1B32E27', 16)); $this->setCoefficients( new BigInteger('3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F4' . '92F375A97D860EB4', 16), new BigInteger('520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD88453981' . '6F5EB4AC8FB1F1A6', 16) ); $this->setBasePoint( new BigInteger('43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C7' . '10AF8D0D39E20611', 16), new BigInteger('14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7' . 'D35245D1692E8EE1', 16) ); $this->setOrder(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D4' . '82EC7EE8658E98691555B44C59311', 16)); } }<?php /** * brainpoolP384r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class brainpoolP384r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger( '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A7' . '1874700133107EC53', 16)); $this->setCoefficients( new BigInteger( '7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503' . 'AD4EB04A8C7DD22CE2826', 16), new BigInteger( '4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DB' . 'C9943AB78696FA504C11', 16) ); $this->setBasePoint( new BigInteger( '1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D' . '646AAEF87B2E247D4AF1E', 16), new BigInteger( '8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E464621779' . '1811142820341263C5315', 16) ); $this->setOrder(new BigInteger( '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC31' . '03B883202E9046565', 16)); } }<?php /** * sect163r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect163r1 extends Binary { public function __construct() { $this->setModulo(163, 7, 6, 3, 0); $this->setCoefficients( '07B6882CAAEFA84F9554FF8428BD88E246D2782AE2', '0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9' ); $this->setBasePoint( '0369979697AB43897789566789567F787A7876A654', '00435EDB42EFAFB2989D51FEFCE3C80988F41FF883' ); $this->setOrder(new BigInteger('03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B', 16)); } }<?php /** * sect233k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect233k1 extends Binary { public function __construct() { $this->setModulo(233, 74, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000000000000000000000000000000000000001' ); $this->setBasePoint( '017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126', '01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3' ); $this->setOrder(new BigInteger('8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF', 16)); } } <?php /** * sect283k1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wiggint on <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Binary; use phpseclib\Math\BigInteger; class sect283k1 extends Binary { public function __construct() { $this->setModulo(283, 12, 7, 5, 0); $this->setCoefficients( '000000000000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000000000000000000000000000000000000000000000000001' ); $this->setBasePoint( '0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836', '01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259' ); $this->setOrder(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61', 16)); } } <?php /** * prime192v2 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class prime192v2 extends Prime { public function __construct() { $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16), new BigInteger('CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953', 16) ); $this->setBasePoint( new BigInteger('EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A', 16), new BigInteger('6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15', 16) ); $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31', 16)); } }<?php /** * prime239v1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class prime239v1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16)); $this->setCoefficients( new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16), new BigInteger('6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A', 16) ); $this->setBasePoint( new BigInteger('0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF', 16), new BigInteger('7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE', 16) ); $this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B', 16)); } }<?php /** * secp521r1 * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\Curves; use phpseclib\Crypt\ECDSA\BaseCurves\Prime; use phpseclib\Math\BigInteger; class secp521r1 extends Prime { public function __construct() { $this->setModulo(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . 'FFFF', 16)); $this->setCoefficients( new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . 'FFFC', 16), new BigInteger('0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF1' . '09E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B50' . '3F00', 16) ); $this->setBasePoint( new BigInteger('00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D' . '3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5' . 'BD66', 16), new BigInteger('011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E' . '662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD1' . '6650', 16) ); $this->setOrder(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . 'FFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E9138' . '6409', 16)); } }<?php /** * libsodium Key Handler * * Different NaCl implementations store the key differently. * https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/ elaborates. * libsodium appears to use the same format as SUPERCOP. * * PHP version 5 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use phpseclib\Crypt\ECDSA\Curves\Ed25519; use phpseclib\Math\Common\FiniteField\Integer; /** * libsodium Key Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class libsodium { use Common; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { switch (strlen($key)) { case 32: $public = $key; break; case 64: $private = substr($key, 0, 32); $public = substr($key, -32); break; case 96: $public = substr($key, -32); if (substr($key, 32, 32) != $public) { throw new \RuntimeException('Keys with 96 bytes should have the 2nd and 3rd set of 32 bytes match'); } $private = substr($key, 0, 32); break; default: throw new \RuntimeException('libsodium keys need to either be 32 bytes long, 64 bytes long or 96 bytes long'); } $curve = new Ed25519(); $components = ['curve' => $curve]; if (isset($private)) { $components['dA'] = $curve->extractSecret($private); } $components['QA'] = isset($public) ? self::extractPoint($public, $curve) : $curve->multiplyPoint($curve->getBasePoint(), $components['dA']); return $components; } /** * Convert an ECDSA public key to the appropriate format * * @access public * @param \phpseclib\Crypt\ECDSA\Curves\Ed25519 $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @return string */ public static function savePublicKey(Ed25519 $curve, array $publicKey) { return $curve->encodePoint($publicKey); } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\Common\FiniteField\Integer $privateKey * @param \phpseclib\Crypt\ECDSA\Curves\Ed25519 $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param string $password optional * @return string */ public static function savePrivateKey(Integer $privateKey, Ed25519 $curve, array $publicKey, $password = '') { if (!isset($privateKey->secret)) { throw new \RuntimeException('Private Key does not have a secret set'); } if (strlen($privateKey->secret) != 32) { throw new \RuntimeException('Private Key secret is not of the correct length'); } return $privateKey->secret . $curve->encodePoint($publicKey); } } <?php /** * XML Formatted ECDSA Key Handler * * More info: * * https://www.w3.org/TR/xmldsig-core/#sec-ECKeyValue * http://en.wikipedia.org/wiki/XML_Signature * * PHP version 5 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve; use phpseclib\Crypt\ECDSA\BaseCurves\Prime as PrimeCurve; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Exception\UnsupportedCurveException; /** * XML Formatted ECDSA Key Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class XML { use Common; /** * Default namespace * * @var string */ private static $namespace; /** * Flag for using RFC4050 syntax * * @var bool */ private static $rfc4050 = false; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { self::initialize_static_variables(); if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $use_errors = libxml_use_internal_errors(true); $temp = self::isolateNamespace($key, 'http://www.w3.org/2009/xmldsig11#'); if ($temp) { $key = $temp; } $temp = self::isolateNamespace($key, 'http://www.w3.org/2001/04/xmldsig-more#'); if ($temp) { $key = $temp; } $dom = new \DOMDocument(); if (substr($key, 0, 5) != '<?xml') { $key = '<xml>' . $key . '</xml>'; } if (!$dom->loadXML($key)) { libxml_use_internal_errors($use_errors); throw new \UnexpectedValueException('Key does not appear to contain XML'); } $xpath = new \DOMXPath($dom); libxml_use_internal_errors($use_errors); $curve = self::loadCurveByParam($xpath); $pubkey = self::query($xpath, 'publickey', 'Public Key is not present'); $QA = self::query($xpath, 'ecdsakeyvalue')->length ? self::extractPointRFC4050($xpath, $curve) : self::extractPoint("\0" . $pubkey, $curve); libxml_use_internal_errors($use_errors); return compact('curve', 'QA'); } /** * Case-insensitive xpath query * * @param \DOMXPath $xpath * @param string $name * @param string $error optional * @param bool $decode optional * @return \DOMNodeList */ private static function query($xpath, $name, $error = null, $decode = true) { $query = '/'; $names = explode('/', $name); foreach ($names as $name) { $query.= "/*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$name']"; } $result = $xpath->query($query); if (!isset($error)) { return $result; } if (!$result->length) { throw new \RuntimeException($error); } return $decode ? self::decodeValue($result->item(0)->textContent) : $result->item(0)->textContent; } /** * Finds the first element in the relevant namespace, strips the namespacing and returns the XML for that element. * * @param string $xml * @param string $ns */ private static function isolateNamespace($xml, $ns) { $dom = new \DOMDocument(); if (!$dom->loadXML($xml)) { return false; } $xpath = new \DOMXPath($dom); $nodes = $xpath->query("//*[namespace::*[.='$ns'] and not(../namespace::*[.='$ns'])]"); if (!$nodes->length) { return false; } $node = $nodes->item(0); $ns_name = $node->lookupPrefix($ns); $node->removeAttributeNS($ns, $ns_name); return $dom->saveXML($node); } /** * Decodes the value * * @param string $value */ private static function decodeValue($value) { return Base64::decode(str_replace(["\r", "\n", ' ', "\t"], '', $value)); } /** * Extract points from an XML document * * @param \DOMXPath $xpath * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @return object[] */ private static function extractPointRFC4050(\DOMXPath $xpath, BaseCurve $curve) { $x = self::query($xpath, 'publickey/x'); $y = self::query($xpath, 'publickey/y'); if (!$x->length || !$x->item(0)->hasAttribute('Value')) { throw new \RuntimeException('Public Key / X coordinate not found'); } if (!$y->length || !$y->item(0)->hasAttribute('Value')) { throw new \RuntimeException('Public Key / Y coordinate not found'); } $point = [ $curve->convertInteger(new BigInteger($x->item(0)->getAttribute('Value'))), $curve->convertInteger(new BigInteger($y->item(0)->getAttribute('Value'))) ]; if (!$curve->verifyPoint($point)) { throw new \RuntimeException('Unable to verify that point exists on curve'); } return $point; } /** * Returns an instance of \phpseclib\Crypt\ECDSA\BaseCurves\Base based * on the curve parameters * * @param \DomXPath $xpath * @return \phpseclib\Crypt\ECDSA\BaseCurves\Base|false */ private static function loadCurveByParam(\DOMXPath $xpath) { $namedCurve = self::query($xpath, 'namedcurve'); if ($namedCurve->length == 1) { $oid = $namedCurve->item(0)->getAttribute('URN'); $oid = preg_replace('#[^\d.]#', '', $oid); $name = array_search($oid, self::$curveOIDs); if ($name === false) { throw new UnsupportedCurveException('Curve with OID of ' . $oid . ' is not supported'); } $curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $name; if (!class_exists($curve)) { throw new UnsupportedCurveException('Named Curve of ' . $name . ' is not supported'); } return new $curve(); } $params = self::query($xpath, 'explicitparams'); if ($params->length) { return self::loadCurveByParamRFC4050($xpath); } $params = self::query($xpath, 'ecparameters'); if (!$params->length) { throw new \RuntimeException('No parameters are present'); } $fieldTypes = [ 'prime-field' => ['fieldid/prime/p'], 'gnb' => ['fieldid/gnb/m'], 'tnb' => ['fieldid/tnb/k'], 'pnb' => ['fieldid/pnb/k1', 'fieldid/pnb/k2', 'fieldid/pnb/k3'], 'unknown' => [] ]; foreach ($fieldTypes as $type => $queries) { foreach ($queries as $query) { $result = self::query($xpath, $query); if (!$result->length) { continue 2; } $param = preg_replace('#.*/#', '', $query); $$param = self::decodeValue($result->item(0)->textContent); } break; } $a = self::query($xpath, 'curve/a', 'A coefficient is not present'); $b = self::query($xpath, 'curve/b', 'B coefficient is not present'); $base = self::query($xpath, 'base', 'Base point is not present'); $order = self::query($xpath, 'order', 'Order is not present'); switch ($type) { case 'prime-field': $curve = new PrimeCurve(); $curve->setModulo(new BigInteger($p, 256)); $curve->setCoefficients( new BigInteger($a, 256), new BigInteger($b, 256) ); $point = self::extractPoint("\0" . $base, $curve); $curve->setBasePoint(...$point); $curve->setOrder(new BigInteger($order, 256)); return $curve; case 'gnb': case 'tnb': case 'pnb': default: throw new UnsupportedCurveException('Field Type of ' . $type . ' is not supported'); } } /** * Returns an instance of \phpseclib\Crypt\ECDSA\BaseCurves\Base based * on the curve parameters * * @param \DomXPath $xpath * @return \phpseclib\Crypt\ECDSA\BaseCurves\Base|false */ private static function loadCurveByParamRFC4050(\DOMXPath $xpath) { $fieldTypes = [ 'prime-field' => ['primefieldparamstype/p'], 'unknown' => [] ]; foreach ($fieldTypes as $type => $queries) { foreach ($queries as $query) { $result = self::query($xpath, $query); if (!$result->length) { continue 2; } $param = preg_replace('#.*/#', '', $query); $$param = $result->item(0)->textContent; } break; } $a = self::query($xpath, 'curveparamstype/a', 'A coefficient is not present', false); $b = self::query($xpath, 'curveparamstype/b', 'B coefficient is not present', false); $x = self::query($xpath, 'basepointparams/basepoint/ecpointtype/x', 'Base Point X is not present', false); $y = self::query($xpath, 'basepointparams/basepoint/ecpointtype/y', 'Base Point Y is not present', false); $order = self::query($xpath, 'order', 'Order is not present', false); switch ($type) { case 'prime-field': $curve = new PrimeCurve(); $p = str_replace(["\r", "\n", ' ', "\t"], '', $p); $curve->setModulo(new BigInteger($p)); $a = str_replace(["\r", "\n", ' ', "\t"], '', $a); $b = str_replace(["\r", "\n", ' ', "\t"], '', $b); $curve->setCoefficients( new BigInteger($a), new BigInteger($b) ); $x = str_replace(["\r", "\n", ' ', "\t"], '', $x); $y = str_replace(["\r", "\n", ' ', "\t"], '', $y); $curve->setBasePoint( new BigInteger($x), new BigInteger($y) ); $order = str_replace(["\r", "\n", ' ', "\t"], '', $order); $curve->setOrder(new BigInteger($order)); return $curve; default: throw new UnsupportedCurveException('Field Type of ' . $type . ' is not supported'); } } /** * Sets the namespace. dsig11 is the most common one. * * Set to null to unset. Used only for creating public keys. * * @param string $namespace */ public static function setNamespace($namespace) { self::$namespace = $namespace; } /** * Uses the XML syntax specified in https://tools.ietf.org/html/rfc4050 */ public static function enableRFC4050Syntax() { self::$rfc4050 = true; } /** * Uses the XML syntax specified in https://www.w3.org/TR/xmldsig-core/#sec-ECParameters */ public static function disableRFC4050Syntax() { self::$rfc4050 = false; } /** * Convert a public key to the appropriate format * * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param array $options optional * @return string */ public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = []) { self::initialize_static_variables(); if ($curve instanceof TwistedEdwardsCurve) { throw new UnsupportedCurveException('TwistedEdwards Curves are not supported'); } if (empty(static::$namespace)) { $pre = $post = ''; } else { $pre = static::$namespace . ':'; $post = ':' . static::$namespace; } if (self::$rfc4050) { return '<' . $pre . 'ECDSAKeyValue xmlns' . $post . '="http://www.w3.org/2001/04/xmldsig-more#">' . "\r\n" . self::encodeXMLParameters($curve, $pre, $options) . "\r\n" . '<' . $pre . 'PublicKey>' . "\r\n" . '<' . $pre . 'X Value="' . $publicKey[0] . '" />' . "\r\n" . '<' . $pre . 'Y Value="' . $publicKey[1] . '" />' . "\r\n" . '</' . $pre . 'PublicKey>' . "\r\n" . '</' . $pre . 'ECDSAKeyValue>'; } $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); return '<' . $pre . 'ECKeyValue xmlns' . $post . '="http://www.w3.org/2009/xmldsig11#">' . "\r\n" . self::encodeXMLParameters($curve, $pre, $options) . "\r\n" . '<' . $pre . 'PublicKey>' . Base64::encode($publicKey) . '</' . $pre . 'PublicKey>' . "\r\n" . '</' . $pre . 'ECKeyValue>'; } /** * Encode Parameters * * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param string $pre * @param array $options optional * @return string|false */ private static function encodeXMLParameters(BaseCurve $curve, $pre, array $options = []) { $result = self::encodeParameters($curve, true, $options); if (isset($result['namedCurve'])) { $namedCurve = '<' . $pre . 'NamedCurve URI="urn:oid:' . self::$curveOIDs[$result['namedCurve']] . '" />'; return self::$rfc4050 ? '<DomainParameters>' . str_replace('URI', 'URN', $namedCurve) . '</DomainParameters>' : $namedCurve; } if (self::$rfc4050) { $xml = '<' . $pre . 'ExplicitParams>' . "\r\n" . '<' . $pre . 'FieldParams>' . "\r\n"; $temp = $result['specifiedCurve']; switch ($temp['fieldID']['fieldType']) { case 'prime-field': $xml.= '<' . $pre . 'PrimeFieldParamsType>' . "\r\n" . '<' . $pre . 'P>' . $temp['fieldID']['parameters'] . '</' . $pre . 'P>' . "\r\n" . '</' . $pre . 'PrimeFieldParamsType>' . "\r\n"; $a = $curve->getA(); $b = $curve->getB(); list($x, $y) = $curve->getBasePoint(); break; default: throw new UnsupportedCurveException('Field Type of ' . $temp['fieldID']['fieldType'] . ' is not supported'); } $xml.= '</' . $pre . 'FieldParams>' . "\r\n" . '<' . $pre . 'CurveParamsType>' . "\r\n" . '<' . $pre . 'A>' . $a . '</' . $pre . 'A>' . "\r\n" . '<' . $pre . 'B>' . $b . '</' . $pre . 'B>' . "\r\n" . '</' . $pre . 'CurveParamsType>' . "\r\n" . '<' . $pre . 'BasePointParams>' . "\r\n" . '<' . $pre . 'BasePoint>' . "\r\n" . '<' . $pre . 'ECPointType>' . "\r\n" . '<' . $pre . 'X>' . $x . '</' . $pre . 'X>' . "\r\n" . '<' . $pre . 'Y>' . $y . '</' . $pre . 'Y>' . "\r\n" . '</' . $pre . 'ECPointType>' . "\r\n" . '</' . $pre . 'BasePoint>' . "\r\n" . '<' . $pre . 'Order>' . $curve->getOrder() . '</' . $pre . 'Order>' . "\r\n" . '</' . $pre . 'BasePointParams>' . "\r\n" . '</' . $pre . 'ExplicitParams>' . "\r\n"; return $xml; } if (isset($result['specifiedCurve'])) { $xml = '<' . $pre . 'ECParameters>' . "\r\n" . '<' . $pre . 'FieldID>' . "\r\n"; $temp = $result['specifiedCurve']; switch ($temp['fieldID']['fieldType']) { case 'prime-field': $xml.= '<' . $pre . 'Prime>' . "\r\n" . '<' . $pre . 'P>' . Base64::encode($temp['fieldID']['parameters']->toBytes()) . '</' . $pre . 'P>' . "\r\n" . '</' . $pre . 'Prime>' . "\r\n" ; break; default: throw new UnsupportedCurveException('Field Type of ' . $temp['fieldID']['fieldType'] . ' is not supported'); } $xml.= '</' . $pre . 'FieldID>' . "\r\n" . '<' . $pre . 'Curve>' . "\r\n" . '<' . $pre . 'A>' . Base64::encode($temp['curve']['a']) . '</' . $pre . 'A>' . "\r\n" . '<' . $pre . 'B>' . Base64::encode($temp['curve']['b']) . '</' . $pre . 'B>' . "\r\n" . '</' . $pre . 'Curve>' . "\r\n" . '<' . $pre . 'Base>' . Base64::encode($temp['base']) . '</' . $pre . 'Base>' . "\r\n" . '<' . $pre . 'Order>' . Base64::encode($temp['order']) . '</' . $pre . 'Order>' . "\r\n" . '</' . $pre . 'ECParameters>'; return $xml; } } } <?php /** * OpenSSH Formatted ECDSA Key Handler * * PHP version 5 * * Place in $HOME/.ssh/authorized_keys * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\OpenSSH as Progenitor; use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve; use phpseclib\Exception\UnsupportedCurveException; use phpseclib\Crypt\ECDSA\Curves\Ed25519; use phpseclib\Math\Common\FiniteField\Integer; /** * OpenSSH Formatted ECDSA Key Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSH extends Progenitor { use Common; /** * Supported Key Types * * @var array */ protected static $types = [ 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519' ]; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { $parsed = parent::load($key, $password); if (isset($parsed['paddedKey'])) { $paddedKey = $parsed['paddedKey']; list($type) = Strings::unpackSSH2('s', $paddedKey); if ($type != $parsed['type']) { throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])"); } if ($type == 'ssh-ed25519' ) { list(, $key, $comment) = Strings::unpackSSH2('sss', $paddedKey); $key = libsodium::load($key); $key['comment'] = $comment; return $key; } list($curveName, $publicKey, $privateKey, $comment) = Strings::unpackSSH2('ssis', $paddedKey); $curve = self::loadCurveByParam(['namedCurve' => $curveName]); return [ 'curve' => $curve, 'dA' => $curve->convertInteger($privateKey), 'QA' => self::extractPoint("\0$publicKey", $curve), 'comment' => $comment ]; } if ($parsed['type'] == 'ssh-ed25519') { if (Strings::shift($parsed['publicKey'], 4) != "\0\0\0\x20") { throw new \RuntimeException('Length of ssh-ed25519 key should be 32'); } $curve = new Ed25519(); $qa = self::extractPoint($parsed['publicKey'], $curve); } else { list($curveName, $publicKey) = Strings::unpackSSH2('ss', $parsed['publicKey']); $curveName = '\phpseclib\Crypt\ECDSA\Curves\\' . $curveName; $curve = new $curveName(); $qa = self::extractPoint("\0" . $publicKey, $curve); } return [ 'curve' => $curve, 'QA' => $qa, 'comment' => $parsed['comment'] ]; } /** * Returns the alias that corresponds to a curve * * @return string */ private static function getAlias(BaseCurve $curve) { self::initialize_static_variables(); $reflect = new \ReflectionClass($curve); $name = $reflect->getShortName(); $oid = self::$curveOIDs[$name]; $aliases = array_filter(self::$curveOIDs, function($v) use ($oid) { return $v == $oid; }); $aliases = array_keys($aliases); for ($i = 0; $i < count($aliases); $i++) { if (in_array('ecdsa-sha2-' . $aliases[$i], self::$types)) { $alias = $aliases[$i]; break; } } if (!isset($alias)) { throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports'); } return $alias; } /** * Convert an ECDSA public key to the appropriate format * * @access public * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param array $options optional * @return string */ public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = []) { $comment = isset($options['comment']) ? $options['comment'] : self::$comment; if ($curve instanceof Ed25519) { $key = Strings::packSSH2('ss', 'ssh-ed25519', $curve->encodePoint($publicKey)); if (self::$binary) { return $key; } $key = 'ssh-ed25519 ' . base64_encode($key) . ' ' . $comment; return $key; } $alias = self::getAlias($curve); $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $key = Strings::packSSH2('sss', 'ecdsa-sha2-' . $alias, $alias, $points); if (isset($options['binary']) ? $options['binary'] : self::$binary) { return $key; } $key = 'ecdsa-sha2-' . $alias . ' ' . base64_encode($key) . ' ' . $comment; return $key; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\Common\FiniteField\Integer $privateKey * @param \phpseclib\Crypt\ECDSA\Curves\Ed25519 $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '', array $options = []) { if ($curve instanceof Ed25519) { if (!isset($privateKey->secret)) { throw new \RuntimeException('Private Key does not have a secret set'); } if (strlen($privateKey->secret) != 32) { throw new \RuntimeException('Private Key secret is not of the correct length'); } $pubKey = $curve->encodePoint($publicKey); $publicKey = Strings::packSSH2('ss', 'ssh-ed25519', $pubKey); $privateKey = Strings::packSSH2('sss', 'ssh-ed25519', $pubKey, $privateKey->secret . $pubKey); return self::wrapPrivateKey($publicKey, $privateKey, $options); } $alias = self::getAlias($curve); $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $publicKey = self::savePublicKey($curve, $publicKey, ['binary' => true]); $privateKey = Strings::packSSH2('sssi', 'ecdsa-sha2-' . $alias, $alias, $points, $privateKey); return self::wrapPrivateKey($publicKey, $privateKey, $options); } } <?php /** * PKCS#8 Formatted ECDSA Key Handler * * PHP version 5 * * Processes keys with the following headers: * * -----BEGIN ENCRYPTED PRIVATE KEY----- * -----BEGIN PRIVATE KEY----- * -----BEGIN PUBLIC KEY----- * * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 * is specific to private keys it's basically creating a DER-encoded wrapper * for keys. This just extends that same concept to public keys (much like ssh-keygen) * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Math\Common\FiniteField\Integer; use phpseclib\Crypt\ECDSA\Curves\Ed25519; use phpseclib\Crypt\ECDSA\Curves\Ed448; /** * PKCS#8 Formatted ECDSA Key Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS8 extends Progenitor { use Common; /** * OID Name * * @var array * @access private */ const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448']; /** * OID Value * * @var string * @access private */ const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113']; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { // initialize_static_variables() is defined in both the trait and the parent class // when it's defined in two places it's the traits one that's called // the parent one is needed, as well, but the parent one is called by other methods // in the parent class as needed and in the context of the parent it's the parent // one that's called self::initialize_static_variables(); if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $isPublic = strpos($key, 'PUBLIC') !== false; $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; switch (true) { case !$isPublic && $type == 'publicKey': throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key'); case $isPublic && $type == 'privateKey': throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); } switch ($key[$type . 'Algorithm']['algorithm']) { case 'id-Ed25519': case 'id-Ed448': return self::loadEdDSA($key); } $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); $params = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP); $components = []; $components['curve'] = self::loadCurveByParam($params); if ($isPublic) { $components['QA'] = self::extractPoint("\0" . $key['publicKey'], $components['curve']); return $components; } $decoded = ASN1::decodeBER($key['privateKey']); $key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP); if (isset($key['parameters']) && $params != $key['parameters']) { throw new \RuntimeException('The PKCS8 parameter field does not match the private key parameter field'); } $temp = new BigInteger($key['privateKey'], 256); $components['dA'] = $components['curve']->convertInteger($temp); $components['QA'] = self::extractPoint($key['publicKey'], $components['curve']); return $components; } /** * Break a public or private EdDSA key down into its constituent components * * @return array */ private static function loadEdDSA(array $key) { $components = []; if (isset($key['privateKey'])) { $components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448(); // 0x04 == octet string // 0x20 == length (32 bytes) if (substr($key['privateKey'], 0, 2) != "\x04\x20") { throw new \RuntimeException('The first two bytes of the private key field should be 0x0420'); } $components['dA'] = $components['curve']->extractSecret(substr($key['privateKey'], 2)); } if (isset($key['publicKey'])) { if (!isset($components['curve'])) { $components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448(); } $components['QA'] = self::extractPoint($key['publicKey'], $components['curve']); } if (isset($key['privateKey']) && !isset($components['QA'])) { $components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']); } return $components; } /** * Convert an ECDSA public key to the appropriate format * * @access public * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param array $optiona optional * @return string */ public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = []) { self::initialize_static_variables(); if ($curve instanceof TwistedEdwardsCurve) { return self::wrapPublicKey( $curve->encodePoint($publicKey), null, $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448' ); } $params = new ASN1\Element(self::encodeParameters($curve, false, $options)); $key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); return self::wrapPublicKey($key, $params, 'id-ecPublicKey'); } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\Common\FiniteField\Integer $privateKey * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '', array $options = []) { self::initialize_static_variables(); if ($curve instanceof TwistedEdwardsCurve) { return self::wrapPrivateKey( "\x04\x20" . $privateKey->secret, [], null, $password, $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448', $curve->encodePoint($publicKey) ); } $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $params = new ASN1\Element(self::encodeParameters($curve, false, $options)); $key = [ 'version' => 'ecPrivkeyVer1', 'privateKey' => $privateKey->toBytes(), //'parameters' => $params, 'publicKey' => "\0" . $publicKey ]; $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP); return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey', '', $options); } } <?php /** * "PKCS1" (RFC5915) Formatted ECDSA Key Handler * * PHP version 5 * * Used by File/X509.php * * Processes keys with the following headers: * * -----BEGIN EC PRIVATE KEY----- * -----BEGIN EC PARAMETERS----- * * Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe * DSA, whose format isn't really formally described anywhere, so might as well * use it to describe this, too. PKCS1 is easier to remember than RFC5915, after * all. I suppose this could also be named IETF but idk * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use phpseclib\Math\Common\FiniteField\Integer; use phpseclib\Crypt\Common\Keys\PKCS1 as Progenitor; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve; use phpseclib\Math\BigInteger; use ParagonIE\ConstantTime\Base64; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Exception\UnsupportedCurveException; /** * "PKCS1" (RFC5915) Formatted ECDSA Key Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS1 extends Progenitor { use Common; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { self::initialize_static_variables(); $key = parent::load($key, $password); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER'); } $key = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP); if (is_array($key)) { return ['curve' => self::loadCurveByParam($key)]; } $key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP); if (!is_array($key)) { throw new \RuntimeException('Unable to perform ASN1 mapping'); } $components = []; $components['curve'] = self::loadCurveByParam($key['parameters']); $temp = new BigInteger($key['privateKey'], 256); $components['dA'] = $components['curve']->convertInteger($temp); $components['QA'] = self::extractPoint($key['publicKey'], $components['curve']); return $components; } /** * Convert ECDSA parameters to the appropriate format * * @access public * @return string */ public static function saveParameters(BaseCurve $curve, array $options = []) { self::initialize_static_variables(); if ($curve instanceof TwistedEdwardsCurve) { throw new UnsupportedCurveException('TwistedEdwards Curves are not supported'); } $key = self::encodeParameters($curve, false, $options); return "-----BEGIN EC PARAMETERS-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END EC PARAMETERS-----\r\n"; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\Common\FiniteField\Integer $privateKey * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '', array $options = []) { self::initialize_static_variables(); if ($curve instanceof TwistedEdwardsCurve) { throw new UnsupportedCurveException('TwistedEdwards Curves are not supported'); } $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $key = [ 'version' => 'ecPrivkeyVer1', 'privateKey' => $privateKey->toBytes(), 'parameters' => new ASN1\Element(self::encodeParameters($curve)), 'publicKey' => "\0" . $publicKey ]; $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP); return self::wrapPrivateKey($key, 'EC', $password, $options); } } <?php /** * Generic ECDSA Key Parsing Helper functions * * PHP version 5 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use ParagonIE\ConstantTime\Hex; use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve; use phpseclib\Crypt\ECDSA\BaseCurves\Prime as PrimeCurve; use phpseclib\Crypt\ECDSA\BaseCurves\Binary as BinaryCurve; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Common\Functions\Strings; use phpseclib\Math\BigInteger; use phpseclib\Math\PrimeField; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; use phpseclib\Exception\UnsupportedCurveException; /** * Generic ECDSA Key Parsing Helper functions * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ trait Common { /** * Curve OIDs * * @var array */ private static $curveOIDs = []; /** * Child OIDs loaded * * @var bool */ protected static $childOIDsLoaded = false; /** * Use Named Curves * * @var bool */ private static $useNamedCurves = true; /** * Initialize static variables */ private static function initialize_static_variables() { if (empty(self::$curveOIDs)) { // the sec* curves are from the standards for efficient cryptography group // sect* curves are curves over binary finite fields // secp* curves are curves over prime finite fields // sec*r* curves are regular curves; sec*k* curves are koblitz curves // brainpool*r* curves are regular prime finite field curves // brainpool*t* curves are twisted versions of the brainpool*r* curves self::$curveOIDs = [ 'prime192v1' => '1.2.840.10045.3.1.1', // J.5.1, example 1 (aka secp192r1) 'prime192v2' => '1.2.840.10045.3.1.2', // J.5.1, example 2 'prime192v3' => '1.2.840.10045.3.1.3', // J.5.1, example 3 'prime239v1' => '1.2.840.10045.3.1.4', // J.5.2, example 1 'prime239v2' => '1.2.840.10045.3.1.5', // J.5.2, example 2 'prime239v3' => '1.2.840.10045.3.1.6', // J.5.2, example 3 'prime256v1' => '1.2.840.10045.3.1.7', // J.5.3, example 1 (aka secp256r1) // https://tools.ietf.org/html/rfc5656#section-10 'nistp256' => '1.2.840.10045.3.1.7', // aka secp256r1 'nistp384' => '1.3.132.0.34', // aka secp384r1 'nistp521' => '1.3.132.0.35', // aka secp521r1 'nistk163' => '1.3.132.0.1', // aka sect163k1 'nistp192' => '1.2.840.10045.3.1.1', // aka secp192r1 'nistp224' => '1.3.132.0.33', // aka secp224r1 'nistk233' => '1.3.132.0.26', // aka sect233k1 'nistb233' => '1.3.132.0.27', // aka sect233r1 'nistk283' => '1.3.132.0.16', // aka sect283k1 'nistk409' => '1.3.132.0.36', // aka sect409k1 'nistb409' => '1.3.132.0.37', // aka sect409r1 'nistt571' => '1.3.132.0.38', // aka sect571k1 // from https://tools.ietf.org/html/rfc5915 'secp192r1' => '1.2.840.10045.3.1.1', // aka prime192v1 'sect163k1' => '1.3.132.0.1', 'sect163r2' => '1.3.132.0.15', 'secp224r1' => '1.3.132.0.33', 'sect233k1'=> '1.3.132.0.26', 'sect233r1'=> '1.3.132.0.27', 'secp256r1' => '1.2.840.10045.3.1.7', // aka prime256v1 'sect283k1' => '1.3.132.0.16', 'sect283r1' => '1.3.132.0.17', 'secp384r1' => '1.3.132.0.34', 'sect409k1' => '1.3.132.0.36', 'sect409r1' => '1.3.132.0.37', 'secp521r1' => '1.3.132.0.35', 'sect571k1' => '1.3.132.0.38', 'sect571r1' => '1.3.132.0.39', // from http://www.secg.org/SEC2-Ver-1.0.pdf 'secp112r1' => '1.3.132.0.6', 'secp112r2' => '1.3.132.0.7', 'secp128r1' => '1.3.132.0.28', 'secp128r2' => '1.3.132.0.29', 'secp160k1' => '1.3.132.0.9', 'secp160r1' => '1.3.132.0.8', 'secp160r2' => '1.3.132.0.30', 'secp192k1' => '1.3.132.0.31', 'secp224k1' => '1.3.132.0.32', 'secp256k1' => '1.3.132.0.10', 'sect113r1' => '1.3.132.0.4', 'sect113r2' => '1.3.132.0.5', 'sect131r1' => '1.3.132.0.22', 'sect131r2' => '1.3.132.0.23', 'sect163r1' => '1.3.132.0.2', 'sect193r1' => '1.3.132.0.24', 'sect193r2' => '1.3.132.0.25', 'sect239k1' => '1.3.132.0.3', // from http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf#page=36 /* 'c2pnb163v1' => '1.2.840.10045.3.0.1', // J.4.1, example 1 'c2pnb163v2' => '1.2.840.10045.3.0.2', // J.4.1, example 2 'c2pnb163v3' => '1.2.840.10045.3.0.3', // J.4.1, example 3 'c2pnb172w1' => '1.2.840.10045.3.0.4', // J.4.2, example 1 'c2tnb191v1' => '1.2.840.10045.3.0.5', // J.4.3, example 1 'c2tnb191v2' => '1.2.840.10045.3.0.6', // J.4.3, example 2 'c2tnb191v3' => '1.2.840.10045.3.0.7', // J.4.3, example 3 'c2onb191v4' => '1.2.840.10045.3.0.8', // J.4.3, example 4 'c2onb191v5' => '1.2.840.10045.3.0.9', // J.4.3, example 5 'c2pnb208w1' => '1.2.840.10045.3.0.10', // J.4.4, example 1 'c2tnb239v1' => '1.2.840.10045.3.0.11', // J.4.5, example 1 'c2tnb239v2' => '1.2.840.10045.3.0.12', // J.4.5, example 2 'c2tnb239v3' => '1.2.840.10045.3.0.13', // J.4.5, example 3 'c2onb239v4' => '1.2.840.10045.3.0.14', // J.4.5, example 4 'c2onb239v5' => '1.2.840.10045.3.0.15', // J.4.5, example 5 'c2pnb272w1' => '1.2.840.10045.3.0.16', // J.4.6, example 1 'c2pnb304w1' => '1.2.840.10045.3.0.17', // J.4.7, example 1 'c2tnb359v1' => '1.2.840.10045.3.0.18', // J.4.8, example 1 'c2pnb368w1' => '1.2.840.10045.3.0.19', // J.4.9, example 1 'c2tnb431r1' => '1.2.840.10045.3.0.20', // J.4.10, example 1 */ // http://www.ecc-brainpool.org/download/Domain-parameters.pdf // https://tools.ietf.org/html/rfc5639 'brainpoolP160r1' => '1.3.36.3.3.2.8.1.1.1', 'brainpoolP160t1' => '1.3.36.3.3.2.8.1.1.2', 'brainpoolP192r1' => '1.3.36.3.3.2.8.1.1.3', 'brainpoolP192t1' => '1.3.36.3.3.2.8.1.1.4', 'brainpoolP224r1' => '1.3.36.3.3.2.8.1.1.5', 'brainpoolP224t1' => '1.3.36.3.3.2.8.1.1.6', 'brainpoolP256r1' => '1.3.36.3.3.2.8.1.1.7', 'brainpoolP256t1' => '1.3.36.3.3.2.8.1.1.8', 'brainpoolP320r1' => '1.3.36.3.3.2.8.1.1.9', 'brainpoolP320t1' => '1.3.36.3.3.2.8.1.1.10', 'brainpoolP384r1' => '1.3.36.3.3.2.8.1.1.11', 'brainpoolP384t1' => '1.3.36.3.3.2.8.1.1.12', 'brainpoolP512r1' => '1.3.36.3.3.2.8.1.1.13', 'brainpoolP512t1' => '1.3.36.3.3.2.8.1.1.14' ]; ASN1::loadOIDs([ 'prime-field' => '1.2.840.10045.1.1', 'characteristic-two-field' => '1.2.840.10045.1.2', 'characteristic-two-basis' => '1.2.840.10045.1.2.3', // per http://www.secg.org/SEC1-Ver-1.0.pdf#page=84, gnBasis "not used here" 'gnBasis' => '1.2.840.10045.1.2.3.1', // NULL 'tpBasis' => '1.2.840.10045.1.2.3.2', // Trinomial 'ppBasis' => '1.2.840.10045.1.2.3.3' // Pentanomial ] + self::$curveOIDs); } } /** * Explicitly set the curve * * If the key contains an implicit curve phpseclib needs the curve * to be explicitly provided * * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve */ public static function setImplicitCurve(BaseCurve $curve) { self::$implicitCurve = $curve; } /** * Returns an instance of \phpseclib\Crypt\ECDSA\BaseCurves\Base based * on the curve parameters * * @param array $params * @return \phpseclib\Crypt\ECDSA\BaseCurves\Base|false */ protected static function loadCurveByParam(array $params) { if (count($params) > 1) { throw new \RuntimeException('No parameters are present'); } if (isset($params['namedCurve'])) { $curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $params['namedCurve']; if (!class_exists($curve)) { throw new UnsupportedCurveException('Named Curve of ' . $params['namedCurve'] . ' is not supported'); } return new $curve(); } if (isset($params['implicitCurve'])) { if (!isset(self::$implicitCurve)) { throw new \RuntimeException('Implicit curves can be provided by calling setImplicitCurve'); } return self::$implicitCurve; } if (isset($params['specifiedCurve'])) { $data = $params['specifiedCurve']; switch ($data['fieldID']['fieldType']) { case 'prime-field': $curve = new PrimeCurve(); $curve->setModulo($data['fieldID']['parameters']); $curve->setCoefficients( new BigInteger($data['curve']['a'], 256), new BigInteger($data['curve']['b'], 256) ); $point = self::extractPoint("\0" . $data['base'], $curve); $curve->setBasePoint(...$point); $curve->setOrder($data['order']); return $curve; case 'characteristic-two-field': $curve = new BinaryCurve(); $params = ASN1::decodeBER($data['fieldID']['parameters']); $params = ASN1::asn1map($params[0], Maps\Characteristic_two::MAP); $modulo = [(int) $params['m']->toString()]; switch ($params['basis']) { case 'tpBasis': $modulo[] = (int) $params['parameters']->toString(); break; case 'ppBasis': $temp = ASN1::decodeBER($params['parameters']); $temp = ASN1::asn1map($temp[0], Maps\Pentanomial::MAP); $modulo[] = (int) $temp['k3']->toString(); $modulo[] = (int) $temp['k2']->toString(); $modulo[] = (int) $temp['k1']->toString(); } $modulo[] = 0; $curve->setModulo(...$modulo); $len = ceil($modulo[0] / 8); $curve->setCoefficients( Hex::encode($data['curve']['a']), Hex::encode($data['curve']['b']) ); $point = self::extractPoint("\0" . $data['base'], $curve); $curve->setBasePoint(...$point); $curve->setOrder($data['order']); return $curve; default: throw new UnsupportedCurveException('Field Type of ' . $data['fieldID']['fieldType'] . ' is not supported'); } } throw new \RuntimeException('No valid parameters are present'); } /** * Extract points from a string * * Supports both compressed and uncompressed points * * @param string $str * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @return object[] */ public static function extractPoint($str, BaseCurve $curve) { if ($curve instanceof TwistedEdwardsCurve) { // first step of point deciding as discussed at the following URL's: // https://tools.ietf.org/html/rfc8032#section-5.1.3 // https://tools.ietf.org/html/rfc8032#section-5.2.3 $y = $str; $y = strrev($y); $sign = (bool) (ord($y[0]) & 0x80); $y[0] = $y[0] & chr(0x7F); $y = new BigInteger($y, 256); if ($y->compare($curve->getModulo()) >= 0) { throw new \RuntimeException('The Y coordinate should not be >= the modulo'); } $point = $curve->recoverX($y, $sign); if (!$curve->verifyPoint($point)) { throw new \RuntimeException('Unable to verify that point exists on curve'); } return $point; } // the first byte of a bit string represents the number of bits in the last byte that are to be ignored but, // currently, bit strings wanting a non-zero amount of bits trimmed are not supported if (($val = Strings::shift($str)) != "\0") { throw new \UnexpectedValueException('extractPoint expects the first byte to be null - not ' . Hex::encode($val)); } if ($str == "\0") { return []; } $keylen = strlen($str); $order = $curve->getLengthInBytes(); // point compression is being used if ($keylen == $order + 1) { return $curve->derivePoint($str); } // point compression is not being used if ($keylen == 2 * $order + 1) { preg_match("#(.)(.{{$order}})(.{{$order}})#s", $str, $matches); list(, $w, $x, $y) = $matches; if ($w != "\4") { throw new \UnexpectedValueException('The first byte of an uncompressed point should be 04 - not ' . Hex::encode($val)); } $point = [ $curve->convertInteger(new BigInteger($x, 256)), $curve->convertInteger(new BigInteger($y, 256)) ]; if (!$curve->verifyPoint($point)) { throw new \RuntimeException('Unable to verify that point exists on curve'); } return $point; } throw new \UnexpectedValueException('The string representation of the points is not of an appropriate length'); } /** * Encode Parameters * * @todo Maybe at some point this could be moved to __toString() for each of the curves? * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param bool $returnArray optional * @param array $options optional * @return string|false */ private static function encodeParameters(BaseCurve $curve, $returnArray = false, array $options = []) { $useNamedCurves = isset($options['namedCurve']) ? $options['namedCurve'] : self::$useNamedCurves; $reflect = new \ReflectionClass($curve); $name = $reflect->getShortName(); if ($useNamedCurves) { if (isset(self::$curveOIDs[$name])) { if ($reflect->isFinal()) { $reflect = $reflect->getParentClass(); $name = $reflect->getShortName(); } return $returnArray ? ['namedCurve' => $name] : ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP); } foreach (new \DirectoryIterator(__DIR__ . '/../Curves/') as $file) { if ($file->getExtension() != 'php') { continue; } $testName = $file->getBasename('.php'); $class = 'phpseclib\Crypt\ECDSA\Curves\\' . $testName; $reflect = new \ReflectionClass($class); if ($reflect->isFinal()) { continue; } $candidate = new $class(); switch ($name) { case 'Prime': if (!$candidate instanceof PrimeCurve) { break; } if (!$candidate->getModulo()->equals($curve->getModulo())) { break; } if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) { break; } if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) { break; } list($candidateX, $candidateY) = $candidate->getBasePoint(); list($curveX, $curveY) = $curve->getBasePoint(); if ($candidateX->toBytes() != $curveX->toBytes()) { break; } if ($candidateY->toBytes() != $curveY->toBytes()) { break; } return $returnArray ? ['namedCurve' => $testName] : ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP); case 'Binary': if (!$candidate instanceof BinaryCurve) { break; } if ($candidate->getModulo() != $curve->getModulo()) { break; } if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) { break; } if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) { break; } list($candidateX, $candidateY) = $candidate->getBasePoint(); list($curveX, $curveY) = $curve->getBasePoint(); if ($candidateX->toBytes() != $curveX->toBytes()) { break; } if ($candidateY->toBytes() != $curveY->toBytes()) { break; } return $returnArray ? ['namedCurve' => $testName] : ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP); } } } $order = $curve->getOrder(); // we could try to calculate the order thusly: // https://crypto.stackexchange.com/a/27914/4520 // https://en.wikipedia.org/wiki/Schoof%E2%80%93Elkies%E2%80%93Atkin_algorithm if (!$order) { throw new \RuntimeException('Specified Curves need the order to be specified'); } $point = $curve->getBasePoint(); $x = $point[0]->toBytes(); $y = $point[1]->toBytes(); if ($curve instanceof PrimeCurve) { /* * valid versions are: * * ecdpVer1: * - neither the curve or the base point are generated verifiably randomly. * ecdpVer2: * - curve and base point are generated verifiably at random and curve.seed is present * ecdpVer3: * - base point is generated verifiably at random but curve is not. curve.seed is present */ // other (optional) parameters can be calculated using the methods discused at // https://crypto.stackexchange.com/q/28947/4520 $data = [ 'version' => 'ecdpVer1', 'fieldID' => [ 'fieldType' => 'prime-field', 'parameters' => $curve->getModulo() ], 'curve' => [ 'a' => $curve->getA()->toBytes(), 'b' => $curve->getB()->toBytes() ], 'base' => "\4" . $x . $y, 'order' => $order ]; return $returnArray ? ['specifiedCurve' => $data] : ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP); } if ($curve instanceof BinaryCurve) { $modulo = $curve->getModulo(); $basis = count($modulo); $m = array_shift($modulo); array_pop($modulo); // the last parameter should always be 0 //rsort($modulo); switch ($basis) { case 3: $basis = 'tpBasis'; $modulo = new BigInteger($modulo[0]); break; case 5: $basis = 'ppBasis'; // these should be in strictly ascending order (hence the commented out rsort above) $modulo = [ 'k1' => new BigInteger($modulo[2]), 'k2' => new BigInteger($modulo[1]), 'k3' => new BigInteger($modulo[0]) ]; $modulo = ASN1::encodeDER($modulo, Maps\Pentanomial::MAP); $modulo = new ASN1\Element($modulo); } $params = ASN1::encodeDER([ 'm' => new BigInteger($m), 'basis' => $basis, 'parameters' => $modulo ], Maps\Characteristic_two::MAP); $params = new ASN1\Element($params); $a = ltrim($curve->getA()->toBytes(), "\0"); if (!strlen($a)) { $a = "\0"; } $b = ltrim($curve->getB()->toBytes(), "\0"); if (!strlen($b)) { $b = "\0"; } $data = [ 'version' => 'ecdpVer1', 'fieldID' => [ 'fieldType' => 'characteristic-two-field', 'parameters' => $params ], 'curve' => [ 'a' => $a, 'b' => $b ], 'base' => "\4" . $x . $y, 'order' => $order ]; return $returnArray ? ['specifiedCurve' => $data] : ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP); } throw new UnsupportedCurveException('Curve cannot be serialized'); } /** * Use Specified Curve * * A specified curve has all the coefficients, the base points, etc, explicitely included. * A specified curve is a more verbose way of representing a curve */ public static function useSpecifiedCurve() { self::$useNamedCurves = false; } /** * Use Named Curve * * A named curve does not include any parameters. It is up to the ECDSA parameters to * know what the coefficients, the base points, etc, are from the name of the curve. * A named curve is a more concise way of representing a curve */ public static function useNamedCurve() { self::$useNamedCurves = true; } }<?php /** * PuTTY Formatted ECDSA Key Handler * * PHP version 5 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\PuTTY as Progenitor; use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve; use phpseclib\Math\Common\FiniteField\Integer; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; /** * PuTTY Formatted ECDSA Key Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PuTTY extends Progenitor { use Common; /** * Public Handler * * @var string * @access private */ const PUBLIC_HANDLER = 'phpseclib\Crypt\ECDSA\Keys\OpenSSH'; /** * Supported Key Types * * @var array * @access private */ protected static $types = [ 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519' ]; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { $components = parent::load($key, $password); if (!isset($components['private'])) { return $components; } $private = $components['private']; $temp = Base64::encode(Strings::packSSH2('s', $components['type']) . $components['public']); $components = OpenSSH::load($components['type'] . ' ' . $temp . ' ' . $components['comment']); if ($components['curve'] instanceof TwistedEdwardsCurve) { if (Strings::shift($private, 4) != "\0\0\0\x20") { throw new \RuntimeException('Length of ssh-ed25519 key should be 32'); } $components['dA'] = $components['curve']->extractSecret($private); } else { list($temp) = Strings::unpackSSH2('i', $private); $components['dA'] = $components['curve']->convertInteger($temp); } return $components; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\Common\FiniteField\Integer $privateKey * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = false, array $options = []) { self::initialize_static_variables(); $public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey)); $name = $public[0]; $public = Base64::decode($public[1]); list(, $length) = unpack('N', Strings::shift($public, 4)); Strings::shift($public, $length); // PuTTY pads private keys with a null byte per the following: // https://github.com/github/putty/blob/a3d14d77f566a41fc61dfdc5c2e0e384c9e6ae8b/sshecc.c#L1926 if (!$curve instanceof TwistedEdwardsCurve) { $private = $privateKey->toBytes(); if (!(strlen($privateKey->toBits()) & 7)) { $private ="\0$private"; } } $private = $curve instanceof TwistedEdwardsCurve ? Strings::packSSH2('s', $privateKey->secret) : Strings::packSSH2('s', $private); return self::wrapPrivateKey($public, $private, $name, $password, $options); } /** * Convert an ECDSA public key to the appropriate format * * @access public * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Math\Common\FiniteField[] $publicKey * @return string */ public static function savePublicKey(BaseCurve $curve, array $publicKey) { $public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey)); $type = $public[0]; $public = Base64::decode($public[1]); list(, $length) = unpack('N', Strings::shift($public, 4)); Strings::shift($public, $length); return self::wrapPublicKey($public, $type); } } <?php /** * Generalized Koblitz Curves over y^2 = x^3 + b. * * According to http://www.secg.org/SEC2-Ver-1.0.pdf Koblitz curves are over the GF(2**m) * finite field. Both the $a$ and $b$ coefficients are either 0 or 1. However, SEC2 * generalizes the definition to include curves over GF(P) "which possess an efficiently * computable endomorphism". * * For these generalized Koblitz curves $b$ doesn't have to be 0 or 1. Whether or not $a$ * has any restrictions on it is unclear, however, for all the GF(P) Koblitz curves defined * in SEC2 v1.0 $a$ is $0$ so all of the methods defined herein will assume that it is. * * I suppose we could rename the $b$ coefficient to $a$, however, the documentation refers * to $b$ so we'll just keep it. * * If a later version of SEC2 comes out wherein some $a$ values are non-zero we can create a * new method for those. eg. KoblitzA1Prime.php or something. * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\BaseCurves; use phpseclib\Common\Functions\Strings; use phpseclib\Math\PrimeField; use phpseclib\Math\BigInteger; use phpseclib\Math\PrimeField\Integer as PrimeInteger; /** * Curves over y^2 = x^3 + b * * @package KoblitzPrime * @author Jim Wigginton <terrafrost@php.net> * @access public */ class KoblitzPrime extends Prime { // don't overwrite setCoefficients() with one that only accepts one parameter so that // one might be able to switch between KoblitzPrime and Prime more easily (for benchmarking // purposes). /** * Multiply and Add Points * * Uses a efficiently computable endomorphism to achieve a slight speedup * * Adapted from https://git.io/vxbrP * * @return int[] */ public function multiplyAddPoints(array $points, array $scalars) { static $zero, $one, $two; if (!isset($two)) { $two = new BigInteger(2); $one = new BigInteger(1); } if (!isset($this->beta)) { // get roots $inv = $this->one->divide($this->two)->negate(); $s = $this->three->negate()->squareRoot()->multiply($inv); $betas = [ $inv->add($s), $inv->subtract($s) ]; $this->beta = $betas[0]->compare($betas[1]) < 0 ? $betas[0] : $betas[1]; //echo strtoupper($this->beta->toHex(true)) . "\n"; exit; } if (!isset($this->basis)) { $factory = new PrimeField($this->order); $tempOne = $factory->newInteger($one); $tempTwo = $factory->newInteger($two); $tempThree = $factory->newInteger(new BigInteger(3)); $inv = $tempOne->divide($tempTwo)->negate(); $s = $tempThree->negate()->squareRoot()->multiply($inv); $lambdas = [ $inv->add($s), $inv->subtract($s) ]; $lhs = $this->multiplyPoint($this->p, $lambdas[0])[0]; $rhs = $this->p[0]->multiply($this->beta); $lambda = $lhs->equals($rhs) ? $lambdas[0] : $lambdas[1]; $this->basis = static::extendedGCD($lambda->toBigInteger(), $this->order); ///* foreach ($this->basis as $basis) { echo strtoupper($basis['a']->toHex(true)) . "\n"; echo strtoupper($basis['b']->toHex(true)) . "\n\n"; } exit; //*/ } $npoints = $nscalars = []; for ($i = 0; $i < count($points); $i++) { $p = $points[$i]; $k = $scalars[$i]->toBigInteger(); // begin split list($v1, $v2) = $this->basis; $c1 = $v2['b']->multiply($k); list($c1, $r) = $c1->divide($this->order); if ($this->order->compare($r->multiply($two)) <= 0) { $c1 = $c1->add($one); } $c2 = $v1['b']->negate()->multiply($k); list($c2, $r) = $c2->divide($this->order); if ($this->order->compare($r->multiply($two)) <= 0) { $c2 = $c2->add($one); } $p1 = $c1->multiply($v1['a']); $p2 = $c2->multiply($v2['a']); $q1 = $c1->multiply($v1['b']); $q2 = $c2->multiply($v2['b']); $k1 = $k->subtract($p1)->subtract($p2); $k2 = $q1->add($q2)->negate(); // end split $beta = [ $p[0]->multiply($this->beta), $p[1], clone $this->one ]; if (isset($p['naf'])) { $beta['naf'] = array_map(function($p) { return [ $p[0]->multiply($this->beta), $p[1], clone $this->one ]; }, $p['naf']); $beta['nafwidth'] = $p['nafwidth']; } if ($k1->isNegative()) { $k1 = $k1->negate(); $p = $this->negatePoint($p); } if ($k2->isNegative()) { $k2 = $k2->negate(); $beta = $this->negatePoint($beta); } $pos = 2 * $i; $npoints[$pos] = $p; $nscalars[$pos] = $this->factory->newInteger($k1); $pos++; $npoints[$pos] = $beta; $nscalars[$pos] = $this->factory->newInteger($k2); } return parent::multiplyAddPoints($npoints, $nscalars); } /** * Returns the numerator and denominator of the slope * * @return FiniteField[] */ protected function doublePointHelper(array $p) { $numerator = $this->three->multiply($p[0])->multiply($p[0]); $denominator = $this->two->multiply($p[1]); return [$numerator, $denominator]; } /** * Doubles a jacobian coordinate on the curve * * See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l * * @return FiniteField[] */ protected function jacobianDoublePoint(array $p) { list($x1, $y1, $z1) = $p; $a = $x1->multiply($x1); $b = $y1->multiply($y1); $c = $b->multiply($b); $d = $x1->add($b); $d = $d->multiply($d)->subtract($a)->subtract($c)->multiply($this->two); $e = $this->three->multiply($a); $f = $e->multiply($e); $x3 = $f->subtract($this->two->multiply($d)); $y3 = $e->multiply($d->subtract($x3))->subtract( $this->eight->multiply($c)); $z3 = $this->two->multiply($y1)->multiply($z1); return [$x3, $y3, $z3]; } /** * Doubles a "fresh" jacobian coordinate on the curve * * See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl * * @return FiniteField[] */ protected function jacobianDoublePointMixed(array $p) { list($x1, $y1) = $p; $xx = $x1->multiply($x1); $yy = $y1->multiply($y1); $yyyy = $yy->multiply($yy); $s = $x1->add($yy); $s = $s->multiply($s)->subtract($xx)->subtract($yyyy)->multiply($this->two); $m = $this->three->multiply($xx); $t = $m->multiply($m)->subtract($this->two->multiply($s)); $x3 = $t; $y3 = $s->subtract($t); $y3 = $m->multiply($y3)->subtract($this->eight->multiply($yyyy)); $z3 = $this->two->multiply($y1); return [$x3, $y3, $z3]; } /** * Tests whether or not the x / y values satisfy the equation * * @return boolean */ public function verifyPoint(array $p) { list($x, $y) = $p; $lhs = $y->multiply($y); $temp = $x->multiply($x)->multiply($x); $rhs = $temp->add($this->b); return $lhs->equals($rhs); } /** * Calculates the parameters needed from the Euclidean algorithm as discussed at * http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=148 * * @param BigInteger $n * @return BigInteger[] */ protected static function extendedGCD(BigInteger $u, BigInteger $v) { $one = new BigInteger(1); $zero = new BigInteger(); $a = clone $one; $b = clone $zero; $c = clone $zero; $d = clone $one; $stop = $v->bitwise_rightShift($v->getLength() >> 1); $a1 = clone $zero; $b1 = clone $zero; $a2 = clone $zero; $b2 = clone $zero; $postGreatestIndex = 0; while (!$v->equals($zero)) { list($q) = $u->divide($v); $temp = $u; $u = $v; $v = $temp->subtract($v->multiply($q)); $temp = $a; $a = $c; $c = $temp->subtract($a->multiply($q)); $temp = $b; $b = $d; $d = $temp->subtract($b->multiply($q)); if ($v->compare($stop) > 0) { $a0 = $v; $b0 = $c; } else { $postGreatestIndex++; } if ($postGreatestIndex == 1) { $a1 = $v; $b1 = $c->negate(); } if ($postGreatestIndex == 2) { $rhs = $a0->multiply($a0)->add($b0->multiply($b0)); $lhs = $v->multiply($v)->add($b->multiply($b)); if ($lhs->compare($rhs) <= 0) { $a2 = $a0; $b2 = $b0->negate(); } else { $a2 = $v; $b2 = $c->negate(); } break; } } return [ ['a' => $a1, 'b' => $b1], ['a' => $a2, 'b' => $b2] ]; } }<?php /** * Curves over y^2 + x*y = x^3 + a*x^2 + b * * These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf * The curve is a weierstrass curve with a[3] and a[2] set to 0. * * Uses Jacobian Coordinates for speed if able: * * https://en.wikipedia.org/wiki/Jacobian_curve * https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\BaseCurves; use phpseclib\Common\Functions\Strings; use phpseclib\Math\BinaryField; use phpseclib\Math\BigInteger; use phpseclib\Math\BinaryField\Integer as BinaryInteger; /** * Curves over y^2 + x*y = x^3 + a*x^2 + b * * @package Binary * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Binary extends Base { /** * Binary Field Integer factory * * @var \phpseclib\Math\BinaryFields */ protected $factory; /** * Cofficient for x^1 * * @var object */ protected $a; /** * Cofficient for x^0 * * @var object */ protected $b; /** * Base Point * * @var object */ protected $p; /** * The number one over the specified finite field * * @var object */ protected $one; /** * The modulo * * @var BigInteger */ protected $modulo; /** * The Order * * @var BigInteger */ protected $order; /** * Sets the modulo */ public function setModulo(...$modulo) { $this->modulo = $modulo; $this->factory = new BinaryField(...$modulo); $this->one = $this->factory->newInteger("\1"); } /** * Set coefficients a and b * * @param string $a * @param string $b */ public function setCoefficients($a, $b) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } $this->a = $this->factory->newInteger(pack('H*', $a)); $this->b = $this->factory->newInteger(pack('H*', $b)); } /** * Set x and y coordinates for the base point * * @param string|BinaryInteger $x * @param string|BinaryInteger $y */ public function setBasePoint($x, $y) { switch (true) { case !is_string($x) && !$x instanceof BinaryInteger: throw new \UnexpectedValueException('Argument 1 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer'); case !is_string($y) && !$y instanceof BinaryInteger: throw new \UnexpectedValueException('Argument 2 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer'); } if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } $this->p = [ is_string($x) ? $this->factory->newInteger(pack('H*', $x)) : $x, is_string($y) ? $this->factory->newInteger(pack('H*', $y)) : $y ]; } /** * Retrieve the base point as an array * * @return array */ public function getBasePoint() { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } /* if (!isset($this->p)) { throw new \RuntimeException('setBasePoint needs to be called before this method'); } */ return $this->p; } /** * Adds two points on the curve * * @return FiniteField[] */ public function addPoint(array $p, array $q) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p) || !count($q)) { if (count($q)) { return $q; } if (count($p)) { return $p; } return []; } if (!isset($p[2]) || !isset($q[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa'); } if ($p[0]->equals($q[0])) { return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p); } // formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html list($x1, $y1, $z1) = $p; list($x2, $y2, $z2) = $q; $o1 = $z1->multiply($z1); $b = $x2->multiply($o1); if ($z2->equals($this->one)) { $d = $y2->multiply($o1)->multiply($z1); $e = $x1->add($b); $f = $y1->add($d); $z3 = $e->multiply($z1); $h = $f->multiply($x2)->add($z3->multiply($y2)); $i = $f->add($z3); $g = $z3->multiply($z3); $p1 = $this->a->multiply($g); $p2 = $f->multiply($i); $p3 = $e->multiply($e)->multiply($e); $x3 = $p1->add($p2)->add($p3); $y3 = $i->multiply($x3)->add($g->multiply($h)); return [$x3, $y3, $z3]; } $o2 = $z2->multiply($z2); $a = $x1->multiply($o2); $c = $y1->multiply($o2)->multiply($z2); $d = $y2->multiply($o1)->multiply($z1); $e = $a->add($b); $f = $c->add($d); $g = $e->multiply($z1); $h = $f->multiply($x2)->add($g->multiply($y2)); $z3 = $g->multiply($z2); $i = $f->add($z3); $p1 = $this->a->multiply($z3->multiply($z3)); $p2 = $f->multiply($i); $p3 = $e->multiply($e)->multiply($e); $x3 = $p1->add($p2)->add($p3); $y3 = $i->multiply($x3)->add($g->multiply($g)->multiply($h)); return [$x3, $y3, $z3]; } /** * Doubles a point on a curve * * @return FiniteField[] */ public function doublePoint(array $p) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p)) { return []; } if (!isset($p[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa'); } // formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html list($x1, $y1, $z1) = $p; $a = $x1->multiply($x1); $b = $a->multiply($a); if ($z1->equals($this->one)) { $x3 = $b->add($this->b); $z3 = clone $x1; $p1 = $a->add($y1)->add($z3)->multiply($this->b); $p2 = $a->add($y1)->multiply($b); $y3 = $p1->add($p2); return [$x3, $y3, $z3]; } $c = $z1->multiply($z1); $d = $c->multiply($c); $x3 = $b->add($this->b->multiply($d->multiply($d))); $z3 = $x1->multiply($c); $p1 = $b->multiply($z3); $p2 = $a->add($y1->multiply($z1))->add($z3)->multiply($x3); $y3 = $p1->add($p2); return [$x3, $y3, $z3]; } /** * Returns the X coordinate and the derived Y coordinate * * Not supported because it is covered by patents. * Quoting https://www.openssl.org/docs/man1.1.0/apps/ecparam.html , * * "Due to patent issues the compressed option is disabled by default for binary curves * and can be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at * compile time." * * @return array */ public function derivePoint($m) { throw new \RuntimeException('Point compression on binary finite field elliptic curves is not supported'); } /** * Tests whether or not the x / y values satisfy the equation * * @return boolean */ public function verifyPoint(array $p) { list($x, $y) = $p; $lhs = $y->multiply($y); $lhs = $lhs->add($x->multiply($y)); $x2 = $x->multiply($x); $x3 = $x2->multiply($x); $rhs = $x3->add($this->a->multiply($x2))->add($this->b); return $lhs->equals($rhs); } /** * Returns the modulo * * @return \phpseclib\Math\BigInteger */ public function getModulo() { return $this->modulo; } /** * Returns the a coefficient * * @return \phpseclib\Math\PrimeField\Integer */ public function getA() { return $this->a; } /** * Returns the a coefficient * * @return \phpseclib\Math\PrimeField\Integer */ public function getB() { return $this->b; } /** * Returns the affine point * * A Jacobian Coordinate is of the form (x, y, z). * To convert a Jacobian Coordinate to an Affine Point * you do (x / z^2, y / z^3) * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToAffine(array $p) { if (!isset($p[2])) { return $p; } list($x, $y, $z) = $p; $z = $this->one->divide($z); $z2 = $z->multiply($z); return [ $x->multiply($z2), $y->multiply($z2)->multiply($z) ]; } /** * Converts an affine point to a jacobian coordinate * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToInternal(array $p) { if (isset($p[2])) { return $p; } $p[2] = clone $this->one; $p['fresh'] = true; return $p; } }<?php /** * Curve methods common to all curves * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\BaseCurves; use phpseclib\Math\Common\FiniteField; use phpseclib\Math\BigInteger; /** * Base * * @package Prime * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Base { /** * Doubles * * @var object[] */ protected $doubles; /** * NAF Points * * @var int[] */ private $naf; /** * The Order * * @var BigInteger */ protected $order; /** * Finite Field Integer factory * * @var \phpseclib\Math\FiniteField\Integer */ protected $factory; /** * Returns a random integer * * @return object */ public function randomInteger() { return $this->factory->randomInteger(); } /** * Converts a BigInteger to a FiniteField integer * * @return object */ public function convertInteger(BigInteger $x) { return $this->factory->newInteger($x); } /** * Returns the length, in bytes, of the modulo * * @return integer */ public function getLengthInBytes() { return $this->factory->getLengthInBytes(); } /** * Returns the length, in bits, of the modulo * * @return integer */ public function getLength() { return $this->factory->getLength(); } /** * Multiply a point on the curve by a scalar * * Uses the montgomery ladder technique as described here: * * https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder * https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772 * * @return array */ public function multiplyPoint(array $p, FiniteField\Integer $d) { $alreadyInternal = isset($p[2]); $r = $alreadyInternal ? [[], $p] : [[], $this->convertToInternal($p)]; $d = $d->toBits(); for ($i = 0; $i < strlen($d); $i++) { $d_i = (int) $d[$i]; $r[1 - $d_i] = $this->addPoint($r[0], $r[1]); $r[$d_i] = $this->doublePoint($r[$d_i]); } return $alreadyInternal ? $r[0] : $this->convertToAffine($r[0]); } /** * Creates a random scalar multiplier * * @return FiniteField */ public function createRandomMultiplier() { static $one; if (!isset($one)) { $one = new BigInteger(1); } $dA = BigInteger::randomRange($one, $this->order->subtract($one)); return $this->factory->newInteger($dA); } /** * Sets the Order */ public function setOrder(BigInteger $order) { $this->order = $order; } /** * Returns the Order * * @return \phpseclib\Math\BigInteger */ public function getOrder() { return $this->order; } /** * Use a custom defined modular reduction function * * @return object */ public function setReduction(callable $func) { $this->factory->setReduction($func); } /** * Returns the affine point * * @return object[] */ public function convertToAffine(array $p) { return $p; } /** * Converts an affine point to a jacobian coordinate * * @return object[] */ public function convertToInternal(array $p) { return $p; } /** * Negates a point * * @return object[] */ public function negatePoint(array $p) { $temp = [ $p[0], $p[1]->negate() ]; if (isset($p[2])) { $temp[] = $p[2]; } return $temp; } /** * Multiply and Add Points * * @return int[] */ public function multiplyAddPoints(array $points, array $scalars) { $p1 = $this->convertToInternal($points[0]); $p2 = $this->convertToInternal($points[1]); $p1 = $this->multiplyPoint($p1, $scalars[0]); $p2 = $this->multiplyPoint($p2, $scalars[1]); $r = $this->addPoint($p1, $p2); return $this->convertToAffine($r); } }<?php /** * Curves over y^2 = x^3 + a*x + b * * These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf * The curve is a weierstrass curve with a[1], a[3] and a[2] set to 0. * * Uses Jacobian Coordinates for speed if able: * * https://en.wikipedia.org/wiki/Jacobian_curve * https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\BaseCurves; use phpseclib\Math\Common\FiniteField\Integer; use phpseclib\Common\Functions\Strings; use phpseclib\Math\PrimeField; use phpseclib\Math\BigInteger; use phpseclib\Math\PrimeField\Integer as PrimeInteger; /** * Curves over y^2 = x^3 + a*x + b * * @package Prime * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Prime extends Base { /** * Prime Field Integer factory * * @var \phpseclib\Math\PrimeFields */ protected $factory; /** * Cofficient for x^1 * * @var object */ protected $a; /** * Cofficient for x^0 * * @var object */ protected $b; /** * Base Point * * @var object */ protected $p; /** * The number one over the specified finite field * * @var object */ protected $one; /** * The number two over the specified finite field * * @var object */ protected $two; /** * The number three over the specified finite field * * @var object */ protected $three; /** * The number four over the specified finite field * * @var object */ protected $four; /** * The number eight over the specified finite field * * @var object */ protected $eight; /** * The modulo * * @var BigInteger */ protected $modulo; /** * The Order * * @var BigInteger */ protected $order; /** * Sets the modulo */ public function setModulo(BigInteger $modulo) { $this->modulo = $modulo; $this->factory = new PrimeField($modulo); $this->two = $this->factory->newInteger(new BigInteger(2)); $this->three = $this->factory->newInteger(new BigInteger(3)); // used by jacobian coordinates $this->one = $this->factory->newInteger(new BigInteger(1)); $this->four = $this->factory->newInteger(new BigInteger(4)); $this->eight = $this->factory->newInteger(new BigInteger(8)); } /** * Set coefficients a and b */ public function setCoefficients(BigInteger $a, BigInteger $b) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } $this->a = $this->factory->newInteger($a); $this->b = $this->factory->newInteger($b); } /** * Set x and y coordinates for the base point * * @param BigInteger|PrimeInteger $x * @param BigInteger|PrimeInteger $y * @return PrimeInteger[] */ public function setBasePoint($x, $y) { switch (true) { case !$x instanceof BigInteger && !$x instanceof PrimeInteger: throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer'); case !$y instanceof BigInteger && !$y instanceof PrimeInteger: throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer'); } if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } $this->p = [ $x instanceof BigInteger ? $this->factory->newInteger($x) : $x, $y instanceof BigInteger ? $this->factory->newInteger($y) : $y ]; } /** * Retrieve the base point as an array * * @return array */ public function getBasePoint() { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } /* if (!isset($this->p)) { throw new \RuntimeException('setBasePoint needs to be called before this method'); } */ return $this->p; } /** * Adds two "fresh" jacobian form on the curve * * @return FiniteField[] */ protected function jacobianAddPointMixedXY(array $p, array $q) { list($u1, $s1) = $p; list($u2, $s2) = $q; if ($u1->equals($u2)) { if (!$s1->equals($s2)) { return []; } else { return $this->doublePoint($p); } } $h = $u2->subtract($u1); $r = $s2->subtract($s1); $h2 = $h->multiply($h); $h3 = $h2->multiply($h); $v = $u1->multiply($h2); $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two)); $y3 = $r->multiply( $v->subtract($x3))->subtract( $s1->multiply($h3)); return [$x3, $y3, $h]; } /** * Adds one "fresh" jacobian form on the curve * * The second parameter should be the "fresh" one * * @return FiniteField[] */ protected function jacobianAddPointMixedX(array $p, array $q) { list($u1, $s1, $z1) = $p; list($x2, $y2) = $q; $z12 = $z1->multiply($z1); $u2 = $x2->multiply($z12); $s2 = $y2->multiply($z12->multiply($z1)); if ($u1->equals($u2)) { if (!$s1->equals($s2)) { return []; } else { return $this->doublePoint($p); } } $h = $u2->subtract($u1); $r = $s2->subtract($s1); $h2 = $h->multiply($h); $h3 = $h2->multiply($h); $v = $u1->multiply($h2); $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two)); $y3 = $r->multiply( $v->subtract($x3))->subtract( $s1->multiply($h3)); $z3 = $h->multiply($z1); return [$x3, $y3, $z3]; } /** * Adds two jacobian coordinates on the curve * * @return FiniteField[] */ protected function jacobianAddPoint(array $p, array $q) { list($x1, $y1, $z1) = $p; list($x2, $y2, $z2) = $q; $z12 = $z1->multiply($z1); $z22 = $z2->multiply($z2); $u1 = $x1->multiply($z22); $u2 = $x2->multiply($z12); $s1 = $y1->multiply($z22->multiply($z2)); $s2 = $y2->multiply($z12->multiply($z1)); if ($u1->equals($u2)) { if (!$s1->equals($s2)) { return []; } else { return $this->doublePoint($p); } } $h = $u2->subtract($u1); $r = $s2->subtract($s1); $h2 = $h->multiply($h); $h3 = $h2->multiply($h); $v = $u1->multiply($h2); $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two)); $y3 = $r->multiply( $v->subtract($x3))->subtract( $s1->multiply($h3)); $z3 = $h->multiply($z1)->multiply($z2); return [$x3, $y3, $z3]; } /** * Adds two points on the curve * * @return FiniteField[] */ public function addPoint(array $p, array $q) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p) || !count($q)) { if (count($q)) { return $q; } if (count($p)) { return $p; } return []; } // use jacobian coordinates if (isset($p[2]) && isset($q[2])) { if (isset($p['fresh']) && isset($q['fresh'])) { return $this->jacobianAddPointMixedXY($p, $q); } if (isset($p['fresh'])) { return $this->jacobianAddPointMixedX($q, $p); } if (isset($q['fresh'])) { return $this->jacobianAddPointMixedX($p, $q); } return $this->jacobianAddPoint($p, $q); } if (isset($p[2]) || isset($q[2])) { throw new \RuntimeException('Affine coordinates need to be manually converted to Jacobi coordinates or vice versa'); } if ($p[0]->equals($q[0])) { if (!$p[1]->equals($q[1])) { return []; } else { // eg. doublePoint list($numerator, $denominator) = $this->doublePointHelper($p); } } else { $numerator = $q[1]->subtract($p[1]); $denominator = $q[0]->subtract($p[0]); } $slope = $numerator->divide($denominator); $x = $slope->multiply($slope)->subtract($p[0])->subtract($q[0]); $y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]); return [$x, $y]; } /** * Returns the numerator and denominator of the slope * * @return FiniteField[] */ protected function doublePointHelper(array $p) { $numerator = $this->three->multiply($p[0])->multiply($p[0])->add($this->a); $denominator = $this->two->multiply($p[1]); return [$numerator, $denominator]; } /** * Doubles a jacobian coordinate on the curve * * @return FiniteField[] */ protected function jacobianDoublePoint(array $p) { list($x, $y, $z) = $p; $x2 = $x->multiply($x); $y2 = $y->multiply($y); $z2 = $z->multiply($z); $s = $this->four->multiply($x)->multiply($y2); $m1 = $this->three->multiply($x2); $m2 = $this->a->multiply($z2->multiply($z2)); $m = $m1->add($m2); $x1 = $m->multiply($m)->subtract($this->two->multiply($s)); $y1 = $m->multiply($s->subtract($x1))->subtract( $this->eight->multiply($y2->multiply($y2))); $z1 = $this->two->multiply($y)->multiply($z); return [$x1, $y1, $z1]; } /** * Doubles a "fresh" jacobian coordinate on the curve * * @return FiniteField[] */ protected function jacobianDoublePointMixed(array $p) { list($x, $y) = $p; $x2 = $x->multiply($x); $y2 = $y->multiply($y); $s = $this->four->multiply($x)->multiply($y2); $m1 = $this->three->multiply($x2); $m = $m1->add($this->a); $x1 = $m->multiply($m)->subtract($this->two->multiply($s)); $y1 = $m->multiply($s->subtract($x1))->subtract( $this->eight->multiply($y2->multiply($y2))); $z1 = $this->two->multiply($y); return [$x1, $y1, $z1]; } /** * Doubles a point on a curve * * @return FiniteField[] */ public function doublePoint(array $p) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } if (!count($p)) { return []; } // use jacobian coordinates if (isset($p[2])) { if (isset($p['fresh'])) { return $this->jacobianDoublePointMixed($p); } return $this->jacobianDoublePoint($p); } list($numerator, $denominator) = $this->doublePointHelper($p); $slope = $numerator->divide($denominator); $x = $slope->multiply($slope)->subtract($p[0])->subtract($p[0]); $y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]); return [$x, $y]; } /** * Returns the X coordinate and the derived Y coordinate * * @return array */ public function derivePoint($m) { $y = ord(Strings::shift($m)); $x = new BigInteger($m, 256); $xp = $this->convertInteger($x); switch ($y) { case 2: $ypn = false; break; case 3: $ypn = true; break; default: throw new \RuntimeException('Coordinate not in recognized format'); } $temp = $xp->multiply($this->a); $temp = $xp->multiply($xp)->multiply($xp)->add($temp); $temp = $temp->add($this->b); $b = $temp->squareRoot(); if (!$b) { throw new \RuntimeException('Unable to derive Y coordinate'); } $bn = $b->isOdd(); $yp = $ypn == $bn ? $b : $b->negate(); return [$xp, $yp]; } /** * Tests whether or not the x / y values satisfy the equation * * @return boolean */ public function verifyPoint(array $p) { list($x, $y) = $p; $lhs = $y->multiply($y); $temp = $x->multiply($this->a); $temp = $x->multiply($x)->multiply($x)->add($temp); $rhs = $temp->add($this->b); return $lhs->equals($rhs); } /** * Returns the modulo * * @return \phpseclib\Math\BigInteger */ public function getModulo() { return $this->modulo; } /** * Returns the a coefficient * * @return \phpseclib\Math\PrimeField\Integer */ public function getA() { return $this->a; } /** * Returns the a coefficient * * @return \phpseclib\Math\PrimeField\Integer */ public function getB() { return $this->b; } /** * Multiply and Add Points * * Adapted from https://git.io/vxPUH * * @return int[] */ public function multiplyAddPoints(array $points, array $scalars) { $length = count($points); foreach ($points as &$point) { $point = $this->convertToInternal($point); } $wnd = [$this->getNAFPoints($points[0], 7)]; $wndWidth = [isset($points[0]['nafwidth']) ? $points[0]['nafwidth'] : 7]; for ($i = 1; $i < $length; $i++) { $wnd[] = $this->getNAFPoints($points[$i], 1); $wndWidth[] = isset($points[$i]['nafwidth']) ? $points[$i]['nafwidth'] : 1; } $naf = []; // comb all window NAFs $max = 0; for ($i = $length - 1; $i >= 1; $i-= 2) { $a = $i - 1; $b = $i; if ($wndWidth[$a] != 1 || $wndWidth[$b] != 1) { $naf[$a] = $scalars[$a]->getNAF($wndWidth[$a]); $naf[$b] = $scalars[$b]->getNAF($wndWidth[$b]); $max = max(count($naf[$a]), count($naf[$b]), $max); continue; } $comb = [ $points[$a], // 1 null, // 3 null, // 5 $points[$b] // 7 ]; $comb[1] = $this->addPoint($points[$a], $points[$b]); $comb[2] = $this->addPoint($points[$a], $this->negatePoint($points[$b])); $index = [ -3, /* -1 -1 */ -1, /* -1 0 */ -5, /* -1 1 */ -7, /* 0 -1 */ 0, /* 0 -1 */ 7, /* 0 1 */ 5, /* 1 -1 */ 1, /* 1 0 */ 3 /* 1 1 */ ]; $jsf = self::getJSFPoints($scalars[$a], $scalars[$b]); $max = max(count($jsf[0]), $max); if ($max > 0) { $naf[$a] = array_fill(0, $max, 0); $naf[$b] = array_fill(0, $max, 0); } else { $naf[$a] = []; $naf[$b] = []; } for ($j = 0; $j < $max; $j++) { $ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0; $jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0; $naf[$a][$j] = $index[3 * ($ja + 1) + $jb + 1]; $naf[$b][$j] = 0; $wnd[$a] = $comb; } } $acc = []; $temp = [0, 0, 0, 0]; for ($i = $max; $i >= 0; $i--) { $k = 0; while ($i >= 0) { $zero = true; for ($j = 0; $j < $length; $j++) { $temp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0; if ($temp[$j] != 0) { $zero = false; } } if (!$zero) { break; } $k++; $i--; } if ($i >= 0) { $k++; } while ($k--) { $acc = $this->doublePoint($acc); } if ($i < 0) { break; } for ($j = 0; $j < $length; $j++) { $z = $temp[$j]; $p = null; if ($z == 0) { continue; } $p = $z > 0 ? $wnd[$j][($z - 1) >> 1] : $this->negatePoint($wnd[$j][(-$z - 1) >> 1]); $acc = $this->addPoint($acc, $p); } } return $this->convertToAffine($acc); } /** * Precomputes NAF points * * Adapted from https://git.io/vxY1f * * @return int[] */ private function getNAFPoints($point, $wnd) { if (isset($point['naf'])) { return $point['naf']; } $res = [$point]; $max = (1 << $wnd) - 1; $dbl = $max == 1 ? null : $this->doublePoint($point); for ($i = 1; $i < $max; $i++) { $res[] = $this->addPoint($res[$i - 1], $dbl); } $point['naf'] = $res; /* $str = ''; foreach ($res as $re) { $re[0] = bin2hex($re[0]->toBytes()); $re[1] = bin2hex($re[1]->toBytes()); $str.= " ['$re[0]', '$re[1]'],\r\n"; } file_put_contents('temp.txt', $str); exit; */ return $res; } /** * Precomputes points in Joint Sparse Form * * Adapted from https://git.io/vxrpD * * @return int[] */ private static function getJSFPoints(Integer $k1, Integer $k2) { static $three; if (!isset($three)) { $three = new BigInteger(3); } $jsf = [[], []]; $k1 = $k1->toBigInteger(); $k2 = $k2->toBigInteger(); $d1 = 0; $d2 = 0; while ($k1->compare(new BigInteger(-$d1)) > 0 || $k2->compare(new BigInteger(-$d2)) > 0) { // first phase $m14 = $k1->testBit(0) + 2 * $k1->testBit(1); $m14+= $d1; $m14&= 3; $m24 = $k2->testBit(0) + 2 * $k2->testBit(1); $m24+= $d2; $m24&= 3; if ($m14 == 3) { $m14 = -1; } if ($m24 == 3) { $m24 = -1; } $u1 = 0; if ($m14 & 1) { // if $m14 is odd $m8 = $k1->testBit(0) + 2 * $k1->testBit(1) + 4 * $k1->testBit(2); $m8+= $d1; $m8&= 7; $u1 = ($m8 == 3 || $m8 == 5) && $m24 == 2 ? -$m14 : $m14; } $jsf[0][] = $u1; $u2 = 0; if ($m24 & 1) { // if $m24 is odd $m8 = $k2->testBit(0) + 2 * $k2->testBit(1) + 4 * $k2->testBit(2); $m8+= $d2; $m8&= 7; $u2 = ($m8 == 3 || $m8 == 5) && $m14 == 2 ? -$m24 : $m24; } $jsf[1][] = $u2; // second phase if (2 * $d1 == $u1 + 1) { $d1 = 1 - $d1; } if (2 * $d2 == $u2 + 1) { $d2 = 1 - $d2; } $k1 = $k1->bitwise_rightShift(1); $k2 = $k2->bitwise_rightShift(1); } return $jsf; } /** * Returns the affine point * * A Jacobian Coordinate is of the form (x, y, z). * To convert a Jacobian Coordinate to an Affine Point * you do (x / z^2, y / z^3) * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToAffine(array $p) { if (!isset($p[2])) { return $p; } list($x, $y, $z) = $p; $z = $this->one->divide($z); $z2 = $z->multiply($z); return [ $x->multiply($z2), $y->multiply($z2)->multiply($z) ]; } /** * Converts an affine point to a jacobian coordinate * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToInternal(array $p) { if (isset($p[2])) { return $p; } $p[2] = clone $this->one; $p['fresh'] = true; return $p; } }<?php /** * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2 * * http://www.secg.org/SEC2-Ver-1.0.pdf provides for curves with custom parameters. * ie. the coefficients can be arbitrary set through specially formatted keys, etc. * As such, Prime.php is built very generically and it's not able to take full * advantage of curves with 0 coefficients to produce simplified point doubling, * point addition. Twisted Edwards curves, in contrast, do not have a way, currently, * to customize them. As such, we can omit the super generic stuff from this class * and let the named curves (Ed25519 and Ed448) define their own custom tailored * point addition and point doubling methods. * * More info: * * https://en.wikipedia.org/wiki/Twisted_Edwards_curve * * PHP version 5 and 7 * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Crypt\ECDSA\BaseCurves; use phpseclib\Math\PrimeField; use phpseclib\Math\BigInteger; use phpseclib\Math\PrimeField\Integer as PrimeInteger; /** * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2 * * @package Prime * @author Jim Wigginton <terrafrost@php.net> * @access public */ class TwistedEdwards extends Base { /** * The modulo * * @var BigInteger */ protected $modulo; /** * Cofficient for x^2 * * @var object */ protected $a; /** * Cofficient for x^2*y^2 * * @var object */ protected $d; /** * Base Point * * @var object[] */ protected $p; /** * The number zero over the specified finite field * * @var object */ protected $zero; /** * The number one over the specified finite field * * @var object */ protected $one; /** * The number two over the specified finite field * * @var object */ protected $two; /** * Sets the modulo */ public function setModulo(BigInteger $modulo) { $this->modulo = $modulo; $this->factory = new PrimeField($modulo); $this->zero = $this->factory->newInteger(new BigInteger(0)); $this->one = $this->factory->newInteger(new BigInteger(1)); $this->two = $this->factory->newInteger(new BigInteger(2)); } /** * Set coefficients a and b */ public function setCoefficients(BigInteger $a, BigInteger $d) { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } $this->a = $this->factory->newInteger($a); $this->d = $this->factory->newInteger($d); } /** * Set x and y coordinates for the base point */ public function setBasePoint($x, $y) { switch (true) { case !$x instanceof BigInteger && !$x instanceof PrimeInteger: throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer'); case !$y instanceof BigInteger && !$y instanceof PrimeInteger: throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer'); } if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } $this->p = [ $x instanceof BigInteger ? $this->factory->newInteger($x) : $x, $y instanceof BigInteger ? $this->factory->newInteger($y) : $y ]; } /** * Returns the a coefficient * * @return \phpseclib\Math\PrimeField\Integer */ public function getA() { return $this->a; } /** * Returns the a coefficient * * @return \phpseclib\Math\PrimeField\Integer */ public function getD() { return $this->d; } /** * Retrieve the base point as an array * * @return array */ public function getBasePoint() { if (!isset($this->factory)) { throw new \RuntimeException('setModulo needs to be called before this method'); } /* if (!isset($this->p)) { throw new \RuntimeException('setBasePoint needs to be called before this method'); } */ return $this->p; } /** * Returns the affine point * * @return \phpseclib\Math\PrimeField\Integer[] */ public function convertToAffine(array $p) { if (!isset($p[2])) { return $p; } list($x, $y, $z) = $p; $z = $this->one->divide($z); return [ $x->multiply($z), $y->multiply($z) ]; } /** * Returns the modulo * * @return \phpseclib\Math\BigInteger */ public function getModulo() { return $this->modulo; } /** * Tests whether or not the x / y values satisfy the equation * * @return boolean */ public function verifyPoint(array $p) { list($x, $y) = $p; $x2 = $x->multiply($x); $y2 = $y->multiply($y); $lhs = $this->a->multiply($x2)->add($y2); $rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one); return $lhs->equals($rhs); } /** * Tests whether or not the x / y values satisfy the equation * * @return boolean */ public function get(array $p) { list($x, $y) = $p; $x2 = $x->multiply($x); $y2 = $y->multiply($y); $lhs = $this->a->multiply($x2)->add($y2); $rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one); return $lhs->equals($rhs); } }<?php /** * ECDSA Parameters * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA; use phpseclib\Crypt\ECDSA; /** * ECDSA Parameters * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Parameters extends ECDSA { /** * Returns the parameters * * @param string $type * @param array $options optional * @return string */ public function toString($type = 'PKCS1', array $options = []) { $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters'); return $type::saveParameters($this->curve, $options); } } <?php /** * ECDSA Public Key * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA; use phpseclib\Crypt\ECDSA; use phpseclib\Crypt\Hash; use phpseclib\Math\BigInteger; use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Crypt\ECDSA\Curves\Ed25519; use phpseclib\Crypt\ECDSA\Keys\PKCS1; use phpseclib\Crypt\ECDSA\Keys\PKCS8; use phpseclib\Crypt\Common; /** * ECDSA Public Key * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PublicKey extends ECDSA implements Common\PublicKey { use Common\Fingerprint; /** * Verify a signature * * @see self::verify() * @access public * @param string $message * @param string $signature * @return mixed */ public function verify($message, $signature) { $order = $this->curve->getOrder(); if ($this->curve instanceof TwistedEdwardsCurve) { if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) { return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium')); } $curve = $this->curve; if (strlen($signature) != 2 * $curve::SIZE) { return false; } $R = substr($signature, 0, $curve::SIZE); $S = substr($signature, $curve::SIZE); try { $R = PKCS1::extractPoint($R, $curve); $R = $this->curve->convertToInternal($R); } catch (\Exception $e) { return false; } $S = strrev($S); $S = new BigInteger($S, 256); if ($S->compare($order) >= 0) { return false; } $A = $curve->encodePoint($this->QA); if ($curve instanceof Ed25519) { $dom2 = !isset($this->context) ? '' : 'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context; } else { $context = isset($this->context) ? $this->context : ''; $dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context; } $hash = new Hash($curve::HASH); $k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message); $k = strrev($k); $k = new BigInteger($k, 256); list(, $k) = $k->divide($order); $qa = $curve->convertToInternal($this->QA); $lhs = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($S)); $rhs = $curve->multiplyPoint($qa, $curve->convertInteger($k)); $rhs = $curve->addPoint($rhs, $R); $rhs = $curve->convertToAffine($rhs); return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]); } $format = $this->format; $params = $format::load($signature); if ($params === false || count($params) != 2) { return false; } extract($params); if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); if ($result != -1) { return (bool) $result; } } $n_1 = $order->subtract(self::$one); if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) { return false; } $e = $this->hash->hash($message); $e = new BigInteger($e, 256); $Ln = $this->hash->getLength() - $order->getLength(); $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e; $w = $s->modInverse($order); list(, $u1) = $z->multiply($w)->divide($order); list(, $u2) = $r->multiply($w)->divide($order); $u1 = $this->curve->convertInteger($u1); $u2 = $this->curve->convertInteger($u2); list($x1, $y1) = $this->curve->multiplyAddPoints( [$this->curve->getBasePoint(), $this->QA], [$u1, $u2] ); $x1 = $x1->toBigInteger(); list(, $x1) = $x1->divide($order); return $x1->equals($r); } /** * Returns the public key * * @param string $type * @param array $options optional * @return string */ public function toString($type, array $options = []) { $type = self::validatePlugin('Keys', $type, 'savePublicKey'); return $type::savePublicKey($this->curve, $this->QA, $options); } } <?php /** * SSH2 Signature Handler * * PHP version 5 * * Handles signatures in the format used by SSH2 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Signature; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; /** * SSH2 Signature Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SSH2 { /** * Loads a signature * * @access public * @param string $sig * @return mixed */ public static function load($sig) { if (!is_string($sig)) { return false; } $result = Strings::unpackSSH2('ss', $sig); if ($result === false) { return false; } list($type, $blob) = $result; switch ($type) { // see https://tools.ietf.org/html/rfc5656#section-3.1.2 case 'ecdsa-sha2-nistp256': case 'ecdsa-sha2-nistp384': case 'ecdsa-sha2-nistp521': break; default: return false; } $result = Strings::unpackSSH2('ii', $blob); if ($result === false) { return false; } return [ 'r' => $result[0], 's' => $result[1] ]; } /** * Returns a signature in the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $r * @param \phpseclib\Math\BigInteger $s * @param string $curve * @return string */ public static function save(BigInteger $r, BigInteger $s, $curve) { switch ($curve) { case 'secp256r1': $curve = 'nistp256'; break; case 'secp384r1': $curve = 'nistp384'; break; case 'secp521r1': $curve = 'nistp521'; break; default: return false; } $blob = Strings::packSSH2('ii', $r, $s); return Strings::packSSH2('ss', 'ecdsa-sha2-' . $curve, $blob); } } <?php /** * Raw ECDSA Signature Handler * * PHP version 5 * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Signature; use phpseclib\Crypt\Common\Signature\Raw as Progenitor; /** * Raw DSA Signature Handler * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Raw extends Progenitor { } <?php /** * ASN1 Signature Handler * * PHP version 5 * * Handles signatures in the format described in * https://tools.ietf.org/html/rfc3279#section-2.2.3 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\ECDSA\Signature; use phpseclib\Math\BigInteger; use phpseclib\File\ASN1 as Encoder; use phpseclib\File\ASN1\Maps\EcdsaSigValue; /** * ASN1 Signature Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ASN1 { /** * Loads a signature * * @access public * @param array $key * @return array */ public static function load($sig) { if (!is_string($sig)) { return false; } $decoded = Encoder::decodeBER($sig); if (empty($decoded)) { return false; } $components = Encoder::asn1map($decoded[0], EcdsaSigValue::MAP); return $components; } /** * Returns a signature in the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $r * @param \phpseclib\Math\BigInteger $s * @return string */ public static function save(BigInteger $r, BigInteger $s) { return Encoder::encodeDER(compact('r', 's'), EcdsaSigValue::MAP); } } <?php /** * Pure-PHP implementation of DES. * * Uses mcrypt, if available, and an internal implementation, otherwise. * * PHP version 5 * * Useful resources are as follows: * * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material} * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard} * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example} * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $des = new \phpseclib\Crypt\DES(); * * $des->setKey('abcdefgh'); * * $size = 10 * 1024; * $plaintext = ''; * for ($i = 0; $i < $size; $i++) { * $plaintext.= 'a'; * } * * echo $des->decrypt($des->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package DES * @author Jim Wigginton <terrafrost@php.net> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\BlockCipher; use phpseclib\Exception\BadModeException; /** * Pure-PHP implementation of DES. * * @package DES * @author Jim Wigginton <terrafrost@php.net> * @access public */ class DES extends BlockCipher { /**#@+ * @access private * @see \phpseclib\Crypt\DES::setupKey() * @see \phpseclib\Crypt\DES::processBlock() */ /** * Contains $keys[self::ENCRYPT] */ const ENCRYPT = 0; /** * Contains $keys[self::DECRYPT] */ const DECRYPT = 1; /**#@-*/ /** * Block Length of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::block_size * @var int * @access private */ protected $block_size = 8; /** * Key Length (in bytes) * * @see \phpseclib\Crypt\Common\SymmetricKey::setKeyLength() * @var int * @access private */ protected $key_length = 8; /** * The mcrypt specific name of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @var string * @access private */ protected $cipher_name_mcrypt = 'des'; /** * The OpenSSL names of the cipher / modes * * @see \phpseclib\Crypt\Common\SymmetricKey::openssl_mode_names * @var array * @access private */ protected $openssl_mode_names = [ self::MODE_ECB => 'des-ecb', self::MODE_CBC => 'des-cbc', self::MODE_CFB => 'des-cfb', self::MODE_OFB => 'des-ofb' // self::MODE_CTR is undefined for DES ]; /** * Optimizing value while CFB-encrypting * * @see \phpseclib\Crypt\Common\SymmetricKey::cfb_init_len * @var int * @access private */ protected $cfb_init_len = 500; /** * Switch for DES/3DES encryption * * Used only if $engine == self::ENGINE_INTERNAL * * @see self::setupKey() * @see self::processBlock() * @var int * @access private */ protected $des_rounds = 1; /** * max possible size of $key * * @see self::setKey() * @var string * @access private */ protected $key_length_max = 8; /** * The Key Schedule * * @see self::setupKey() * @var array * @access private */ private $keys; /** * Shuffle table. * * For each byte value index, the entry holds an 8-byte string * with each byte containing all bits in the same state as the * corresponding bit in the index value. * * @see self::processBlock() * @see self::setupKey() * @var array * @access private */ protected static $shuffle = [ "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF", "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF", "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF", "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF", "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF", "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF", "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF", "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF", "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF", "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF", "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF", "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF", "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF", "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF", "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF", "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF", "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF", "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF", "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF", "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF", "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF", "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF", "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF", "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF", "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF", "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF", "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF", "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF", "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF", "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF", "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF", "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF", "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF", "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF", "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF", "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF", "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF", "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF", "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF", "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF", "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF", "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF", "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF", "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF", "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF", "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF", "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF", "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF", "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF", "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF", "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF", "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF", "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF", "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF", "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF", "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF", "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF", "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF", "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF", "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF", "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF", "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF", "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF", "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF", "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF", "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF", "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF", "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF", "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF", "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF", "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF", "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF", "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF", "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF", "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF", "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF", "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF", "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF", "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF", "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF", "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF", "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF", "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF", "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF", "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF", "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF", "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF", "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF", "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF", "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF", "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF", "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF", "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF", "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF", "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF", "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF", "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF", "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF", "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF", "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF", "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF", "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF", "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF", "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF", "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF", "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF", "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF", "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF", "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF", "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF", "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF", "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF", "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF", "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF", "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF", "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF", "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF", "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF", "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF", "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" ]; /** * IP mapping helper table. * * Indexing this table with each source byte performs the initial bit permutation. * * @var array * @access private */ protected static $ipmap = [ 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31, 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33, 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71, 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73, 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35, 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37, 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75, 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77, 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1, 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3, 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1, 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3, 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5, 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7, 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5, 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7, 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39, 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B, 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79, 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B, 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D, 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D, 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9, 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB, 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9, 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB, 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD, 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF, 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD, 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF ]; /** * Inverse IP mapping helper table. * Indexing this table with a byte value reverses the bit order. * * @var array * @access private */ protected static $invipmap = [ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF ]; /** * Pre-permuted S-box1 * * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the * P table: concatenation can then be replaced by exclusive ORs. * * @var array * @access private */ protected static $sbox1 = [ 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000, 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002, 0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202, 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000, 0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200, 0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202, 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200, 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002 ]; /** * Pre-permuted S-box2 * * @var array * @access private */ protected static $sbox2 = [ 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010, 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010, 0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000, 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010, 0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000, 0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000, 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010, 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000 ]; /** * Pre-permuted S-box3 * * @var array * @access private */ protected static $sbox3 = [ 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100, 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104, 0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104, 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000, 0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000, 0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004, 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004, 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100 ]; /** * Pre-permuted S-box4 * * @var array * @access private */ protected static $sbox4 = [ 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000, 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000, 0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040, 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040, 0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000, 0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040, 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040 ]; /** * Pre-permuted S-box5 * * @var array * @access private */ protected static $sbox5 = [ 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000, 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000, 0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080, 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080, 0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080, 0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000, 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000, 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080 ]; /** * Pre-permuted S-box6 * * @var array * @access private */ protected static $sbox6 = [ 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000, 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008, 0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008, 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000, 0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008, 0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000, 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008, 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008 ]; /** * Pre-permuted S-box7 * * @var array * @access private */ protected static $sbox7 = [ 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400, 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401, 0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001, 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400, 0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001, 0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400, 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401, 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001 ]; /** * Pre-permuted S-box8 * * @var array * @access private */ protected static $sbox8 = [ 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000, 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020, 0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800, 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000, 0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820, 0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820, 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000, 0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800 ]; /** * Default Constructor. * * @param int $mode * @access public * @throws BadModeException if an invalid / unsupported mode is provided */ public function __construct($mode) { if ($mode == self::MODE_STREAM) { throw new BadModeException('Block ciphers cannot be ran in stream mode'); } parent::__construct($mode); } /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { if ($this->key_length_max == 8) { if ($engine == self::ENGINE_OPENSSL) { self::$cipher_name_openssl_ecb = 'des-ecb'; $this->cipher_name_openssl = 'des-' . $this->openssl_translate_mode(); } } return parent::isValidEngineHelper($engine); } /** * Sets the key. * * Keys must be 64-bits long or 8 bytes long. * * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. * * @see \phpseclib\Crypt\Common\SymmetricKey::setKey() * @access public * @param string $key */ public function setKey($key) { if (!($this instanceof TripleDES) && strlen($key) != 8) { throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of size 8 are supported'); } // Sets the key parent::setKey($key); } /** * Encrypts a block * * @see \phpseclib\Crypt\Common\SymmetricKey::encryptBlock() * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @see self::encrypt() * @access private * @param string $in * @return string */ protected function encryptBlock($in) { return $this->processBlock($in, self::ENCRYPT); } /** * Decrypts a block * * @see \phpseclib\Crypt\Common\SymmetricKey::decryptBlock() * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() * @see self::decrypt() * @access private * @param string $in * @return string */ protected function decryptBlock($in) { return $this->processBlock($in, self::DECRYPT); } /** * Encrypts or decrypts a 64-bit block * * $mode should be either self::ENCRYPT or self::DECRYPT. See * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general * idea of what this function does. * * @see self::encryptBlock() * @see self::decryptBlock() * @access private * @param string $block * @param int $mode * @return string */ private function processBlock($block, $mode) { static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; if (!$sbox1) { $sbox1 = array_map('intval', self::$sbox1); $sbox2 = array_map('intval', self::$sbox2); $sbox3 = array_map('intval', self::$sbox3); $sbox4 = array_map('intval', self::$sbox4); $sbox5 = array_map('intval', self::$sbox5); $sbox6 = array_map('intval', self::$sbox6); $sbox7 = array_map('intval', self::$sbox7); $sbox8 = array_map('intval', self::$sbox8); /* Merge $shuffle with $[inv]ipmap */ for ($i = 0; $i < 256; ++$i) { $shuffleip[] = self::$shuffle[self::$ipmap[$i]]; $shuffleinvip[] = self::$shuffle[self::$invipmap[$i]]; } } $keys = $this->keys[$mode]; $ki = -1; // Do the initial IP permutation. $t = unpack('Nl/Nr', $block); list($l, $r) = [$t['l'], $t['r']]; $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); // Extract L0 and R0. $t = unpack('Nl/Nr', $block); list($l, $r) = [$t['l'], $t['r']]; for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { // Perform the 16 steps. for ($i = 0; $i < 16; $i++) { // start of "the Feistel (F) function" - see the following URL: // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png // Merge key schedule. $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki]; $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki]; // S-box indexing. $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l; // end of "the Feistel (F) function" $l = $r; $r = $t; } // Last step should not permute L & R. $t = $l; $l = $r; $r = $t; } // Perform the inverse IP permutation. return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); } /** * Creates the key schedule * * @see \phpseclib\Crypt\Common\SymmetricKey::setupKey() * @access private */ protected function setupKey() { if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) { // already expanded return; } $this->kl = ['key' => $this->key, 'des_rounds' => $this->des_rounds]; static $shifts = [ // number of key bits shifted per round 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ]; static $pc1map = [ 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C, 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E, 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C, 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E, 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C, 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E, 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C, 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E, 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C, 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E, 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C, 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E, 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C, 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E, 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C, 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E, 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C, 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E, 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C, 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E, 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC, 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE, 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC, 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE, 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC, 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE, 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC, 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE, 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC, 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE, 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC, 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE ]; // Mapping tables for the PC-2 transformation. static $pc2mapc1 = [ 0x00000000, 0x00000400, 0x00200000, 0x00200400, 0x00000001, 0x00000401, 0x00200001, 0x00200401, 0x02000000, 0x02000400, 0x02200000, 0x02200400, 0x02000001, 0x02000401, 0x02200001, 0x02200401 ]; static $pc2mapc2 = [ 0x00000000, 0x00000800, 0x08000000, 0x08000800, 0x00010000, 0x00010800, 0x08010000, 0x08010800, 0x00000000, 0x00000800, 0x08000000, 0x08000800, 0x00010000, 0x00010800, 0x08010000, 0x08010800, 0x00000100, 0x00000900, 0x08000100, 0x08000900, 0x00010100, 0x00010900, 0x08010100, 0x08010900, 0x00000100, 0x00000900, 0x08000100, 0x08000900, 0x00010100, 0x00010900, 0x08010100, 0x08010900, 0x00000010, 0x00000810, 0x08000010, 0x08000810, 0x00010010, 0x00010810, 0x08010010, 0x08010810, 0x00000010, 0x00000810, 0x08000010, 0x08000810, 0x00010010, 0x00010810, 0x08010010, 0x08010810, 0x00000110, 0x00000910, 0x08000110, 0x08000910, 0x00010110, 0x00010910, 0x08010110, 0x08010910, 0x00000110, 0x00000910, 0x08000110, 0x08000910, 0x00010110, 0x00010910, 0x08010110, 0x08010910, 0x00040000, 0x00040800, 0x08040000, 0x08040800, 0x00050000, 0x00050800, 0x08050000, 0x08050800, 0x00040000, 0x00040800, 0x08040000, 0x08040800, 0x00050000, 0x00050800, 0x08050000, 0x08050800, 0x00040100, 0x00040900, 0x08040100, 0x08040900, 0x00050100, 0x00050900, 0x08050100, 0x08050900, 0x00040100, 0x00040900, 0x08040100, 0x08040900, 0x00050100, 0x00050900, 0x08050100, 0x08050900, 0x00040010, 0x00040810, 0x08040010, 0x08040810, 0x00050010, 0x00050810, 0x08050010, 0x08050810, 0x00040010, 0x00040810, 0x08040010, 0x08040810, 0x00050010, 0x00050810, 0x08050010, 0x08050810, 0x00040110, 0x00040910, 0x08040110, 0x08040910, 0x00050110, 0x00050910, 0x08050110, 0x08050910, 0x00040110, 0x00040910, 0x08040110, 0x08040910, 0x00050110, 0x00050910, 0x08050110, 0x08050910, 0x01000000, 0x01000800, 0x09000000, 0x09000800, 0x01010000, 0x01010800, 0x09010000, 0x09010800, 0x01000000, 0x01000800, 0x09000000, 0x09000800, 0x01010000, 0x01010800, 0x09010000, 0x09010800, 0x01000100, 0x01000900, 0x09000100, 0x09000900, 0x01010100, 0x01010900, 0x09010100, 0x09010900, 0x01000100, 0x01000900, 0x09000100, 0x09000900, 0x01010100, 0x01010900, 0x09010100, 0x09010900, 0x01000010, 0x01000810, 0x09000010, 0x09000810, 0x01010010, 0x01010810, 0x09010010, 0x09010810, 0x01000010, 0x01000810, 0x09000010, 0x09000810, 0x01010010, 0x01010810, 0x09010010, 0x09010810, 0x01000110, 0x01000910, 0x09000110, 0x09000910, 0x01010110, 0x01010910, 0x09010110, 0x09010910, 0x01000110, 0x01000910, 0x09000110, 0x09000910, 0x01010110, 0x01010910, 0x09010110, 0x09010910, 0x01040000, 0x01040800, 0x09040000, 0x09040800, 0x01050000, 0x01050800, 0x09050000, 0x09050800, 0x01040000, 0x01040800, 0x09040000, 0x09040800, 0x01050000, 0x01050800, 0x09050000, 0x09050800, 0x01040100, 0x01040900, 0x09040100, 0x09040900, 0x01050100, 0x01050900, 0x09050100, 0x09050900, 0x01040100, 0x01040900, 0x09040100, 0x09040900, 0x01050100, 0x01050900, 0x09050100, 0x09050900, 0x01040010, 0x01040810, 0x09040010, 0x09040810, 0x01050010, 0x01050810, 0x09050010, 0x09050810, 0x01040010, 0x01040810, 0x09040010, 0x09040810, 0x01050010, 0x01050810, 0x09050010, 0x09050810, 0x01040110, 0x01040910, 0x09040110, 0x09040910, 0x01050110, 0x01050910, 0x09050110, 0x09050910, 0x01040110, 0x01040910, 0x09040110, 0x09040910, 0x01050110, 0x01050910, 0x09050110, 0x09050910 ]; static $pc2mapc3 = [ 0x00000000, 0x00000004, 0x00001000, 0x00001004, 0x00000000, 0x00000004, 0x00001000, 0x00001004, 0x10000000, 0x10000004, 0x10001000, 0x10001004, 0x10000000, 0x10000004, 0x10001000, 0x10001004, 0x00000020, 0x00000024, 0x00001020, 0x00001024, 0x00000020, 0x00000024, 0x00001020, 0x00001024, 0x10000020, 0x10000024, 0x10001020, 0x10001024, 0x10000020, 0x10000024, 0x10001020, 0x10001024, 0x00080000, 0x00080004, 0x00081000, 0x00081004, 0x00080000, 0x00080004, 0x00081000, 0x00081004, 0x10080000, 0x10080004, 0x10081000, 0x10081004, 0x10080000, 0x10080004, 0x10081000, 0x10081004, 0x00080020, 0x00080024, 0x00081020, 0x00081024, 0x00080020, 0x00080024, 0x00081020, 0x00081024, 0x10080020, 0x10080024, 0x10081020, 0x10081024, 0x10080020, 0x10080024, 0x10081020, 0x10081024, 0x20000000, 0x20000004, 0x20001000, 0x20001004, 0x20000000, 0x20000004, 0x20001000, 0x20001004, 0x30000000, 0x30000004, 0x30001000, 0x30001004, 0x30000000, 0x30000004, 0x30001000, 0x30001004, 0x20000020, 0x20000024, 0x20001020, 0x20001024, 0x20000020, 0x20000024, 0x20001020, 0x20001024, 0x30000020, 0x30000024, 0x30001020, 0x30001024, 0x30000020, 0x30000024, 0x30001020, 0x30001024, 0x20080000, 0x20080004, 0x20081000, 0x20081004, 0x20080000, 0x20080004, 0x20081000, 0x20081004, 0x30080000, 0x30080004, 0x30081000, 0x30081004, 0x30080000, 0x30080004, 0x30081000, 0x30081004, 0x20080020, 0x20080024, 0x20081020, 0x20081024, 0x20080020, 0x20080024, 0x20081020, 0x20081024, 0x30080020, 0x30080024, 0x30081020, 0x30081024, 0x30080020, 0x30080024, 0x30081020, 0x30081024, 0x00000002, 0x00000006, 0x00001002, 0x00001006, 0x00000002, 0x00000006, 0x00001002, 0x00001006, 0x10000002, 0x10000006, 0x10001002, 0x10001006, 0x10000002, 0x10000006, 0x10001002, 0x10001006, 0x00000022, 0x00000026, 0x00001022, 0x00001026, 0x00000022, 0x00000026, 0x00001022, 0x00001026, 0x10000022, 0x10000026, 0x10001022, 0x10001026, 0x10000022, 0x10000026, 0x10001022, 0x10001026, 0x00080002, 0x00080006, 0x00081002, 0x00081006, 0x00080002, 0x00080006, 0x00081002, 0x00081006, 0x10080002, 0x10080006, 0x10081002, 0x10081006, 0x10080002, 0x10080006, 0x10081002, 0x10081006, 0x00080022, 0x00080026, 0x00081022, 0x00081026, 0x00080022, 0x00080026, 0x00081022, 0x00081026, 0x10080022, 0x10080026, 0x10081022, 0x10081026, 0x10080022, 0x10080026, 0x10081022, 0x10081026, 0x20000002, 0x20000006, 0x20001002, 0x20001006, 0x20000002, 0x20000006, 0x20001002, 0x20001006, 0x30000002, 0x30000006, 0x30001002, 0x30001006, 0x30000002, 0x30000006, 0x30001002, 0x30001006, 0x20000022, 0x20000026, 0x20001022, 0x20001026, 0x20000022, 0x20000026, 0x20001022, 0x20001026, 0x30000022, 0x30000026, 0x30001022, 0x30001026, 0x30000022, 0x30000026, 0x30001022, 0x30001026, 0x20080002, 0x20080006, 0x20081002, 0x20081006, 0x20080002, 0x20080006, 0x20081002, 0x20081006, 0x30080002, 0x30080006, 0x30081002, 0x30081006, 0x30080002, 0x30080006, 0x30081002, 0x30081006, 0x20080022, 0x20080026, 0x20081022, 0x20081026, 0x20080022, 0x20080026, 0x20081022, 0x20081026, 0x30080022, 0x30080026, 0x30081022, 0x30081026, 0x30080022, 0x30080026, 0x30081022, 0x30081026 ]; static $pc2mapc4 = [ 0x00000000, 0x00100000, 0x00000008, 0x00100008, 0x00000200, 0x00100200, 0x00000208, 0x00100208, 0x00000000, 0x00100000, 0x00000008, 0x00100008, 0x00000200, 0x00100200, 0x00000208, 0x00100208, 0x04000000, 0x04100000, 0x04000008, 0x04100008, 0x04000200, 0x04100200, 0x04000208, 0x04100208, 0x04000000, 0x04100000, 0x04000008, 0x04100008, 0x04000200, 0x04100200, 0x04000208, 0x04100208, 0x00002000, 0x00102000, 0x00002008, 0x00102008, 0x00002200, 0x00102200, 0x00002208, 0x00102208, 0x00002000, 0x00102000, 0x00002008, 0x00102008, 0x00002200, 0x00102200, 0x00002208, 0x00102208, 0x04002000, 0x04102000, 0x04002008, 0x04102008, 0x04002200, 0x04102200, 0x04002208, 0x04102208, 0x04002000, 0x04102000, 0x04002008, 0x04102008, 0x04002200, 0x04102200, 0x04002208, 0x04102208, 0x00000000, 0x00100000, 0x00000008, 0x00100008, 0x00000200, 0x00100200, 0x00000208, 0x00100208, 0x00000000, 0x00100000, 0x00000008, 0x00100008, 0x00000200, 0x00100200, 0x00000208, 0x00100208, 0x04000000, 0x04100000, 0x04000008, 0x04100008, 0x04000200, 0x04100200, 0x04000208, 0x04100208, 0x04000000, 0x04100000, 0x04000008, 0x04100008, 0x04000200, 0x04100200, 0x04000208, 0x04100208, 0x00002000, 0x00102000, 0x00002008, 0x00102008, 0x00002200, 0x00102200, 0x00002208, 0x00102208, 0x00002000, 0x00102000, 0x00002008, 0x00102008, 0x00002200, 0x00102200, 0x00002208, 0x00102208, 0x04002000, 0x04102000, 0x04002008, 0x04102008, 0x04002200, 0x04102200, 0x04002208, 0x04102208, 0x04002000, 0x04102000, 0x04002008, 0x04102008, 0x04002200, 0x04102200, 0x04002208, 0x04102208, 0x00020000, 0x00120000, 0x00020008, 0x00120008, 0x00020200, 0x00120200, 0x00020208, 0x00120208, 0x00020000, 0x00120000, 0x00020008, 0x00120008, 0x00020200, 0x00120200, 0x00020208, 0x00120208, 0x04020000, 0x04120000, 0x04020008, 0x04120008, 0x04020200, 0x04120200, 0x04020208, 0x04120208, 0x04020000, 0x04120000, 0x04020008, 0x04120008, 0x04020200, 0x04120200, 0x04020208, 0x04120208, 0x00022000, 0x00122000, 0x00022008, 0x00122008, 0x00022200, 0x00122200, 0x00022208, 0x00122208, 0x00022000, 0x00122000, 0x00022008, 0x00122008, 0x00022200, 0x00122200, 0x00022208, 0x00122208, 0x04022000, 0x04122000, 0x04022008, 0x04122008, 0x04022200, 0x04122200, 0x04022208, 0x04122208, 0x04022000, 0x04122000, 0x04022008, 0x04122008, 0x04022200, 0x04122200, 0x04022208, 0x04122208, 0x00020000, 0x00120000, 0x00020008, 0x00120008, 0x00020200, 0x00120200, 0x00020208, 0x00120208, 0x00020000, 0x00120000, 0x00020008, 0x00120008, 0x00020200, 0x00120200, 0x00020208, 0x00120208, 0x04020000, 0x04120000, 0x04020008, 0x04120008, 0x04020200, 0x04120200, 0x04020208, 0x04120208, 0x04020000, 0x04120000, 0x04020008, 0x04120008, 0x04020200, 0x04120200, 0x04020208, 0x04120208, 0x00022000, 0x00122000, 0x00022008, 0x00122008, 0x00022200, 0x00122200, 0x00022208, 0x00122208, 0x00022000, 0x00122000, 0x00022008, 0x00122008, 0x00022200, 0x00122200, 0x00022208, 0x00122208, 0x04022000, 0x04122000, 0x04022008, 0x04122008, 0x04022200, 0x04122200, 0x04022208, 0x04122208, 0x04022000, 0x04122000, 0x04022008, 0x04122008, 0x04022200, 0x04122200, 0x04022208, 0x04122208 ]; static $pc2mapd1 = [ 0x00000000, 0x00000001, 0x08000000, 0x08000001, 0x00200000, 0x00200001, 0x08200000, 0x08200001, 0x00000002, 0x00000003, 0x08000002, 0x08000003, 0x00200002, 0x00200003, 0x08200002, 0x08200003 ]; static $pc2mapd2 = [ 0x00000000, 0x00100000, 0x00000800, 0x00100800, 0x00000000, 0x00100000, 0x00000800, 0x00100800, 0x04000000, 0x04100000, 0x04000800, 0x04100800, 0x04000000, 0x04100000, 0x04000800, 0x04100800, 0x00000004, 0x00100004, 0x00000804, 0x00100804, 0x00000004, 0x00100004, 0x00000804, 0x00100804, 0x04000004, 0x04100004, 0x04000804, 0x04100804, 0x04000004, 0x04100004, 0x04000804, 0x04100804, 0x00000000, 0x00100000, 0x00000800, 0x00100800, 0x00000000, 0x00100000, 0x00000800, 0x00100800, 0x04000000, 0x04100000, 0x04000800, 0x04100800, 0x04000000, 0x04100000, 0x04000800, 0x04100800, 0x00000004, 0x00100004, 0x00000804, 0x00100804, 0x00000004, 0x00100004, 0x00000804, 0x00100804, 0x04000004, 0x04100004, 0x04000804, 0x04100804, 0x04000004, 0x04100004, 0x04000804, 0x04100804, 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, 0x00000200, 0x00100200, 0x00000A00, 0x00100A00, 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, 0x04000200, 0x04100200, 0x04000A00, 0x04100A00, 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, 0x00000204, 0x00100204, 0x00000A04, 0x00100A04, 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, 0x04000204, 0x04100204, 0x04000A04, 0x04100A04, 0x00020000, 0x00120000, 0x00020800, 0x00120800, 0x00020000, 0x00120000, 0x00020800, 0x00120800, 0x04020000, 0x04120000, 0x04020800, 0x04120800, 0x04020000, 0x04120000, 0x04020800, 0x04120800, 0x00020004, 0x00120004, 0x00020804, 0x00120804, 0x00020004, 0x00120004, 0x00020804, 0x00120804, 0x04020004, 0x04120004, 0x04020804, 0x04120804, 0x04020004, 0x04120004, 0x04020804, 0x04120804, 0x00020000, 0x00120000, 0x00020800, 0x00120800, 0x00020000, 0x00120000, 0x00020800, 0x00120800, 0x04020000, 0x04120000, 0x04020800, 0x04120800, 0x04020000, 0x04120000, 0x04020800, 0x04120800, 0x00020004, 0x00120004, 0x00020804, 0x00120804, 0x00020004, 0x00120004, 0x00020804, 0x00120804, 0x04020004, 0x04120004, 0x04020804, 0x04120804, 0x04020004, 0x04120004, 0x04020804, 0x04120804, 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, 0x00020200, 0x00120200, 0x00020A00, 0x00120A00, 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, 0x04020200, 0x04120200, 0x04020A00, 0x04120A00, 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, 0x00020204, 0x00120204, 0x00020A04, 0x00120A04, 0x04020204, 0x04120204, 0x04020A04, 0x04120A04, 0x04020204, 0x04120204, 0x04020A04, 0x04120A04 ]; static $pc2mapd3 = [ 0x00000000, 0x00010000, 0x02000000, 0x02010000, 0x00000020, 0x00010020, 0x02000020, 0x02010020, 0x00040000, 0x00050000, 0x02040000, 0x02050000, 0x00040020, 0x00050020, 0x02040020, 0x02050020, 0x00002000, 0x00012000, 0x02002000, 0x02012000, 0x00002020, 0x00012020, 0x02002020, 0x02012020, 0x00042000, 0x00052000, 0x02042000, 0x02052000, 0x00042020, 0x00052020, 0x02042020, 0x02052020, 0x00000000, 0x00010000, 0x02000000, 0x02010000, 0x00000020, 0x00010020, 0x02000020, 0x02010020, 0x00040000, 0x00050000, 0x02040000, 0x02050000, 0x00040020, 0x00050020, 0x02040020, 0x02050020, 0x00002000, 0x00012000, 0x02002000, 0x02012000, 0x00002020, 0x00012020, 0x02002020, 0x02012020, 0x00042000, 0x00052000, 0x02042000, 0x02052000, 0x00042020, 0x00052020, 0x02042020, 0x02052020, 0x00000010, 0x00010010, 0x02000010, 0x02010010, 0x00000030, 0x00010030, 0x02000030, 0x02010030, 0x00040010, 0x00050010, 0x02040010, 0x02050010, 0x00040030, 0x00050030, 0x02040030, 0x02050030, 0x00002010, 0x00012010, 0x02002010, 0x02012010, 0x00002030, 0x00012030, 0x02002030, 0x02012030, 0x00042010, 0x00052010, 0x02042010, 0x02052010, 0x00042030, 0x00052030, 0x02042030, 0x02052030, 0x00000010, 0x00010010, 0x02000010, 0x02010010, 0x00000030, 0x00010030, 0x02000030, 0x02010030, 0x00040010, 0x00050010, 0x02040010, 0x02050010, 0x00040030, 0x00050030, 0x02040030, 0x02050030, 0x00002010, 0x00012010, 0x02002010, 0x02012010, 0x00002030, 0x00012030, 0x02002030, 0x02012030, 0x00042010, 0x00052010, 0x02042010, 0x02052010, 0x00042030, 0x00052030, 0x02042030, 0x02052030, 0x20000000, 0x20010000, 0x22000000, 0x22010000, 0x20000020, 0x20010020, 0x22000020, 0x22010020, 0x20040000, 0x20050000, 0x22040000, 0x22050000, 0x20040020, 0x20050020, 0x22040020, 0x22050020, 0x20002000, 0x20012000, 0x22002000, 0x22012000, 0x20002020, 0x20012020, 0x22002020, 0x22012020, 0x20042000, 0x20052000, 0x22042000, 0x22052000, 0x20042020, 0x20052020, 0x22042020, 0x22052020, 0x20000000, 0x20010000, 0x22000000, 0x22010000, 0x20000020, 0x20010020, 0x22000020, 0x22010020, 0x20040000, 0x20050000, 0x22040000, 0x22050000, 0x20040020, 0x20050020, 0x22040020, 0x22050020, 0x20002000, 0x20012000, 0x22002000, 0x22012000, 0x20002020, 0x20012020, 0x22002020, 0x22012020, 0x20042000, 0x20052000, 0x22042000, 0x22052000, 0x20042020, 0x20052020, 0x22042020, 0x22052020, 0x20000010, 0x20010010, 0x22000010, 0x22010010, 0x20000030, 0x20010030, 0x22000030, 0x22010030, 0x20040010, 0x20050010, 0x22040010, 0x22050010, 0x20040030, 0x20050030, 0x22040030, 0x22050030, 0x20002010, 0x20012010, 0x22002010, 0x22012010, 0x20002030, 0x20012030, 0x22002030, 0x22012030, 0x20042010, 0x20052010, 0x22042010, 0x22052010, 0x20042030, 0x20052030, 0x22042030, 0x22052030, 0x20000010, 0x20010010, 0x22000010, 0x22010010, 0x20000030, 0x20010030, 0x22000030, 0x22010030, 0x20040010, 0x20050010, 0x22040010, 0x22050010, 0x20040030, 0x20050030, 0x22040030, 0x22050030, 0x20002010, 0x20012010, 0x22002010, 0x22012010, 0x20002030, 0x20012030, 0x22002030, 0x22012030, 0x20042010, 0x20052010, 0x22042010, 0x22052010, 0x20042030, 0x20052030, 0x22042030, 0x22052030 ]; static $pc2mapd4 = [ 0x00000000, 0x00000400, 0x01000000, 0x01000400, 0x00000000, 0x00000400, 0x01000000, 0x01000400, 0x00000100, 0x00000500, 0x01000100, 0x01000500, 0x00000100, 0x00000500, 0x01000100, 0x01000500, 0x10000000, 0x10000400, 0x11000000, 0x11000400, 0x10000000, 0x10000400, 0x11000000, 0x11000400, 0x10000100, 0x10000500, 0x11000100, 0x11000500, 0x10000100, 0x10000500, 0x11000100, 0x11000500, 0x00080000, 0x00080400, 0x01080000, 0x01080400, 0x00080000, 0x00080400, 0x01080000, 0x01080400, 0x00080100, 0x00080500, 0x01080100, 0x01080500, 0x00080100, 0x00080500, 0x01080100, 0x01080500, 0x10080000, 0x10080400, 0x11080000, 0x11080400, 0x10080000, 0x10080400, 0x11080000, 0x11080400, 0x10080100, 0x10080500, 0x11080100, 0x11080500, 0x10080100, 0x10080500, 0x11080100, 0x11080500, 0x00000008, 0x00000408, 0x01000008, 0x01000408, 0x00000008, 0x00000408, 0x01000008, 0x01000408, 0x00000108, 0x00000508, 0x01000108, 0x01000508, 0x00000108, 0x00000508, 0x01000108, 0x01000508, 0x10000008, 0x10000408, 0x11000008, 0x11000408, 0x10000008, 0x10000408, 0x11000008, 0x11000408, 0x10000108, 0x10000508, 0x11000108, 0x11000508, 0x10000108, 0x10000508, 0x11000108, 0x11000508, 0x00080008, 0x00080408, 0x01080008, 0x01080408, 0x00080008, 0x00080408, 0x01080008, 0x01080408, 0x00080108, 0x00080508, 0x01080108, 0x01080508, 0x00080108, 0x00080508, 0x01080108, 0x01080508, 0x10080008, 0x10080408, 0x11080008, 0x11080408, 0x10080008, 0x10080408, 0x11080008, 0x11080408, 0x10080108, 0x10080508, 0x11080108, 0x11080508, 0x10080108, 0x10080508, 0x11080108, 0x11080508, 0x00001000, 0x00001400, 0x01001000, 0x01001400, 0x00001000, 0x00001400, 0x01001000, 0x01001400, 0x00001100, 0x00001500, 0x01001100, 0x01001500, 0x00001100, 0x00001500, 0x01001100, 0x01001500, 0x10001000, 0x10001400, 0x11001000, 0x11001400, 0x10001000, 0x10001400, 0x11001000, 0x11001400, 0x10001100, 0x10001500, 0x11001100, 0x11001500, 0x10001100, 0x10001500, 0x11001100, 0x11001500, 0x00081000, 0x00081400, 0x01081000, 0x01081400, 0x00081000, 0x00081400, 0x01081000, 0x01081400, 0x00081100, 0x00081500, 0x01081100, 0x01081500, 0x00081100, 0x00081500, 0x01081100, 0x01081500, 0x10081000, 0x10081400, 0x11081000, 0x11081400, 0x10081000, 0x10081400, 0x11081000, 0x11081400, 0x10081100, 0x10081500, 0x11081100, 0x11081500, 0x10081100, 0x10081500, 0x11081100, 0x11081500, 0x00001008, 0x00001408, 0x01001008, 0x01001408, 0x00001008, 0x00001408, 0x01001008, 0x01001408, 0x00001108, 0x00001508, 0x01001108, 0x01001508, 0x00001108, 0x00001508, 0x01001108, 0x01001508, 0x10001008, 0x10001408, 0x11001008, 0x11001408, 0x10001008, 0x10001408, 0x11001008, 0x11001408, 0x10001108, 0x10001508, 0x11001108, 0x11001508, 0x10001108, 0x10001508, 0x11001108, 0x11001508, 0x00081008, 0x00081408, 0x01081008, 0x01081408, 0x00081008, 0x00081408, 0x01081008, 0x01081408, 0x00081108, 0x00081508, 0x01081108, 0x01081508, 0x00081108, 0x00081508, 0x01081108, 0x01081508, 0x10081008, 0x10081408, 0x11081008, 0x11081408, 0x10081008, 0x10081408, 0x11081008, 0x11081408, 0x10081108, 0x10081508, 0x11081108, 0x11081508, 0x10081108, 0x10081508, 0x11081108, 0x11081508 ]; $keys = []; for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) { // pad the key and remove extra characters as appropriate. $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0"); // Perform the PC/1 transformation and compute C and D. $t = unpack('Nl/Nr', $key); list($l, $r) = [$t['l'], $t['r']]; $key = (self::$shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") | (self::$shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") | (self::$shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") | (self::$shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") | (self::$shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") | (self::$shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") | (self::$shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") | (self::$shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00"); $key = unpack('Nc/Nd', $key); $c = ( $key['c'] >> 4) & 0x0FFFFFFF; $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F); $keys[$des_round] = [ self::ENCRYPT => [], self::DECRYPT => array_fill(0, 32, 0) ]; for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) { $c <<= $shifts[$i]; $c = ($c | ($c >> 28)) & 0x0FFFFFFF; $d <<= $shifts[$i]; $d = ($d | ($d >> 28)) & 0x0FFFFFFF; // Perform the PC-2 transformation. $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] | $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF]; $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] | $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF]; // Reorder: odd bytes/even bytes. Push the result in key schedule. $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) | (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); $val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) | (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); $keys[$des_round][self::ENCRYPT][ ] = $val1; $keys[$des_round][self::DECRYPT][$ki - 1] = $val1; $keys[$des_round][self::ENCRYPT][ ] = $val2; $keys[$des_round][self::DECRYPT][$ki ] = $val2; } } switch ($this->des_rounds) { case 3: // 3DES keys $this->keys = [ self::ENCRYPT => array_merge( $keys[0][self::ENCRYPT], $keys[1][self::DECRYPT], $keys[2][self::ENCRYPT] ), self::DECRYPT => array_merge( $keys[2][self::DECRYPT], $keys[1][self::ENCRYPT], $keys[0][self::DECRYPT] ) ]; break; // case 1: // DES keys default: $this->keys = [ self::ENCRYPT => $keys[0][self::ENCRYPT], self::DECRYPT => $keys[0][self::DECRYPT] ]; } } /** * Setup the performance-optimized function for de/encrypt() * * @see \phpseclib\Crypt\Common\SymmetricKey::setupInlineCrypt() * @access private */ protected function setupInlineCrypt() { // Engine configuration for: // - DES ($des_rounds == 1) or // - 3DES ($des_rounds == 3) $des_rounds = $this->des_rounds; $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; if (!$sbox1) { $sbox1 = array_map("intval", self::$sbox1); $sbox2 = array_map("intval", self::$sbox2); $sbox3 = array_map("intval", self::$sbox3); $sbox4 = array_map("intval", self::$sbox4); $sbox5 = array_map("intval", self::$sbox5); $sbox6 = array_map("intval", self::$sbox6); $sbox7 = array_map("intval", self::$sbox7); $sbox8 = array_map("intval", self::$sbox8);' /* Merge $shuffle with $[inv]ipmap */ . ' for ($i = 0; $i < 256; ++$i) { $shuffleip[] = self::$shuffle[self::$ipmap[$i]]; $shuffleinvip[] = self::$shuffle[self::$invipmap[$i]]; } } '; $k = [ self::ENCRYPT => $this->keys[self::ENCRYPT], self::DECRYPT => $this->keys[self::DECRYPT] ]; $init_encrypt = ''; $init_decrypt = ''; // Creating code for en- and decryption. $crypt_block = []; foreach ([self::ENCRYPT, self::DECRYPT] as $c) { /* Do the initial IP permutation. */ $crypt_block[$c] = ' $in = unpack("N*", $in); $l = $in[1]; $r = $in[2]; $in = unpack("N*", ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01") ); ' . /* Extract L0 and R0 */ ' $l = $in[1]; $r = $in[2]; '; $l = '$l'; $r = '$r'; // Perform DES or 3DES. for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) { // Perform the 16 steps. for ($i = 0; $i < 16; ++$i) { // start of "the Feistel (F) function" - see the following URL: // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png // Merge key schedule. $crypt_block[$c].= ' $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . '; $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' . /* S-box indexing. */ $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^ $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . '; '; // end of "the Feistel (F) function" // swap L & R list($l, $r) = [$r, $l]; } list($l, $r) = [$r, $l]; } // Perform the inverse IP permutation. $crypt_block[$c].= '$in = ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") | ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") | ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") | ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") | ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") | ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") | ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") | ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01"); '; } // Creates the inline-crypt function $this->inline_crypt = $this->createInlineCryptFunction( [ 'init_crypt' => $init_crypt, 'init_encrypt' => $init_encrypt, 'init_decrypt' => $init_decrypt, 'encrypt_block' => $crypt_block[self::ENCRYPT], 'decrypt_block' => $crypt_block[self::DECRYPT] ] ); } } <?php /** * Pure-PHP implementation of RC2. * * Uses mcrypt, if available, and an internal implementation, otherwise. * * PHP version 5 * * Useful resources are as follows: * * - {@link http://tools.ietf.org/html/rfc2268} * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $rc2 = new \phpseclib\Crypt\RC2(); * * $rc2->setKey('abcdefgh'); * * $plaintext = str_repeat('a', 1024); * * echo $rc2->decrypt($rc2->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package RC2 * @author Patrick Monnerat <pm@datasphere.ch> * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\BlockCipher; use phpseclib\Exception\BadModeException; /** * Pure-PHP implementation of RC2. * * @package RC2 * @access public */ class RC2 extends BlockCipher { /** * Block Length of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::block_size * @var int * @access private */ protected $block_size = 8; /** * The Key * * @see \phpseclib\Crypt\Common\SymmetricKey::key * @see self::setKey() * @var string * @access private */ protected $key; /** * The Original (unpadded) Key * * @see \phpseclib\Crypt\Common\SymmetricKey::key * @see self::setKey() * @see self::encrypt() * @see self::decrypt() * @var string * @access private */ private $orig_key; /** * Don't truncate / null pad key * * @see \phpseclib\Crypt\Common\SymmetricKey::clearBuffers() * @var bool * @access private */ private $skip_key_adjustment = true; /** * Key Length (in bytes) * * @see \phpseclib\Crypt\RC2::setKeyLength() * @var int * @access private */ protected $key_length = 16; // = 128 bits /** * The mcrypt specific name of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @var string * @access private */ protected $cipher_name_mcrypt = 'rc2'; /** * Optimizing value while CFB-encrypting * * @see \phpseclib\Crypt\Common\SymmetricKey::cfb_init_len * @var int * @access private */ protected $cfb_init_len = 500; /** * The key length in bits. * * @see self::setKeyLength() * @see self::setKey() * @var int * @access private * @internal Should be in range [1..1024]. * @internal Changing this value after setting the key has no effect. */ private $default_key_length = 1024; /** * The key length in bits. * * @see self::isValidEnine() * @see self::setKey() * @var int * @access private * @internal Should be in range [1..1024]. */ private $current_key_length; /** * The Key Schedule * * @see self::setupKey() * @var array * @access private */ private $keys; /** * Key expansion randomization table. * Twice the same 256-value sequence to save a modulus in key expansion. * * @see self::setKey() * @var array * @access private */ private static $pitable = [ 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD, 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD ]; /** * Inverse key expansion randomization table. * * @see self::setKey() * @var array * @access private */ private static $invpitable = [ 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66, 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4, 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20, 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53, 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68, 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B, 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12, 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB, 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3, 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26, 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67, 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB, 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC, 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60, 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7, 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD, 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24, 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31, 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE, 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99, 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C, 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA, 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35, 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61, 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72, 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3, 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F, 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9, 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77, 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75, 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87, 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6 ]; /** * Default Constructor. * * @param int $mode * @access public * @throws \InvalidArgumentException if an invalid / unsupported mode is provided */ public function __construct($mode) { if ($mode == self::MODE_STREAM) { throw new BadModeException('Block ciphers cannot be ran in stream mode'); } parent::__construct($mode); } /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { switch ($engine) { case self::ENGINE_OPENSSL: if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) { return false; } self::$cipher_name_openssl_ecb = 'rc2-ecb'; $this->cipher_name_openssl = 'rc2-' . $this->openssl_translate_mode(); } return parent::isValidEngineHelper($engine); } /** * Sets the key length. * * Valid key lengths are 8 to 1024. * Calling this function after setting the key has no effect until the next * \phpseclib\Crypt\RC2::setKey() call. * * @access public * @param int $length in bits * @throws \LengthException if the key length isn't supported */ public function setKeyLength($length) { if ($length < 8 || $length > 1024) { throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported'); } $this->default_key_length = $this->current_key_length = $length; $this->explicit_key_length = $length >> 3; } /** * Returns the current key length * * @access public * @return int */ public function getKeyLength() { return $this->current_key_length; } /** * Sets the key. * * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg. * strlen($key) <= 128), however, we only use the first 128 bytes if $key * has more then 128 bytes in it, and set $key to a single null byte if * it is empty. * * @see \phpseclib\Crypt\Common\SymmetricKey::setKey() * @access public * @param string $key * @param int|boolean $t1 optional Effective key length in bits. * @throws \LengthException if the key length isn't supported */ public function setKey($key, $t1 = false) { $this->orig_key = $key; if ($t1 === false) { $t1 = $this->default_key_length; } if ($t1 < 1 || $t1 > 1024) { throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported'); } $this->current_key_length = $t1; if (strlen($key) < 1 || strlen($key) > 128) { throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes between 8 and 1024 bits, inclusive, are supported'); } $t = strlen($key); // The mcrypt RC2 implementation only supports effective key length // of 1024 bits. It is however possible to handle effective key // lengths in range 1..1024 by expanding the key and applying // inverse pitable mapping to the first byte before submitting it // to mcrypt. // Key expansion. $l = array_values(unpack('C*', $key)); $t8 = ($t1 + 7) >> 3; $tm = 0xFF >> (8 * $t8 - $t1); // Expand key. $pitable = self::$pitable; for ($i = $t; $i < 128; $i++) { $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]]; } $i = 128 - $t8; $l[$i] = $pitable[$l[$i] & $tm]; while ($i--) { $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]]; } // Prepare the key for mcrypt. $l[0] = self::$invpitable[$l[0]]; array_unshift($l, 'C*'); $this->key = call_user_func_array('pack', $l); $this->key_length = strlen($this->key); $this->changed = true; $this->setEngine(); } /** * Encrypts a message. * * Mostly a wrapper for \phpseclib\Crypt\Common\SymmetricKey::encrypt, with some additional OpenSSL handling code * * @see self::decrypt() * @access public * @param string $plaintext * @return string $ciphertext */ public function encrypt($plaintext) { if ($this->engine == self::ENGINE_OPENSSL) { $temp = $this->key; $this->key = $this->orig_key; $result = parent::encrypt($plaintext); $this->key = $temp; return $result; } return parent::encrypt($plaintext); } /** * Decrypts a message. * * Mostly a wrapper for \phpseclib\Crypt\Common\SymmetricKey::decrypt, with some additional OpenSSL handling code * * @see self::encrypt() * @access public * @param string $ciphertext * @return string $plaintext */ public function decrypt($ciphertext) { if ($this->engine == self::ENGINE_OPENSSL) { $temp = $this->key; $this->key = $this->orig_key; $result = parent::decrypt($ciphertext); $this->key = $temp; return $result; } return parent::decrypt($ciphertext); } /** * Encrypts a block * * @see \phpseclib\Crypt\Common\SymmetricKey::encryptBlock() * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @access private * @param string $in * @return string */ protected function encryptBlock($in) { list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); $keys = $this->keys; $limit = 20; $actions = [$limit => 44, 44 => 64]; $j = 0; for (;;) { // Mixing round. $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; $r0 |= $r0 >> 16; $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; $r1 |= $r1 >> 16; $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; $r2 |= $r2 >> 16; $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; $r3 |= $r3 >> 16; if ($j === $limit) { if ($limit === 64) { break; } // Mashing round. $r0 += $keys[$r3 & 0x3F]; $r1 += $keys[$r0 & 0x3F]; $r2 += $keys[$r1 & 0x3F]; $r3 += $keys[$r2 & 0x3F]; $limit = $actions[$limit]; } } return pack('vvvv', $r0, $r1, $r2, $r3); } /** * Decrypts a block * * @see \phpseclib\Crypt\Common\SymmetricKey::decryptBlock() * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() * @access private * @param string $in * @return string */ protected function decryptBlock($in) { list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); $keys = $this->keys; $limit = 44; $actions = [$limit => 20, 20 => 0]; $j = 64; for (;;) { // R-mixing round. $r3 = ($r3 | ($r3 << 16)) >> 5; $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; $r2 = ($r2 | ($r2 << 16)) >> 3; $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; $r1 = ($r1 | ($r1 << 16)) >> 2; $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; $r0 = ($r0 | ($r0 << 16)) >> 1; $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF; if ($j === $limit) { if ($limit === 0) { break; } // R-mashing round. $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF; $limit = $actions[$limit]; } } return pack('vvvv', $r0, $r1, $r2, $r3); } /** * Creates the key schedule * * @see \phpseclib\Crypt\Common\SymmetricKey::setupKey() * @access private */ protected function setupKey() { if (!isset($this->key)) { $this->setKey(''); } // Key has already been expanded in \phpseclib\Crypt\RC2::setKey(): // Only the first value must be altered. $l = unpack('Ca/Cb/v*', $this->key); array_unshift($l, self::$pitable[$l['a']] | ($l['b'] << 8)); unset($l['a']); unset($l['b']); $this->keys = $l; } /** * Setup the performance-optimized function for de/encrypt() * * @see \phpseclib\Crypt\Common\SymmetricKey::setupInlineCrypt() * @access private */ protected function setupInlineCrypt() { // Init code for both, encrypt and decrypt. $init_crypt = '$keys = $this->keys;'; $keys = $this->keys; // $in is the current 8 bytes block which has to be en/decrypt $encrypt_block = $decrypt_block = ' $in = unpack("v4", $in); $r0 = $in[1]; $r1 = $in[2]; $r2 = $in[3]; $r3 = $in[4]; '; // Create code for encryption. $limit = 20; $actions = [$limit => 44, 44 => 64]; $j = 0; for (;;) { // Mixing round. $encrypt_block .= ' $r0 = (($r0 + ' . $keys[$j++] . ' + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; $r0 |= $r0 >> 16; $r1 = (($r1 + ' . $keys[$j++] . ' + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; $r1 |= $r1 >> 16; $r2 = (($r2 + ' . $keys[$j++] . ' + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; $r2 |= $r2 >> 16; $r3 = (($r3 + ' . $keys[$j++] . ' + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; $r3 |= $r3 >> 16;'; if ($j === $limit) { if ($limit === 64) { break; } // Mashing round. $encrypt_block .= ' $r0 += $keys[$r3 & 0x3F]; $r1 += $keys[$r0 & 0x3F]; $r2 += $keys[$r1 & 0x3F]; $r3 += $keys[$r2 & 0x3F];'; $limit = $actions[$limit]; } } $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; // Create code for decryption. $limit = 44; $actions = [$limit => 20, 20 => 0]; $j = 64; for (;;) { // R-mixing round. $decrypt_block .= ' $r3 = ($r3 | ($r3 << 16)) >> 5; $r3 = ($r3 - ' . $keys[--$j] . ' - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; $r2 = ($r2 | ($r2 << 16)) >> 3; $r2 = ($r2 - ' . $keys[--$j] . ' - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; $r1 = ($r1 | ($r1 << 16)) >> 2; $r1 = ($r1 - ' . $keys[--$j] . ' - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; $r0 = ($r0 | ($r0 << 16)) >> 1; $r0 = ($r0 - ' . $keys[--$j] . ' - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;'; if ($j === $limit) { if ($limit === 0) { break; } // R-mashing round. $decrypt_block .= ' $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;'; $limit = $actions[$limit]; } } $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; // Creates the inline-crypt function $this->inline_crypt = $this->createInlineCryptFunction( [ 'init_crypt' => $init_crypt, 'encrypt_block' => $encrypt_block, 'decrypt_block' => $decrypt_block ] ); } } <?php /** * Random Number Generator * * PHP version 5 * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * echo bin2hex(\phpseclib\Crypt\Random::string(8)); * ?> * </code> * * @category Crypt * @package Random * @author Jim Wigginton <terrafrost@php.net> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; /** * Pure-PHP Random Number Generator * * @package Random * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Random { /** * Generate a random string. * * Although microoptimizations are generally discouraged as they impair readability this function is ripe with * microoptimizations because this function has the potential of being called a huge number of times. * eg. for RSA key generation. * * @param int $length * @throws \RuntimeException if a symmetric cipher is needed but not loaded * @return string */ public static function string($length) { if (!$length) { return ''; } try { return \random_bytes($length); } catch (\Exception $e) { // random_compat will throw an Exception, which in PHP 5 does not implement Throwable } catch (\Throwable $e) { // If a sufficient source of randomness is unavailable, random_bytes() will throw an // object that implements the Throwable interface (Exception, TypeError, Error). // We don't actually need to do anything here. The string() method should just continue // as normal. Note, however, that if we don't have a sufficient source of randomness for // random_bytes(), most of the other calls here will fail too, so we'll end up using // the PHP implementation. } // at this point we have no choice but to use a pure-PHP CSPRNG // cascade entropy across multiple PHP instances by fixing the session and collecting all // environmental variables, including the previous session data and the current session // data. // // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively) // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but // PHP isn't low level to be able to use those as sources and on a web server there's not likely // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use // however, a ton of people visiting the website. obviously you don't want to base your seeding // solely on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled // by the user and (2) this isn't just looking at the data sent by the current user - it's based // on the data sent by all users. one user requests the page and a hash of their info is saved. // another user visits the page and the serialization of their data is utilized along with the // server environment stuff and a hash of the previous http request data (which itself utilizes // a hash of the session data before that). certainly an attacker should be assumed to have // full control over his own http requests. he, however, is not going to have control over // everyone's http requests. static $crypto = false, $v; if ($crypto === false) { // save old session data $old_session_id = session_id(); $old_use_cookies = ini_get('session.use_cookies'); $old_session_cache_limiter = session_cache_limiter(); $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; if ($old_session_id != '') { session_write_close(); } session_id(1); ini_set('session.use_cookies', 0); session_cache_limiter(''); session_start(); $v = (isset($_SERVER) ? self::safe_serialize($_SERVER) : '') . (isset($_POST) ? self::safe_serialize($_POST) : '') . (isset($_GET) ? self::safe_serialize($_GET) : '') . (isset($_COOKIE) ? self::safe_serialize($_COOKIE) : '') . self::safe_serialize($GLOBALS) . self::safe_serialize($_SESSION) . self::safe_serialize($_OLD_SESSION); $v = $seed = $_SESSION['seed'] = sha1($v, true); if (!isset($_SESSION['count'])) { $_SESSION['count'] = 0; } $_SESSION['count']++; session_write_close(); // restore old session data if ($old_session_id != '') { session_id($old_session_id); session_start(); ini_set('session.use_cookies', $old_use_cookies); session_cache_limiter($old_session_cache_limiter); } else { if ($_OLD_SESSION !== false) { $_SESSION = $_OLD_SESSION; unset($_OLD_SESSION); } else { unset($_SESSION); } } // in SSH2 a shared secret and an exchange hash are generated through the key exchange process. // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the // original hash and the current hash. we'll be emulating that. for more info see the following URL: // // http://tools.ietf.org/html/rfc4253#section-7.2 // // see the is_string($crypto) part for an example of how to expand the keys $key = sha1($seed . 'A', true); $iv = sha1($seed . 'C', true); // ciphers are used as per the nist.gov link below. also, see this link: // // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives switch (true) { case class_exists('\phpseclib\Crypt\AES'): $crypto = new AES('ctr'); break; case class_exists('\phpseclib\Crypt\Twofish'): $crypto = new Twofish('ctr'); break; case class_exists('\phpseclib\Crypt\Blowfish'): $crypto = new Blowfish('ctr'); break; case class_exists('\phpseclib\Crypt\TripleDES'): $crypto = new TripleDES('ctr'); break; case class_exists('\phpseclib\Crypt\DES'): $crypto = new DES('ctr'); break; case class_exists('\phpseclib\Crypt\RC4'): $crypto = new RC4(); break; default: throw new \RuntimeException(__CLASS__ . ' requires at least one symmetric cipher be loaded'); } $crypto->setKey(substr($key, 0, $crypto->getKeyLength() >> 3)); $crypto->setIV(substr($iv, 0, $crypto->getBlockLength() >> 3)); $crypto->enableContinuousBuffer(); } //return $crypto->encrypt(str_repeat("\0", $length)); // the following is based off of ANSI X9.31: // // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf // // OpenSSL uses that same standard for it's random numbers: // // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c // (do a search for "ANS X9.31 A.2.4") $result = ''; while (strlen($result) < $length) { $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21 $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20 $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20 $result.= $r; } return substr($result, 0, $length); } /** * Safely serialize variables * * If a class has a private __sleep() it'll emit a warning * @return mixed * @param mixed $arr */ private static function safe_serialize(&$arr) { if (is_object($arr)) { return ''; } if (!is_array($arr)) { return serialize($arr); } // prevent circular array recursion if (isset($arr['__phpseclib_marker'])) { return ''; } $safearr = []; $arr['__phpseclib_marker'] = true; foreach (array_keys($arr) as $key) { // do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage if ($key !== '__phpseclib_marker') { $safearr[$key] = self::safe_serialize($arr[$key]); } } unset($arr['__phpseclib_marker']); return serialize($safearr); } } <?php /** * Fingerprint Trait for Public Keys * * PHP version 5 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; use phpseclib\Crypt\Hash; /** * Fingerprint Trait for Private Keys * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ trait Fingerprint { /** * Returns the public key's fingerprint * * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is * no public key currently loaded, false is returned. * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716) * * @access public * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned * for invalid values. * @return mixed */ public function getFingerprint($algorithm = 'md5') { $type = self::validatePlugin('Keys', 'OpenSSH', 'savePublicKey'); if ($type === false) { return false; } $key = $this->toString('OpenSSH', ['binary' => true]); if ($key === false) { return false; } switch ($algorithm) { case 'sha256': $hash = new Hash('sha256'); $base = base64_encode($hash->hash($key)); return substr($base, 0, strlen($base) - 1); case 'md5': return substr(chunk_split(md5($key), 2, ':'), 0, -1); default: return false; } } }<?php /** * Password Protected Trait for Private Keys * * PHP version 5 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; /** * Password Protected Trait for Private Keys * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ trait PasswordProtected { /** * Password * * @var string|bool */ private $password = false; /** * Sets the password * * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false. * Or rather, pass in $password such that empty($password) && !is_string($password) is true. * * @see self::createKey() * @see self::load() * @access public * @param string|boolean $password */ public function withPassword($password = false) { $new = clone $this; $new->password = $password; return $new; } }<?php /** * PrivateKey interface * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; /** * PrivateKey interface * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ interface PrivateKey { public function sign($message); //public function decrypt($ciphertext); public function getPublicKey(); public function toString($type, array $options = []); public function withPassword($string); } <?php /** * Base Class for all \phpseclib\Crypt\* cipher classes * * PHP version 5 * * Internally for phpseclib developers: * If you plan to add a new cipher class, please note following rules: * * - The new \phpseclib\Crypt\* cipher class should extend \phpseclib\Crypt\Common\SymmetricKey * * - Following methods are then required to be overridden/overloaded: * * - encryptBlock() * * - decryptBlock() * * - setupKey() * * - All other methods are optional to be overridden/overloaded * * - Look at the source code of the current ciphers how they extend \phpseclib\Crypt\Common\SymmetricKey * and take one of them as a start up for the new cipher class. * * - Please read all the other comments/notes/hints here also for each class var/method * * @category Crypt * @package Base * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Hash; use phpseclib\Exception\BadDecryptionException; use phpseclib\Exception\BadModeException; use phpseclib\Exception\InconsistentSetupException; use phpseclib\Exception\InsufficientSetupException; use phpseclib\Exception\UnsupportedAlgorithmException; use phpseclib\Math\BigInteger; use phpseclib\Math\BinaryField; use phpseclib\Math\PrimeField; /** * Base Class for all \phpseclib\Crypt\* cipher classes * * @package Base * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> */ abstract class SymmetricKey { /**#@+ * @access public * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() */ /** * Encrypt / decrypt using the Counter mode. * * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 */ const MODE_CTR = -1; /** * Encrypt / decrypt using the Electronic Code Book mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 */ const MODE_ECB = 1; /** * Encrypt / decrypt using the Code Book Chaining mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 */ const MODE_CBC = 2; /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 */ const MODE_CFB = 3; /** * Encrypt / decrypt using the Cipher Feedback mode (8bit) */ const MODE_CFB8 = 38; /** * Encrypt / decrypt using the Output Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 */ const MODE_OFB = 4; /** * Encrypt / decrypt using Galois/Counter mode. * * @link https://en.wikipedia.org/wiki/Galois/Counter_Mode */ const MODE_GCM = 5; /** * Encrypt / decrypt using streaming mode. */ const MODE_STREAM = 6; /** * Encrypt / decrypt using the Infinite Garble Extension mode. */ const MODE_IGE = 7; /**#@-*/ /** * Mode Map * * @access private * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() */ const MODE_MAP = [ 'ctr' => self::MODE_CTR, 'ecb' => self::MODE_ECB, 'cbc' => self::MODE_CBC, 'cfb' => self::MODE_CFB, 'cfb8' => self::MODE_CFB8, 'ofb' => self::MODE_OFB, 'ige' => self::MODE_IGE, 'gcm' => self::MODE_GCM, 'stream' => self::MODE_STREAM, ]; /**#@+ * @access private * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() */ /** * Base value for the internal implementation $engine switch */ const ENGINE_INTERNAL = 1; /** * Base value for the eval() implementation $engine switch */ const ENGINE_EVAL = 2; /** * Base value for the mcrypt implementation $engine switch */ const ENGINE_MCRYPT = 3; /** * Base value for the openssl implementation $engine switch */ const ENGINE_OPENSSL = 4; /** * Base value for the libsodium implementation $engine switch */ const ENGINE_LIBSODIUM = 5; /** * Base value for the openssl / gcm implementation $engine switch */ const ENGINE_OPENSSL_GCM = 6; /**#@-*/ /** * Engine Reverse Map * * @access private * @see \phpseclib\Crypt\Common\SymmetricKey::getEngine() */ const ENGINE_MAP = [ self::ENGINE_INTERNAL => 'PHP', self::ENGINE_EVAL => 'Eval', self::ENGINE_MCRYPT => 'mcrypt', self::ENGINE_OPENSSL => 'OpenSSL', self::ENGINE_LIBSODIUM => 'libsodium', self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)', ]; /** * The Encryption Mode * * @see self::__construct() * @var int * @access private */ protected $mode; /** * The Block Length of the block cipher * * @var int * @access private */ protected $block_size = 16; /** * The IV length multiplier of the block cipher * * @var int * @access private */ protected $iv_length_multiplier = 1; /** * The Key * * @see self::setKey() * @var string * @access private */ protected $key = false; /** * The Initialization Vector * * @see self::setIV() * @var string * @access private */ private $iv = false; /** * A "sliding" Initialization Vector * * @see self::enableContinuousBuffer() * @see self::clearBuffers() * @var string * @access private */ protected $encryptIV; /** * A "sliding" Initialization Vector * * @see self::enableContinuousBuffer() * @see self::clearBuffers() * @var string * @access private */ protected $decryptIV; /** * Continuous Buffer status * * @see self::enableContinuousBuffer() * @var bool * @access private */ protected $continuousBuffer = false; /** * Encryption buffer for IGE, CTR, OFB and CFB modes * * @see self::encrypt() * @see self::clearBuffers() * @var array * @access private */ private $enbuffer; /** * Decryption buffer for CTR, OFB and CFB modes * * @see self::decrypt() * @see self::clearBuffers() * @var array * @access private */ private $debuffer; /** * mcrypt resource for encryption * * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. * * @see self::encrypt() * @var resource * @access private */ private $enmcrypt; /** * mcrypt resource for decryption * * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. * * @see self::decrypt() * @var resource * @access private */ private $demcrypt; /** * Does the enmcrypt resource need to be (re)initialized? * * @see \phpseclib\Crypt\Twofish::setKey() * @see \phpseclib\Crypt\Twofish::setIV() * @var bool * @access private */ private $enchanged = true; /** * Does the demcrypt resource need to be (re)initialized? * * @see \phpseclib\Crypt\Twofish::setKey() * @see \phpseclib\Crypt\Twofish::setIV() * @var bool * @access private */ private $dechanged = true; /** * mcrypt resource for CFB mode * * mcrypt's CFB mode, in (and only in) buffered context, * is broken, so phpseclib implements the CFB mode by it self, * even when the mcrypt php extension is available. * * In order to do the CFB-mode work (fast) phpseclib * use a separate ECB-mode mcrypt resource. * * @link http://phpseclib.sourceforge.net/cfb-demo.phps * @see self::encrypt() * @see self::decrypt() * @see self::setupMcrypt() * @var resource * @access private */ private $ecb; /** * Optimizing value while CFB-encrypting * * Only relevant if $continuousBuffer enabled * and $engine == self::ENGINE_MCRYPT * * It's faster to re-init $enmcrypt if * $buffer bytes > $cfb_init_len than * using the $ecb resource furthermore. * * This value depends of the chosen cipher * and the time it would be needed for it's * initialization [by mcrypt_generic_init()] * which, typically, depends on the complexity * on its internaly Key-expanding algorithm. * * @see self::encrypt() * @var int * @access private */ protected $cfb_init_len = 600; /** * Does internal cipher state need to be (re)initialized? * * @see self::setKey() * @see self::setIV() * @see self::disableContinuousBuffer() * @var bool * @access private */ protected $changed = true; /** * Padding status * * @see self::enablePadding() * @var bool * @access private */ private $padding = true; /** * Is the mode one that is paddable? * * @see self::__construct() * @var bool * @access private */ private $paddable = false; /** * Holds which crypt engine internaly should be use, * which will be determined automatically on __construct() * * Currently available $engines are: * - self::ENGINE_LIBSODIUM (very fast, php-extension: libsodium, extension_loaded('libsodium') required) * - self::ENGINE_OPENSSL_GCM (very fast, php-extension: openssl, extension_loaded('openssl') required) * - self::ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required) * - self::ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required) * - self::ENGINE_EVAL (medium, pure php-engine, no php-extension required) * - self::ENGINE_INTERNAL (slower, pure php-engine, no php-extension required) * * @see self::setEngine() * @see self::encrypt() * @see self::decrypt() * @var int * @access private */ protected $engine; /** * Holds the preferred crypt engine * * @see self::setEngine() * @see self::setPreferredEngine() * @var int * @access private */ private $preferredEngine; /** * The mcrypt specific name of the cipher * * Only used if $engine == self::ENGINE_MCRYPT * * @link http://www.php.net/mcrypt_module_open * @link http://www.php.net/mcrypt_list_algorithms * @see self::setupMcrypt() * @var string * @access private */ protected $cipher_name_mcrypt; /** * The openssl specific name of the cipher * * Only used if $engine == self::ENGINE_OPENSSL * * @link http://www.php.net/openssl-get-cipher-methods * @var string * @access private */ protected $cipher_name_openssl; /** * The openssl specific name of the cipher in ECB mode * * If OpenSSL does not support the mode we're trying to use (CTR) * it can still be emulated with ECB mode. * * @link http://www.php.net/openssl-get-cipher-methods * @var string * @access private */ protected static $cipher_name_openssl_ecb; /** * The default salt used by setPassword() * * @see self::setPassword() * @var string * @access private */ private $password_default_salt = 'phpseclib/salt'; /** * The name of the performance-optimized callback function * * Used by encrypt() / decrypt() * only if $engine == self::ENGINE_INTERNAL * * @see self::encrypt() * @see self::decrypt() * @see self::setupInlineCrypt() * @var Callback * @access private */ protected $inline_crypt; /** * If OpenSSL can be used in ECB but not in CTR we can emulate CTR * * @see self::openssl_ctr_process() * @var bool * @access private */ private $openssl_emulate_ctr = false; /** * Don't truncate / null pad key * * @see self::clearBuffers() * @var bool * @access private */ private $skip_key_adjustment = false; /** * Has the key length explicitly been set or should it be derived from the key, itself? * * @see self::setKeyLength() * @var bool * @access private */ protected $explicit_key_length = false; /** * Hash subkey for GHASH * * @see self::setupGCM() * @see self::ghash() * @var BinaryField\Integer * @access private */ private $h; /** * Additional authenticated data * * @var string * @access private */ protected $aad = ''; /** * Authentication Tag produced after a round of encryption * * @var string * @access private */ protected $newtag = false; /** * Authentication Tag to be verified during decryption * * @var string * @access private */ protected $oldtag = false; /** * GCM Binary Field * * @see self::__construct() * @see self::ghash() * @var BinaryField * @access private */ private static $gcmField; /** * Poly1305 Prime Field * * @see self::enablePoly1305() * @see self::poly1305() * @var PrimeField * @access private */ private static $poly1305Field; /** * Poly1305 Key * * @see self::setPoly1305Key() * @see self::poly1305() * @var string * @access private */ protected $poly1305Key; /** * Poly1305 Flag * * @see self::setPoly1305Key() * @see self::enablePoly1305() * @var boolean * @access private */ protected $usePoly1305 = false; /** * The Original Initialization Vector * * GCM uses the nonce to build the IV but we want to be able to distinguish between nonce-derived * IV's and user-set IV's * * @see self::setIV() * @var string * @access private */ private $origIV = false; /** * Nonce * * Only used with GCM. We could re-use setIV() but nonce's can be of a different length and * toggling between GCM and other modes could be more complicated if we re-used setIV() * * @see self::setNonce() * @var string * @access private */ protected $nonce = false; /** * Default Constructor. * * $mode could be: * * - ecb * * - cbc * * - ctr * * - cfb * * - cfb8 * * - ofb * * - ige * * - gcm * * @param string $mode * @access public * @throws BadModeException if an invalid / unsupported mode is provided */ public function __construct($mode) { $mode = strtolower($mode); // necessary because of 5.6 compatibility; we can't do isset(self::MODE_MAP[$mode]) in 5.6 $map = self::MODE_MAP; if (!isset($map[$mode])) { throw new BadModeException('No valid mode has been specified'); } $mode = self::MODE_MAP[$mode]; // $mode dependent settings switch ($mode) { case self::MODE_ECB: case self::MODE_CBC: $this->paddable = true; break; case self::MODE_IGE: $this->iv_length_multiplier = 2; case self::MODE_CTR: case self::MODE_CFB: case self::MODE_CFB8: case self::MODE_OFB: case self::MODE_STREAM: $this->paddable = false; break; case self::MODE_GCM: if ($this->block_size != 16) { throw new BadModeException('GCM is only valid for block ciphers with a block size of 128 bits'); } if (!isset(self::$gcmField)) { self::$gcmField = new BinaryField(128, 7, 2, 1, 0); } $this->paddable = false; break; default: throw new BadModeException('No valid mode has been specified'); } $this->mode = $mode; } /** * Sets the initialization vector. * * setIV() is not required when ecb or gcm modes are being used. * * @access public * @param string $iv * @throws \LengthException if the IV length isn't equal to the block size * @throws \BadMethodCallException if an IV is provided when one shouldn't be * @internal Can be overwritten by a sub class, but does not have to be */ public function setIV($iv) { if ($this->mode == self::MODE_ECB) { throw new \BadMethodCallException('This mode does not require an IV.'); } if ($this->mode == self::MODE_GCM) { throw new \BadMethodCallException('Use setNonce instead'); } if (!$this->usesIV()) { throw new \BadMethodCallException('This algorithm does not use an IV.'); } if (strlen($iv) != $this->block_size * $this->iv_length_multiplier) { throw new \LengthException('Received initialization vector of size '.strlen($iv).', but size '.($this->block_size * $this->iv_length_multiplier).' is required'); } $this->iv = $this->origIV = $iv; $this->changed = true; } /** * Enables Poly1305 mode. * * Once enabled Poly1305 cannot be disabled. * * @access public * @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode */ public function enablePoly1305() { if ($this->mode == self::MODE_GCM) { throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode'); } $this->usePoly1305 = true; } /** * Enables Poly1305 mode. * * Once enabled Poly1305 cannot be disabled. If $key is not passed then an attempt to call createPoly1305Key * will be made. * * @access public * @param string $key optional * @throws \LengthException if the key isn't long enough * @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode */ public function setPoly1305Key($key = null) { if ($this->mode == self::MODE_GCM) { throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode'); } if (!is_string($key) || strlen($key) != 32) { throw new \LengthException('The Poly1305 key must be 32 bytes long (256 bits)'); } if (!isset(self::$poly1305Field)) { // 2^130-5 self::$poly1305Field = new PrimeField(new BigInteger('3fffffffffffffffffffffffffffffffb', 16)); } $this->poly1305Key = $key; $this->usePoly1305 = true; } /** * Sets the nonce. * * setNonce() is only required when gcm is used * * @access public * @param string $nonce * @throws \BadMethodCallException if an nonce is provided when one shouldn't be */ public function setNonce($nonce) { if ($this->mode != self::MODE_GCM) { throw new \BadMethodCallException('Nonces are only used in GCM mode.'); } $this->nonce = $nonce; $this->changed = true; $this->setEngine(); } /** * Sets additional authenticated data * * setAAD() is only used by gcm or in poly1305 mode * * @access public * @param string $aad * @throws \BadMethodCallException if mode isn't GCM or if poly1305 isn't being utilized */ public function setAAD($aad) { if ($this->mode != self::MODE_GCM && !$this->usePoly1305) { throw new \BadMethodCallException('Additional authenticated data is only utilized in GCM mode or with Poly1305'); } $this->aad = $aad; } /** * Returns whether or not the algorithm uses an IV * * @access public * @return bool */ public function usesIV() { return $this->mode != self::MODE_GCM; } /** * Returns whether or not the algorithm uses a nonce * * @access public * @return bool */ public function usesNonce() { return $this->mode == self::MODE_GCM; } /** * Returns the current key length in bits * * @access public * @return int */ public function getKeyLength() { return $this->key_length << 3; } /** * Returns the current block length in bits * * @access public * @return int */ public function getBlockLength() { return $this->block_size << 3; } /** * Returns the current block length in bytes * * @access public * @return int */ public function getBlockLengthInBytes() { return $this->block_size; } /** * Sets the key length. * * Keys with explicitly set lengths need to be treated accordingly * * @access public * @param int $length */ public function setKeyLength($length) { $this->explicit_key_length = $length >> 3; if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) { $this->key = false; throw new InconsistentSetupException('Key has already been set and is not '.$this->explicit_key_length.' bytes long'); } } /** * Sets the key. * * The min/max length(s) of the key depends on the cipher which is used. * If the key not fits the length(s) of the cipher it will paded with null bytes * up to the closest valid key length. If the key is more than max length, * we trim the excess bits. * * If the key is not explicitly set, it'll be assumed to be all null bytes. * * @access public * @param string $key * @internal Could, but not must, extend by the child Crypt_* class */ public function setKey($key) { if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) { throw new InconsistentSetupException('Key length has already been set to '.$this->explicit_key_length.' bytes and this key is '.strlen($key).' bytes'); } $this->key = $key; $this->key_length = strlen($key); $this->changed = true; $this->setEngine(); } /** * Sets the password. * * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1: * $hash, $salt, $count, $dkLen * * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php * * @see Crypt/Hash.php * @param string $password * @param string $method * @param $func_args[] * @throws \LengthException if pbkdf1 is being used and the derived key length exceeds the hash length * @return bool * @access public * @internal Could, but not must, extend by the child Crypt_* class */ public function setPassword($password, $method = 'pbkdf2',...$func_args) { $key = ''; $method = strtolower($method); switch ($method) { case 'pkcs12': // from https://tools.ietf.org/html/rfc7292#appendix-B.2 case 'pbkdf1': case 'pbkdf2': // Hash function $hash = isset($func_args[0]) ? strtolower($func_args[0]) : 'sha1'; $hashObj = new Hash(); $hashObj->setHash($hash); // WPA and WPA2 use the SSID as the salt $salt = isset($func_args[1]) ? $func_args[1] : $this->password_default_salt; // RFC2898#section-4.2 uses 1,000 iterations by default // WPA and WPA2 use 4,096. $count = isset($func_args[2]) ? $func_args[2] : 1000; // Keylength if (isset($func_args[3])) { if ($func_args[3] <= 0) { throw new \LengthException('Derived key length cannot be longer 0 or less'); } $dkLen = $func_args[3]; } else { $key_length = $this->explicit_key_length !== false ? $this->explicit_key_length : $this->key_length; $dkLen = $method == 'pbkdf1' ? 2 * $key_length : $key_length; } switch (true) { case $method == 'pkcs12': /* In this specification, however, all passwords are created from BMPStrings with a NULL terminator. This means that each character in the original BMPString is encoded in 2 bytes in big-endian format (most-significant byte first). There are no Unicode byte order marks. The 2 bytes produced from the last character in the BMPString are followed by 2 additional bytes with the value 0x00. -- https://tools.ietf.org/html/rfc7292#appendix-B.1 */ $password = "\0".chunk_split($password, 1, "\0")."\0"; /* This standard specifies 3 different values for the ID byte mentioned above: 1. If ID=1, then the pseudorandom bits being produced are to be used as key material for performing encryption or decryption. 2. If ID=2, then the pseudorandom bits being produced are to be used as an IV (Initial Value) for encryption or decryption. 3. If ID=3, then the pseudorandom bits being produced are to be used as an integrity key for MACing. */ // Construct a string, D (the "diversifier"), by concatenating v/8 // copies of ID. $blockLength = $hashObj->getBlockLengthInBytes(); $d1 = str_repeat(chr(1), $blockLength); $d2 = str_repeat(chr(2), $blockLength); $s = ''; if (strlen($salt)) { while (strlen($s) < $blockLength) { $s .= $salt; } } $s = substr($s, 0, $blockLength); $p = ''; if (strlen($password)) { while (strlen($p) < $blockLength) { $p .= $password; } } $p = substr($p, 0, $blockLength); $i = $s.$p; $this->setKey(self::pkcs12helper($dkLen, $hashObj, $i, $d1, $count)); if ($this->usesIV()) { $this->setIV(self::pkcs12helper($this->block_size, $hashObj, $i, $d2, $count)); } return true; case $method == 'pbkdf1': if ($dkLen > $hashObj->getLengthInBytes()) { throw new \LengthException('Derived key length cannot be longer than the hash length'); } $t = $password.$salt; for ($i = 0; $i < $count; ++$i) { $t = $hashObj->hash($t); } $key = substr($t, 0, $dkLen); $this->setKey(substr($key, 0, $dkLen >> 1)); if ($this->usesIV()) { $this->setIV(substr($key, $dkLen >> 1)); } return true; case !in_array($hash, hash_algos()): $i = 1; $hashObj->setKey($password); while (strlen($key) < $dkLen) { $f = $u = $hashObj->hash($salt.pack('N', $i++)); for ($j = 2; $j <= $count; ++$j) { $u = $hashObj->hash($u); $f ^= $u; } $key .= $f; } $key = substr($key, 0, $dkLen); break; default: $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true); } break; default: throw new UnsupportedAlgorithmException($method.' is not a supported password hashing method'); } $this->setKey($key); return true; } /** * PKCS#12 KDF Helper Function * * As discussed here: * * {@link https://tools.ietf.org/html/rfc7292#appendix-B} * * @see self::setPassword() * @access private * @param int $n * @param \phpseclib\Crypt\Hash $hashObj * @param string $i * @param string $d * @param int $count * @return string $a */ private static function pkcs12helper($n, $hashObj, $i, $d, $count) { static $one; if (!isset($one)) { $one = new BigInteger(1); } $blockLength = $hashObj->getBlockLength() >> 3; $c = ceil($n / $hashObj->getLengthInBytes()); $a = ''; for ($j = 1; $j <= $c; $j++) { $ai = $d.$i; for ($k = 0; $k < $count; $k++) { $ai = $hashObj->hash($ai); } $b = ''; while (strlen($b) < $blockLength) { $b .= $ai; } $b = substr($b, 0, $blockLength); $b = new BigInteger($b, 256); $newi = ''; for ($k = 0; $k < strlen($i); $k += $blockLength) { $temp = substr($i, $k, $blockLength); $temp = new BigInteger($temp, 256); $temp->setPrecision($blockLength << 3); $temp = $temp->add($b); $temp = $temp->add($one); $newi .= $temp->toBytes(false); } $i = $newi; $a .= $ai; } return substr($a, 0, $n); } /** * Encrypts a message. * * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's * necessary are discussed in the following * URL: * * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} * * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that * length. * * @see self::decrypt() * @access public * @param string $plaintext * @return string $ciphertext * @internal Could, but not must, extend by the child Crypt_* class */ public function encrypt($plaintext) { if ($this->paddable) { $plaintext = $this->pad($plaintext); } $this->setup(); if ($this->mode == self::MODE_GCM) { $oldIV = $this->iv; Strings::increment_str($this->iv); $cipher = new static('ctr'); $cipher->setKey($this->key); $cipher->setIV($this->iv); $ciphertext = $cipher->encrypt($plaintext); $s = $this->ghash( self::nullPad128($this->aad). self::nullPad128($ciphertext). self::len64($this->aad). self::len64($ciphertext) ); $cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV; $this->newtag = $cipher->encrypt($s); return $ciphertext; } if (isset($this->poly1305Key)) { $cipher = clone $this; unset($cipher->poly1305Key); $this->usePoly1305 = false; $ciphertext = $cipher->encrypt($plaintext); $this->newtag = $this->poly1305($ciphertext); return $ciphertext; } if ($this->engine === self::ENGINE_EVAL) { $inline = $this->inline_crypt; return $inline('encrypt', $plaintext); } if ($this->mode === self::MODE_IGE) { return $this->handleIGE($plaintext, $this->encryptIV, true); } if ($this->engine === self::ENGINE_OPENSSL) { switch ($this->mode) { case self::MODE_STREAM: return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); case self::MODE_ECB: return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); case self::MODE_CBC: $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV); if ($this->continuousBuffer) { $this->encryptIV = substr($result, -$this->block_size); } return $result; case self::MODE_CTR: return $this->openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer); case self::MODE_CFB: // cfb loosely routines inspired by openssl's: // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} $ciphertext = ''; if ($this->continuousBuffer) { $iv = &$this->encryptIV; $pos = &$this->enbuffer['pos']; } else { $iv = $this->encryptIV; $pos = 0; } $len = strlen($plaintext); $i = 0; if ($pos) { $orig_pos = $pos; $max = $this->block_size - $pos; if ($len >= $max) { $i = $max; $len -= $max; $pos = 0; } else { $i = $len; $pos += $len; $len = 0; } // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize $ciphertext = substr($iv, $orig_pos) ^ $plaintext; $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); $plaintext = substr($plaintext, $i); } $overflow = $len % $this->block_size; if ($overflow) { $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow).str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); $iv = Strings::pop($ciphertext, $this->block_size); $size = $len - $overflow; $block = $iv ^ substr($plaintext, -$overflow); $iv = substr_replace($iv, $block, 0, $overflow); $ciphertext .= $block; $pos = $overflow; } elseif ($len) { $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); $iv = substr($ciphertext, -$this->block_size); } return $ciphertext; case self::MODE_CFB8: $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV); if ($this->continuousBuffer) { if (($len = strlen($ciphertext)) >= $this->block_size) { $this->encryptIV = substr($ciphertext, -$this->block_size); } else { $this->encryptIV = substr($this->encryptIV, $len - $this->block_size).substr($ciphertext, -$len); } } return $ciphertext; case self::MODE_OFB: return $this->openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer); } } if ($this->engine === self::ENGINE_MCRYPT) { if ($this->enchanged) { @mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV)); $this->enchanged = false; } // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's // rewritten CFB implementation the above outputs the same thing twice. if ($this->mode == self::MODE_CFB && $this->continuousBuffer) { $block_size = $this->block_size; $iv = &$this->encryptIV; $pos = &$this->enbuffer['pos']; $len = strlen($plaintext); $ciphertext = ''; $i = 0; if ($pos) { $orig_pos = $pos; $max = $block_size - $pos; if ($len >= $max) { $i = $max; $len -= $max; $pos = 0; } else { $i = $len; $pos += $len; $len = 0; } $ciphertext = substr($iv, $orig_pos) ^ $plaintext; $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); $this->enbuffer['enmcrypt_init'] = true; } if ($len >= $block_size) { if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) { if ($this->enbuffer['enmcrypt_init'] === true) { @mcrypt_generic_init($this->enmcrypt, $this->key, $iv); $this->enbuffer['enmcrypt_init'] = false; } $ciphertext .= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size)); $iv = substr($ciphertext, -$block_size); $len %= $block_size; } else { while ($len >= $block_size) { $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size); $ciphertext .= $iv; $len -= $block_size; $i += $block_size; } } } if ($len) { $iv = @mcrypt_generic($this->ecb, $iv); $block = $iv ^ substr($plaintext, -$len); $iv = substr_replace($iv, $block, 0, $len); $ciphertext .= $block; $pos = $len; } return $ciphertext; } $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext); if (!$this->continuousBuffer) { @mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV)); } return $ciphertext; } $buffer = &$this->enbuffer; $block_size = $this->block_size; $ciphertext = ''; switch ($this->mode) { case self::MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $ciphertext .= $this->encryptBlock(substr($plaintext, $i, $block_size)); } break; case self::MODE_CBC: $xor = $this->encryptIV; for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $block = substr($plaintext, $i, $block_size); $block = $this->encryptBlock($block ^ $xor); $xor = $block; $ciphertext .= $block; } if ($this->continuousBuffer) { $this->encryptIV = $xor; } break; case self::MODE_CTR: $xor = $this->encryptIV; if (strlen($buffer['ciphertext'])) { for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $block = substr($plaintext, $i, $block_size); if (strlen($block) > strlen($buffer['ciphertext'])) { $buffer['ciphertext'] .= $this->encryptBlock($xor); } Strings::increment_str($xor); $key = Strings::shift($buffer['ciphertext'], $block_size); $ciphertext .= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $block = substr($plaintext, $i, $block_size); $key = $this->encryptBlock($xor); Strings::increment_str($xor); $ciphertext .= $block ^ $key; } } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer['ciphertext'] = substr($key, $start).$buffer['ciphertext']; } } break; case self::MODE_CFB: // cfb loosely routines inspired by openssl's: // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} if ($this->continuousBuffer) { $iv = &$this->encryptIV; $pos = &$buffer['pos']; } else { $iv = $this->encryptIV; $pos = 0; } $len = strlen($plaintext); $i = 0; if ($pos) { $orig_pos = $pos; $max = $block_size - $pos; if ($len >= $max) { $i = $max; $len -= $max; $pos = 0; } else { $i = $len; $pos += $len; $len = 0; } // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize $ciphertext = substr($iv, $orig_pos) ^ $plaintext; $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); } while ($len >= $block_size) { $iv = $this->encryptBlock($iv) ^ substr($plaintext, $i, $block_size); $ciphertext .= $iv; $len -= $block_size; $i += $block_size; } if ($len) { $iv = $this->encryptBlock($iv); $block = $iv ^ substr($plaintext, $i); $iv = substr_replace($iv, $block, 0, $len); $ciphertext .= $block; $pos = $len; } break; case self::MODE_CFB8: $ciphertext = ''; $len = strlen($plaintext); $iv = $this->encryptIV; for ($i = 0; $i < $len; ++$i) { $ciphertext .= ($c = $plaintext[$i] ^ $this->encryptBlock($iv)); $iv = substr($iv, 1).$c; } if ($this->continuousBuffer) { if ($len >= $block_size) { $this->encryptIV = substr($ciphertext, -$block_size); } else { $this->encryptIV = substr($this->encryptIV, $len - $block_size).substr($ciphertext, -$len); } } break; case self::MODE_OFB: $xor = $this->encryptIV; if (strlen($buffer['xor'])) { for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $block = substr($plaintext, $i, $block_size); if (strlen($block) > strlen($buffer['xor'])) { $xor = $this->encryptBlock($xor); $buffer['xor'] .= $xor; } $key = Strings::shift($buffer['xor'], $block_size); $ciphertext .= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $xor = $this->encryptBlock($xor); $ciphertext .= substr($plaintext, $i, $block_size) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer['xor'] = substr($key, $start).$buffer['xor']; } } break; case self::MODE_STREAM: $ciphertext = $this->encryptBlock($plaintext); break; } return $ciphertext; } /** * Decrypts a message. * * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until * it is. * * @see self::encrypt() * @access public * @param string $ciphertext * @return string $plaintext * @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size * @internal Could, but not must, extend by the child Crypt_* class */ public function decrypt($ciphertext) { if ($this->paddable && strlen($ciphertext) % $this->block_size) { throw new \LengthException('The ciphertext length ('.strlen($ciphertext).') needs to be a multiple of the block size ('.$this->block_size.')'); } $this->setup(); if ($this->mode == self::MODE_GCM || isset($this->poly1305Key)) { if ($this->oldtag === false) { throw new InsufficientSetupException('Authentication Tag has not been set'); } if (isset($this->poly1305Key)) { $newtag = $this->poly1305($ciphertext); } else { $oldIV = $this->iv; Strings::increment_str($this->iv); $cipher = new static('ctr'); $cipher->setKey($this->key); $cipher->setIV($this->iv); $plaintext = $cipher->decrypt($ciphertext); $s = $this->ghash( self::nullPad128($this->aad). self::nullPad128($ciphertext). self::len64($this->aad). self::len64($ciphertext) ); $cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV; $newtag = $cipher->encrypt($s); } if ($this->oldtag != substr($newtag, 0, strlen($newtag))) { $cipher = clone $this; unset($cipher->poly1305Key); $this->usePoly1305 = false; $plaintext = $cipher->decrypt($ciphertext); $this->oldtag = false; throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match'); } $this->oldtag = false; return $plaintext; } if ($this->engine === self::ENGINE_EVAL) { $inline = $this->inline_crypt; return $inline('decrypt', $ciphertext); } if ($this->mode === self::MODE_IGE) { return $this->handleIGE($ciphertext, $this->decryptIV, false); } if ($this->engine === self::ENGINE_OPENSSL) { switch ($this->mode) { case self::MODE_STREAM: $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); break; case self::MODE_ECB: $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); break; case self::MODE_CBC: $offset = $this->block_size; $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV); if ($this->continuousBuffer) { $this->decryptIV = substr($ciphertext, -$offset, $this->block_size); } break; case self::MODE_CTR: $plaintext = $this->openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer); break; case self::MODE_CFB: // cfb loosely routines inspired by openssl's: // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} $plaintext = ''; if ($this->continuousBuffer) { $iv = &$this->decryptIV; $pos = &$this->buffer['pos']; } else { $iv = $this->decryptIV; $pos = 0; } $len = strlen($ciphertext); $i = 0; if ($pos) { $orig_pos = $pos; $max = $this->block_size - $pos; if ($len >= $max) { $i = $max; $len -= $max; $pos = 0; } else { $i = $len; $pos += $len; $len = 0; } // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize $plaintext = substr($iv, $orig_pos) ^ $ciphertext; $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); $ciphertext = substr($ciphertext, $i); } $overflow = $len % $this->block_size; if ($overflow) { $plaintext .= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); if ($len - $overflow) { $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow); } $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); $plaintext .= $iv ^ substr($ciphertext, -$overflow); $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow); $pos = $overflow; } elseif ($len) { $plaintext .= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); $iv = substr($ciphertext, -$this->block_size); } break; case self::MODE_CFB8: $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV); if ($this->continuousBuffer) { if (($len = strlen($ciphertext)) >= $this->block_size) { $this->decryptIV = substr($ciphertext, -$this->block_size); } else { $this->decryptIV = substr($this->decryptIV, $len - $this->block_size).substr($ciphertext, -$len); } } break; case self::MODE_OFB: $plaintext = $this->openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer); } return $this->paddable ? $this->unpad($plaintext) : $plaintext; } if ($this->engine === self::ENGINE_MCRYPT) { $block_size = $this->block_size; if ($this->dechanged) { @mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV)); $this->dechanged = false; } if ($this->mode == self::MODE_CFB && $this->continuousBuffer) { $iv = &$this->decryptIV; $pos = &$this->debuffer['pos']; $len = strlen($ciphertext); $plaintext = ''; $i = 0; if ($pos) { $orig_pos = $pos; $max = $block_size - $pos; if ($len >= $max) { $i = $max; $len -= $max; $pos = 0; } else { $i = $len; $pos += $len; $len = 0; } // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize $plaintext = substr($iv, $orig_pos) ^ $ciphertext; $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); } if ($len >= $block_size) { $cb = substr($ciphertext, $i, $len - $len % $block_size); $plaintext .= @mcrypt_generic($this->ecb, $iv.$cb) ^ $cb; $iv = substr($cb, -$block_size); $len %= $block_size; } if ($len) { $iv = @mcrypt_generic($this->ecb, $iv); $plaintext .= $iv ^ substr($ciphertext, -$len); $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); $pos = $len; } return $plaintext; } $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext); if (!$this->continuousBuffer) { @mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV)); } return $this->paddable ? $this->unpad($plaintext) : $plaintext; } $block_size = $this->block_size; $buffer = &$this->debuffer; $plaintext = ''; switch ($this->mode) { case self::MODE_ECB: for ($i = 0; $i < strlen($ciphertext); $i += $block_size) { $plaintext .= $this->decryptBlock(substr($ciphertext, $i, $block_size)); } break; case self::MODE_CBC: $xor = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i += $block_size) { $block = substr($ciphertext, $i, $block_size); $plaintext .= $this->decryptBlock($block) ^ $xor; $xor = $block; } if ($this->continuousBuffer) { $this->decryptIV = $xor; } break; case self::MODE_CTR: $xor = $this->decryptIV; if (strlen($buffer['ciphertext'])) { for ($i = 0; $i < strlen($ciphertext); $i += $block_size) { $block = substr($ciphertext, $i, $block_size); if (strlen($block) > strlen($buffer['ciphertext'])) { $buffer['ciphertext'] .= $this->encryptBlock($xor); } Strings::increment_str($xor); $key = Strings::shift($buffer['ciphertext'], $block_size); $plaintext .= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i += $block_size) { $block = substr($ciphertext, $i, $block_size); $key = $this->encryptBlock($xor); Strings::increment_str($xor); $plaintext .= $block ^ $key; } } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % $block_size) { $buffer['ciphertext'] = substr($key, $start).$buffer['ciphertext']; } } break; case self::MODE_CFB: if ($this->continuousBuffer) { $iv = &$this->decryptIV; $pos = &$buffer['pos']; } else { $iv = $this->decryptIV; $pos = 0; } $len = strlen($ciphertext); $i = 0; if ($pos) { $orig_pos = $pos; $max = $block_size - $pos; if ($len >= $max) { $i = $max; $len -= $max; $pos = 0; } else { $i = $len; $pos += $len; $len = 0; } // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize $plaintext = substr($iv, $orig_pos) ^ $ciphertext; $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); } while ($len >= $block_size) { $iv = $this->encryptBlock($iv); $cb = substr($ciphertext, $i, $block_size); $plaintext .= $iv ^ $cb; $iv = $cb; $len -= $block_size; $i += $block_size; } if ($len) { $iv = $this->encryptBlock($iv); $plaintext .= $iv ^ substr($ciphertext, $i); $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len); $pos = $len; } break; case self::MODE_CFB8: $plaintext = ''; $len = strlen($ciphertext); $iv = $this->decryptIV; for ($i = 0; $i < $len; ++$i) { $plaintext .= $ciphertext[$i] ^ $this->encryptBlock($iv); $iv = substr($iv, 1).$ciphertext[$i]; } if ($this->continuousBuffer) { if ($len >= $block_size) { $this->decryptIV = substr($ciphertext, -$block_size); } else { $this->decryptIV = substr($this->decryptIV, $len - $block_size).substr($ciphertext, -$len); } } break; case self::MODE_OFB: $xor = $this->decryptIV; if (strlen($buffer['xor'])) { for ($i = 0; $i < strlen($ciphertext); $i += $block_size) { $block = substr($ciphertext, $i, $block_size); if (strlen($block) > strlen($buffer['xor'])) { $xor = $this->encryptBlock($xor); $buffer['xor'] .= $xor; } $key = Strings::shift($buffer['xor'], $block_size); $plaintext .= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i += $block_size) { $xor = $this->encryptBlock($xor); $plaintext .= substr($ciphertext, $i, $block_size) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % $block_size) { $buffer['xor'] = substr($key, $start).$buffer['xor']; } } break; case self::MODE_STREAM: $plaintext = $this->decryptBlock($ciphertext); break; } return $this->paddable ? $this->unpad($plaintext) : $plaintext; } /** * Get the authentication tag * * Only used in GCM or Poly1305 mode * * @see self::encrypt() * @param int $length optional * @return string * @access public * @throws \LengthException if $length isn't of a sufficient length * @throws \RuntimeException if GCM mode isn't being used */ public function getTag($length = 16) { if ($this->mode != self::MODE_GCM && !$this->usePoly1305) { throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305'); } if ($this->newtag === false) { throw new \BadMethodCallException('A tag can only be returned after a round of encryption has been performed'); } // the tag is 128-bits. it can't be greater than 16 bytes because that's bigger than the tag is. if it // were 0 you might as well be doing CTR and less than 4 provides minimal security that could be trivially // easily brute forced. // see https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=36 // for more info if ($length < 4 || $length > 16) { throw new \LengthException('The authentication tag must be between 4 and 16 bytes long'); } return $length == 16 ? $this->newtag : substr($this->newtag, 0, $length); } /** * Sets the authentication tag * * Only used in GCM mode * * @see self::decrypt() * @param string $tag * @access public * @throws \LengthException if $length isn't of a sufficient length * @throws \RuntimeException if GCM mode isn't being used */ public function setTag($tag) { if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) { $this->createPoly1305Key(); } if ($this->mode != self::MODE_GCM && !$this->usePoly1305) { throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305'); } $length = strlen($tag); if ($length < 4 || $length > 16) { throw new \LengthException('The authentication tag must be between 4 and 16 bytes long'); } $this->oldtag = $tag; } /** * Get the IV * * mcrypt requires an IV even if ECB is used * * @see self::encrypt() * @see self::decrypt() * @param string $iv * @return string * @access private */ protected function getIV($iv) { return $this->mode == self::MODE_ECB ? str_repeat("\0", $this->block_size) : $iv; } /** * Handle mode-independant IGE encryption/decryption * * @see self::encrypt() * @see self::decrypt() * @param string $plaintext * @param string $encryptIV * @param bool $encrypt * @return string * @access private */ private function handleIGE($plaintext, &$encryptIV, $encrypt) { if (strlen($plaintext) % $this->block_size) { throw new \LengthException('The input length ('.strlen($plaintext).') needs to be a multiple of the block size ('.$this->block_size.')'); } $iv_part_1 = substr($encryptIV, 0, $this->block_size); $iv_part_2 = substr($encryptIV, $this->block_size); $ciphertext = ""; for ($i = 0, $length = strlen($plaintext); $i < $length; $i += $this->block_size) { $indata = substr($plaintext, $i, $this->block_size); $outdata = $indata ^ $iv_part_1; switch ($this->engine) { case self::ENGINE_OPENSSL: if ($encrypt) { $outdata = openssl_encrypt($outdata, static::$cipher_name_openssl_ecb, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); } else { $outdata = openssl_decrypt($outdata, static::$cipher_name_openssl_ecb, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); } break; case self::ENGINE_MCRYPT: if ($encrypt) { if ($this->enchanged) { @mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV)); $this->enchanged = false; } $outdata = @mcrypt_generic($this->enmcrypt, $outdata); } else { if ($this->dechanged) { @mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV)); $this->dechanged = false; } $outdata = @mdecrypt_generic($this->demcrypt, $outdata); } break; case self::ENGINE_INTERNAL: if ($encrypt) { $outdata = $this->encryptBlock($outdata); } else { $outdata = $this->decryptBlock($outdata); } break; } $outdata = $outdata ^ $iv_part_2; $ciphertext .= $outdata; $iv_part_1 = $outdata; $iv_part_2 = $indata; } if ($this->continuousBuffer) { $encryptIV = $iv_part_1.$iv_part_2; } return $ciphertext; } /** * OpenSSL CTR Processor * * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream * for CTR is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt() * and SymmetricKey::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this * function will emulate CTR with ECB when necessary. * * @see self::encrypt() * @see self::decrypt() * @param string $plaintext * @param string $encryptIV * @param array $buffer * @return string * @access private */ private function openssl_ctr_process($plaintext, &$encryptIV, &$buffer) { $ciphertext = ''; $block_size = $this->block_size; $key = $this->key; if ($this->openssl_emulate_ctr) { $xor = $encryptIV; if (strlen($buffer['ciphertext'])) { for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $block = substr($plaintext, $i, $block_size); if (strlen($block) > strlen($buffer['ciphertext'])) { $buffer['ciphertext'] .= openssl_encrypt($xor, static::$cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); } Strings::increment_str($xor); $otp = Strings::shift($buffer['ciphertext'], $block_size); $ciphertext .= $block ^ $otp; } } else { for ($i = 0; $i < strlen($plaintext); $i += $block_size) { $block = substr($plaintext, $i, $block_size); $otp = openssl_encrypt($xor, static::$cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); Strings::increment_str($xor); $ciphertext .= $block ^ $otp; } } if ($this->continuousBuffer) { $encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer['ciphertext'] = substr($key, $start).$buffer['ciphertext']; } } return $ciphertext; } if (strlen($buffer['ciphertext'])) { $ciphertext = $plaintext ^ Strings::shift($buffer['ciphertext'], strlen($plaintext)); $plaintext = substr($plaintext, strlen($ciphertext)); if (!strlen($plaintext)) { return $ciphertext; } } $overflow = strlen($plaintext) % $block_size; if ($overflow) { $plaintext2 = Strings::pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2 $encrypted = openssl_encrypt($plaintext.str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV); $temp = Strings::pop($encrypted, $block_size); $ciphertext .= $encrypted.($plaintext2 ^ $temp); if ($this->continuousBuffer) { $buffer['ciphertext'] = substr($temp, $overflow); $encryptIV = $temp; } } elseif (!strlen($buffer['ciphertext'])) { $ciphertext .= openssl_encrypt($plaintext.str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV); $temp = Strings::pop($ciphertext, $block_size); if ($this->continuousBuffer) { $encryptIV = $temp; } } if ($this->continuousBuffer) { $encryptIV = openssl_decrypt($encryptIV, static::$cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); if ($overflow) { Strings::increment_str($encryptIV); } } return $ciphertext; } /** * OpenSSL OFB Processor * * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream * for OFB is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt() * and SymmetricKey::decrypt(). * * @see self::encrypt() * @see self::decrypt() * @param string $plaintext * @param string $encryptIV * @param array $buffer * @return string * @access private */ private function openssl_ofb_process($plaintext, &$encryptIV, &$buffer) { if (strlen($buffer['xor'])) { $ciphertext = $plaintext ^ $buffer['xor']; $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); $plaintext = substr($plaintext, strlen($ciphertext)); } else { $ciphertext = ''; } $block_size = $this->block_size; $len = strlen($plaintext); $key = $this->key; $overflow = $len % $block_size; if (strlen($plaintext)) { if ($overflow) { $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow).str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV); $xor = Strings::pop($ciphertext, $block_size); if ($this->continuousBuffer) { $encryptIV = $xor; } $ciphertext .= Strings::shift($xor, $overflow) ^ substr($plaintext, -$overflow); if ($this->continuousBuffer) { $buffer['xor'] = $xor; } } else { $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV); if ($this->continuousBuffer) { $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size); } } } return $ciphertext; } /** * phpseclib <-> OpenSSL Mode Mapper * * May need to be overwritten by classes extending this one in some cases * * @return string * @access private */ protected function openssl_translate_mode() { switch ($this->mode) { case self::MODE_IGE: return 'ige'; case self::MODE_ECB: return 'ecb'; case self::MODE_CBC: return 'cbc'; case self::MODE_CTR: case self::MODE_GCM: return 'ctr'; case self::MODE_CFB: return 'cfb'; case self::MODE_CFB8: return 'cfb8'; case self::MODE_OFB: return 'ofb'; } } /** * Pad "packets". * * Block ciphers working by encrypting between their specified [$this->]block_size at a time * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to * pad the input so that it is of the proper length. * * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is * transmitted separately) * * @see self::disablePadding() * @access public */ public function enablePadding() { $this->padding = true; } /** * Do not pad packets. * * @see self::enablePadding() * @access public */ public function disablePadding() { $this->padding = false; } /** * Treat consecutive "packets" as if they are a continuous buffer. * * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets * will yield different outputs: * * <code> * echo $rijndael->encrypt(substr($plaintext, 0, 16)); * echo $rijndael->encrypt(substr($plaintext, 16, 16)); * </code> * <code> * echo $rijndael->encrypt($plaintext); * </code> * * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates * another, as demonstrated with the following: * * <code> * $rijndael->encrypt(substr($plaintext, 0, 16)); * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); * </code> * <code> * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16))); * </code> * * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different * outputs. The reason is due to the fact that the initialization vector's change after every encryption / * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. * * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\*() object changes after each * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), * however, they are also less intuitive and more likely to cause you problems. * * @see self::disableContinuousBuffer() * @access public * @internal Could, but not must, extend by the child Crypt_* class */ public function enableContinuousBuffer() { if ($this->mode == self::MODE_ECB) { return; } if ($this->mode == self::MODE_GCM) { throw new \BadMethodCallException('This mode does not run in continuous mode'); } $this->continuousBuffer = true; $this->setEngine(); } /** * Treat consecutive packets as if they are a discontinuous buffer. * * The default behavior. * * @see self::enableContinuousBuffer() * @access public * @internal Could, but not must, extend by the child Crypt_* class */ public function disableContinuousBuffer() { if ($this->mode == self::MODE_ECB) { return; } if (!$this->continuousBuffer) { return; } $this->continuousBuffer = false; $this->changed = true; $this->setEngine(); } /** * Test for engine validity * * @see self::__construct() * @param int $engine * @access private * @return bool */ protected function isValidEngineHelper($engine) { switch ($engine) { case self::ENGINE_OPENSSL: $this->openssl_emulate_ctr = false; $result = $this->cipher_name_openssl && extension_loaded('openssl'); if (!$result) { return false; } $methods = openssl_get_cipher_methods(); if (in_array($this->cipher_name_openssl, $methods)) { return true; } // not all of openssl's symmetric cipher's support ctr. for those // that don't we'll emulate it if ($this->mode === self::MODE_CTR && in_array(static::$cipher_name_openssl_ecb, $methods)) { $this->openssl_emulate_ctr = true; return true; } else if ($this->mode === self::MODE_IGE) { return true; } return false; case self::ENGINE_MCRYPT: return $this->cipher_name_mcrypt && extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms()); case self::ENGINE_EVAL: return method_exists($this, 'setupInlineCrypt'); case self::ENGINE_INTERNAL: return true; } return false; } /** * Test for engine validity * * @see self::__construct() * @param string $engine * @access public * @return bool */ public function isValidEngine($engine) { static $reverseMap; if (!isset($reverseMap)) { $reverseMap = array_map('strtolower', self::ENGINE_MAP); $reverseMap = array_flip($reverseMap); } $engine = strtolower($engine); if (!isset($reverseMap[$engine])) { return false; } return $this->isValidEngineHelper($reverseMap[$engine]); } /** * Sets the preferred crypt engine * * Currently, $engine could be: * * - libsodium[very fast] * * - OpenSSL [very fast] * * - mcrypt [fast] * * - Eval [slow] * * - PHP [slowest] * * If the preferred crypt engine is not available the fastest available one will be used * * @see self::__construct() * @param string $engine * @access public */ public function setPreferredEngine($engine) { static $reverseMap; if (!isset($reverseMap)) { $reverseMap = array_map('strtolower', self::ENGINE_MAP); $reverseMap = array_flip($reverseMap); } $engine = strtolower($engine); $this->preferredEngine = isset($reverseMap[$engine]) ? $reverseMap[$engine] : self::ENGINE_LIBSODIUM; $this->setEngine(); } /** * Returns the engine currently being utilized * * @see self::setEngine() * @access public */ public function getEngine() { return self::ENGINE_MAP[$this->engine]; } /** * Sets the engine as appropriate * * @see self::__construct() * @access private */ protected function setEngine() { $this->engine = null; $candidateEngines = [ self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM, self::ENGINE_OPENSSL, self::ENGINE_MCRYPT, self::ENGINE_EVAL, ]; if (isset($this->preferredEngine)) { $temp = [$this->preferredEngine]; $candidateEngines = array_merge( $temp, array_diff($candidateEngines, $temp) ); } foreach ($candidateEngines as $engine) { if ($this->isValidEngineHelper($engine)) { $this->engine = $engine; break; } } if (!$this->engine) { $this->engine = self::ENGINE_INTERNAL; } if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) { // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed, // (re)open them with the module named in $this->cipher_name_mcrypt @mcrypt_module_close($this->enmcrypt); @mcrypt_module_close($this->demcrypt); $this->enmcrypt = null; $this->demcrypt = null; if ($this->ecb) { @mcrypt_module_close($this->ecb); $this->ecb = null; } } $this->changed = true; } /** * Encrypts a block * * Note: Must be extended by the child \phpseclib\Crypt\* class * * @access private * @param string $in * @return string */ abstract protected function encryptBlock($in); /** * Decrypts a block * * Note: Must be extended by the child \phpseclib\Crypt\* class * * @access private * @param string $in * @return string */ abstract protected function decryptBlock($in); /** * Setup the key (expansion) * * Only used if $engine == self::ENGINE_INTERNAL * * Note: Must extend by the child \phpseclib\Crypt\* class * * @see self::setup() * @access private */ abstract protected function setupKey(); /** * Setup the self::ENGINE_INTERNAL $engine * * (re)init, if necessary, the internal cipher $engine and flush all $buffers * Used (only) if $engine == self::ENGINE_INTERNAL * * _setup() will be called each time if $changed === true * typically this happens when using one or more of following public methods: * * - setKey() * * - setIV() * * - disableContinuousBuffer() * * - First run of encrypt() / decrypt() with no init-settings * * @see self::setKey() * @see self::setIV() * @see self::disableContinuousBuffer() * @access private * @internal setup() is always called before en/decryption. * @internal Could, but not must, extend by the child Crypt_* class */ protected function setup() { if (!$this->changed) { return; } $this->changed = false; if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) { $this->createPoly1305Key(); } $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true]; //$this->newtag = $this->oldtag = false; if ($this->usesNonce()) { if ($this->nonce === false) { throw new InsufficientSetupException('No nonce has been defined'); } if ($this->mode == self::MODE_GCM && !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) { $this->setupGCM(); } } else { $this->iv = $this->origIV; } if ($this->iv === false && !in_array($this->mode, [self::MODE_STREAM, self::MODE_ECB])) { if ($this->mode != self::MODE_GCM || !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) { throw new InsufficientSetupException('No IV has been defined'); } } if ($this->key === false) { throw new InsufficientSetupException('No key has been defined'); } $this->encryptIV = $this->decryptIV = $this->iv; if ($this->mode === self::MODE_IGE) { $this->decryptIV = implode('', array_reverse(str_split($this->decryptIV, $this->block_size))); } switch ($this->engine) { case self::ENGINE_MCRYPT: $this->enchanged = $this->dechanged = true; if (!isset($this->enmcrypt)) { static $mcrypt_modes = [ self::MODE_IGE => MCRYPT_MODE_ECB, self::MODE_CTR => 'ctr', self::MODE_ECB => MCRYPT_MODE_ECB, self::MODE_CBC => MCRYPT_MODE_CBC, self::MODE_CFB => 'ncfb', self::MODE_CFB8 => MCRYPT_MODE_CFB, self::MODE_OFB => MCRYPT_MODE_NOFB, self::MODE_STREAM => MCRYPT_MODE_STREAM, ]; $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], ''); // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() // to workaround mcrypt's broken ncfb implementation in buffered mode // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} if ($this->mode == self::MODE_CFB) { $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); } } // else should mcrypt_generic_deinit be called? if ($this->mode == self::MODE_CFB) { @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); } break; case self::ENGINE_INTERNAL: $this->setupKey(); break; case self::ENGINE_EVAL: $this->setupKey(); $this->setupInlineCrypt(); } } /** * Pads a string * * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to * chr($this->block_size - (strlen($text) % $this->block_size) * * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless * and padding will, hence forth, be enabled. * * @see self::unpad() * @param string $text * @throws \LengthException if padding is disabled and the plaintext's length is not a multiple of the block size * @access private * @return string */ protected function pad($text) { $length = strlen($text); if (!$this->padding) { if ($length % $this->block_size == 0) { return $text; } else { throw new \LengthException("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size}). Try enabling padding."); } } $pad = $this->block_size - ($length % $this->block_size); return str_pad($text, $length + $pad, chr($pad)); } /** * Unpads a string. * * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong * and false will be returned. * * @see self::pad() * @param string $text * @throws \LengthException if the ciphertext's length is not a multiple of the block size * @access private * @return string */ protected function unpad($text) { if (!$this->padding) { return $text; } $length = ord($text[strlen($text) - 1]); if (!$length || $length > $this->block_size) { throw new BadDecryptionException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})"); } return substr($text, 0, -$length); } /** * Setup the performance-optimized function for de/encrypt() * * Stores the created (or existing) callback function-name * in $this->inline_crypt * * Internally for phpseclib developers: * * _setupInlineCrypt() would be called only if: * * - $this->engine === self::ENGINE_EVAL * * - each time on _setup(), after(!) _setupKey() * * * This ensures that _setupInlineCrypt() has always a * full ready2go initializated internal cipher $engine state * where, for example, the keys already expanded, * keys/block_size calculated and such. * * It is, each time if called, the responsibility of _setupInlineCrypt(): * * - to set $this->inline_crypt to a valid and fully working callback function * as a (faster) replacement for encrypt() / decrypt() * * - NOT to create unlimited callback functions (for memory reasons!) * no matter how often _setupInlineCrypt() would be called. At some * point of amount they must be generic re-useable. * * - the code of _setupInlineCrypt() it self, * and the generated callback code, * must be, in following order: * - 100% safe * - 100% compatible to encrypt()/decrypt() * - using only php5+ features/lang-constructs/php-extensions if * compatibility (down to php4) or fallback is provided * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-) * - >= 10% faster than encrypt()/decrypt() [which is, by the way, * the reason for the existence of _setupInlineCrypt() :-)] * - memory-nice * - short (as good as possible) * * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code. * - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib\Crypt\* class. * - The following variable names are reserved: * - $_* (all variable names prefixed with an underscore) * - $self (object reference to it self. Do not use $this, but $self instead) * - $in (the content of $in has to en/decrypt by the generated code) * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only * * * @see self::setup() * @see self::createInlineCryptFunction() * @see self::encrypt() * @see self::decrypt() * @access private * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt() */ //protected function setupInlineCrypt(); /** * Creates the performance-optimized function for en/decrypt() * * Internally for phpseclib developers: * * _createInlineCryptFunction(): * * - merge the $cipher_code [setup'ed by _setupInlineCrypt()] * with the current [$this->]mode of operation code * * - create the $inline function, which called by encrypt() / decrypt() * as its replacement to speed up the en/decryption operations. * * - return the name of the created $inline callback function * * - used to speed up en/decryption * * * * The main reason why can speed up things [up to 50%] this way are: * * - using variables more effective then regular. * (ie no use of expensive arrays but integers $k_0, $... * or even, for example, the pure $key[] values hardcoded) * * - avoiding 1000's of function calls of ie _encryptBlock() * but inlining the crypt operations. * in the mode of operation for() loop. * * - full loop unroll the (sometimes key-dependent) rounds * avoiding this way ++$i counters and runtime-if's etc... * * The basic code architectur of the generated $inline en/decrypt() * lambda function, in pseudo php, is: * * <code> * +----------------------------------------------------------------------------------------------+ * | callback $inline = create_function: | * | lambda_function_0001_crypt_ECB($action, $text) | * | { | * | INSERT PHP CODE OF: | * | $cipher_code['init_crypt']; // general init code. | * | // ie: $sbox'es declarations used for | * | // encrypt and decrypt'ing. | * | | * | switch ($action) { | * | case 'encrypt': | * | INSERT PHP CODE OF: | * | $cipher_code['init_encrypt']; // encrypt sepcific init code. | * | ie: specified $key or $box | * | declarations for encrypt'ing. | * | | * | foreach ($ciphertext) { | * | $in = $block_size of $ciphertext; | * | | * | INSERT PHP CODE OF: | * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: | * | // strlen($in) == $this->block_size | * | // here comes the cipher algorithm in action | * | // for encryption. | * | // $cipher_code['encrypt_block'] has to | * | // encrypt the content of the $in variable | * | | * | $plaintext .= $in; | * | } | * | return $plaintext; | * | | * | case 'decrypt': | * | INSERT PHP CODE OF: | * | $cipher_code['init_decrypt']; // decrypt sepcific init code | * | ie: specified $key or $box | * | declarations for decrypt'ing. | * | foreach ($plaintext) { | * | $in = $block_size of $plaintext; | * | | * | INSERT PHP CODE OF: | * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always | * | // strlen($in) == $this->block_size | * | // here comes the cipher algorithm in action | * | // for decryption. | * | // $cipher_code['decrypt_block'] has to | * | // decrypt the content of the $in variable | * | $ciphertext .= $in; | * | } | * | return $ciphertext; | * | } | * | } | * +----------------------------------------------------------------------------------------------+ * </code> * * See also the \phpseclib\Crypt\*::_setupInlineCrypt()'s for * productive inline $cipher_code's how they works. * * Structure of: * <code> * $cipher_code = [ * 'init_crypt' => (string) '', // optional * 'init_encrypt' => (string) '', // optional * 'init_decrypt' => (string) '', // optional * 'encrypt_block' => (string) '', // required * 'decrypt_block' => (string) '' // required * ]; * </code> * * @see self::setupInlineCrypt() * @see self::encrypt() * @see self::decrypt() * @param array $cipher_code * @access private * @return string (the name of the created callback function) */ protected function createInlineCryptFunction($cipher_code) { $block_size = $this->block_size; // optional $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : ''; $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : ''; $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : ''; // required $encrypt_block = $cipher_code['encrypt_block']; $decrypt_block = $cipher_code['decrypt_block']; // Generating mode of operation inline code, // merged with the $cipher_code algorithm // for encrypt- and decryption. switch ($this->mode) { case self::MODE_ECB: $encrypt = $init_encrypt.' $_ciphertext = ""; $_plaintext_len = strlen($_text); for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $in = substr($_text, $_i, '.$block_size.'); '.$encrypt_block.' $_ciphertext.= $in; } return $_ciphertext; '; $decrypt = $init_decrypt.' $_plaintext = ""; $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); $_ciphertext_len = strlen($_text); for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $in = substr($_text, $_i, '.$block_size.'); '.$decrypt_block.' $_plaintext.= $in; } return $this->unpad($_plaintext); '; break; case self::MODE_CTR: $encrypt = $init_encrypt.' $_ciphertext = ""; $_plaintext_len = strlen($_text); $_xor = $this->encryptIV; $_buffer = &$this->enbuffer; if (strlen($_buffer["ciphertext"])) { for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); if (strlen($_block) > strlen($_buffer["ciphertext"])) { $in = $_xor; '.$encrypt_block.' \phpseclib\Common\Functions\Strings::increment_str($_xor); $_buffer["ciphertext"].= $in; } $_key = \phpseclib\Common\Functions\Strings::shift($_buffer["ciphertext"], '.$block_size.'); $_ciphertext.= $_block ^ $_key; } } else { for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); $in = $_xor; '.$encrypt_block.' \phpseclib\Common\Functions\Strings::increment_str($_xor); $_key = $in; $_ciphertext.= $_block ^ $_key; } } if ($this->continuousBuffer) { $this->encryptIV = $_xor; if ($_start = $_plaintext_len % '.$block_size.') { $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; } } return $_ciphertext; '; $decrypt = $init_encrypt.' $_plaintext = ""; $_ciphertext_len = strlen($_text); $_xor = $this->decryptIV; $_buffer = &$this->debuffer; if (strlen($_buffer["ciphertext"])) { for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); if (strlen($_block) > strlen($_buffer["ciphertext"])) { $in = $_xor; '.$encrypt_block.' \phpseclib\Common\Functions\Strings::increment_str($_xor); $_buffer["ciphertext"].= $in; } $_key = \phpseclib\Common\Functions\Strings::shift($_buffer["ciphertext"], '.$block_size.'); $_plaintext.= $_block ^ $_key; } } else { for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); $in = $_xor; '.$encrypt_block.' \phpseclib\Common\Functions\Strings::increment_str($_xor); $_key = $in; $_plaintext.= $_block ^ $_key; } } if ($this->continuousBuffer) { $this->decryptIV = $_xor; if ($_start = $_ciphertext_len % '.$block_size.') { $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"]; } } return $_plaintext; '; break; case self::MODE_CFB: $encrypt = $init_encrypt.' $_ciphertext = ""; $_buffer = &$this->enbuffer; if ($this->continuousBuffer) { $_iv = &$this->encryptIV; $_pos = &$_buffer["pos"]; } else { $_iv = $this->encryptIV; $_pos = 0; } $_len = strlen($_text); $_i = 0; if ($_pos) { $_orig_pos = $_pos; $_max = '.$block_size.' - $_pos; if ($_len >= $_max) { $_i = $_max; $_len-= $_max; $_pos = 0; } else { $_i = $_len; $_pos+= $_len; $_len = 0; } $_ciphertext = substr($_iv, $_orig_pos) ^ $_text; $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i); } while ($_len >= '.$block_size.') { $in = $_iv; '.$encrypt_block.'; $_iv = $in ^ substr($_text, $_i, '.$block_size.'); $_ciphertext.= $_iv; $_len-= '.$block_size.'; $_i+= '.$block_size.'; } if ($_len) { $in = $_iv; '.$encrypt_block.' $_iv = $in; $_block = $_iv ^ substr($_text, $_i); $_iv = substr_replace($_iv, $_block, 0, $_len); $_ciphertext.= $_block; $_pos = $_len; } return $_ciphertext; '; $decrypt = $init_encrypt.' $_plaintext = ""; $_buffer = &$this->debuffer; if ($this->continuousBuffer) { $_iv = &$this->decryptIV; $_pos = &$_buffer["pos"]; } else { $_iv = $this->decryptIV; $_pos = 0; } $_len = strlen($_text); $_i = 0; if ($_pos) { $_orig_pos = $_pos; $_max = '.$block_size.' - $_pos; if ($_len >= $_max) { $_i = $_max; $_len-= $_max; $_pos = 0; } else { $_i = $_len; $_pos+= $_len; $_len = 0; } $_plaintext = substr($_iv, $_orig_pos) ^ $_text; $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i); } while ($_len >= '.$block_size.') { $in = $_iv; '.$encrypt_block.' $_iv = $in; $cb = substr($_text, $_i, '.$block_size.'); $_plaintext.= $_iv ^ $cb; $_iv = $cb; $_len-= '.$block_size.'; $_i+= '.$block_size.'; } if ($_len) { $in = $_iv; '.$encrypt_block.' $_iv = $in; $_plaintext.= $_iv ^ substr($_text, $_i); $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len); $_pos = $_len; } return $_plaintext; '; break; case self::MODE_CFB8: $encrypt = $init_encrypt.' $_ciphertext = ""; $_len = strlen($_text); $_iv = $this->encryptIV; for ($_i = 0; $_i < $_len; ++$_i) { $in = $_iv; '.$encrypt_block.' $_ciphertext .= ($_c = $_text[$_i] ^ $in); $_iv = substr($_iv, 1) . $_c; } if ($this->continuousBuffer) { if ($_len >= '.$block_size.') { $this->encryptIV = substr($_ciphertext, -'.$block_size.'); } else { $this->encryptIV = substr($this->encryptIV, $_len - '.$block_size.') . substr($_ciphertext, -$_len); } } return $_ciphertext; '; $decrypt = $init_encrypt.' $_plaintext = ""; $_len = strlen($_text); $_iv = $this->decryptIV; for ($_i = 0; $_i < $_len; ++$_i) { $in = $_iv; '.$encrypt_block.' $_plaintext .= $_text[$_i] ^ $in; $_iv = substr($_iv, 1) . $_text[$_i]; } if ($this->continuousBuffer) { if ($_len >= '.$block_size.') { $this->decryptIV = substr($_text, -'.$block_size.'); } else { $this->decryptIV = substr($this->decryptIV, $_len - '.$block_size.') . substr($_text, -$_len); } } return $_plaintext; '; break; case self::MODE_OFB: $encrypt = $init_encrypt.' $_ciphertext = ""; $_plaintext_len = strlen($_text); $_xor = $this->encryptIV; $_buffer = &$this->enbuffer; if (strlen($_buffer["xor"])) { for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); if (strlen($_block) > strlen($_buffer["xor"])) { $in = $_xor; '.$encrypt_block.' $_xor = $in; $_buffer["xor"].= $_xor; } $_key = \phpseclib\Common\Functions\Strings::shift($_buffer["xor"], '.$block_size.'); $_ciphertext.= $_block ^ $_key; } } else { for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $in = $_xor; '.$encrypt_block.' $_xor = $in; $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor; } $_key = $_xor; } if ($this->continuousBuffer) { $this->encryptIV = $_xor; if ($_start = $_plaintext_len % '.$block_size.') { $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; } } return $_ciphertext; '; $decrypt = $init_encrypt.' $_plaintext = ""; $_ciphertext_len = strlen($_text); $_xor = $this->decryptIV; $_buffer = &$this->debuffer; if (strlen($_buffer["xor"])) { for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $_block = substr($_text, $_i, '.$block_size.'); if (strlen($_block) > strlen($_buffer["xor"])) { $in = $_xor; '.$encrypt_block.' $_xor = $in; $_buffer["xor"].= $_xor; } $_key = \phpseclib\Common\Functions\Strings::shift($_buffer["xor"], '.$block_size.'); $_plaintext.= $_block ^ $_key; } } else { for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $in = $_xor; '.$encrypt_block.' $_xor = $in; $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor; } $_key = $_xor; } if ($this->continuousBuffer) { $this->decryptIV = $_xor; if ($_start = $_ciphertext_len % '.$block_size.') { $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"]; } } return $_plaintext; '; break; case self::MODE_STREAM: $encrypt = $init_encrypt.' $_ciphertext = ""; '.$encrypt_block.' return $_ciphertext; '; $decrypt = $init_decrypt.' $_plaintext = ""; '.$decrypt_block.' return $_plaintext; '; break; case self::MODE_IGE: $encrypt = $init_encrypt.' $_ciphertext = ""; $_plaintext_len = strlen($_text); $_encryptIV = &$this->encryptIV; if ($_plaintext_len % '.$block_size.') { throw new \LengthException("The input length ($_plaintext_len) needs to be a multiple of the block size ('.$block_size.')"); } $iv_part_1 = substr($_encryptIV, 0, '.$block_size.'); $iv_part_2 = substr($_encryptIV, '.$block_size.'); for ($i = 0; $i < $_plaintext_len; $i += '.$block_size.') { $indata = substr($_text, $i, '.$block_size.'); $in = $indata ^ $iv_part_1; '.$encrypt_block.' $in = $in ^ $iv_part_2; $_ciphertext .= $in; $iv_part_1 = $in; $iv_part_2 = $indata; } if ($this->continuousBuffer) { $_encryptIV = $iv_part_1.$iv_part_2; } return $_ciphertext; '; $decrypt = $init_decrypt.' $_ciphertext = ""; $_plaintext_len = strlen($_text); $_encryptIV = &$this->decryptIV; if ($_plaintext_len % '.$block_size.') { throw new \LengthException("The input length ($_plaintext_len) needs to be a multiple of the block size ('.$block_size.')"); } $iv_part_1 = substr($_encryptIV, 0, '.$block_size.'); $iv_part_2 = substr($_encryptIV, '.$block_size.'); for ($i = 0; $i < $_plaintext_len; $i += '.$block_size.') { $indata = substr($_text, $i, '.$block_size.'); $in = $indata ^ $iv_part_1; '.$decrypt_block.' $in = $in ^ $iv_part_2; $_ciphertext .= $in; $iv_part_1 = $in; $iv_part_2 = $indata; } if ($this->continuousBuffer) { $_encryptIV = $iv_part_1.$iv_part_2; } return $_ciphertext; '; break; // case self::MODE_CBC: default: $encrypt = $init_encrypt.' $_ciphertext = ""; $_plaintext_len = strlen($_text); $in = $this->encryptIV; for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') { $in = substr($_text, $_i, '.$block_size.') ^ $in; '.$encrypt_block.' $_ciphertext.= $in; } if ($this->continuousBuffer) { $this->encryptIV = $in; } return $_ciphertext; '; $decrypt = $init_decrypt.' $_plaintext = ""; $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0)); $_ciphertext_len = strlen($_text); $_iv = $this->decryptIV; for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') { $in = $_block = substr($_text, $_i, '.$block_size.'); '.$decrypt_block.' $_plaintext.= $in ^ $_iv; $_iv = $_block; } if ($this->continuousBuffer) { $this->decryptIV = $_iv; } return $this->unpad($_plaintext); '; break; } // Before discrediting this, please read the following: // @see https://github.com/phpseclib/phpseclib/issues/1293 // @see https://github.com/phpseclib/phpseclib/pull/1143 eval('$func = function ($_action, $_text) { '.$init_crypt.'if ($_action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }};'); return \Closure::bind($func, $this, static::class); } /** * Convert float to int * * On ARM CPUs converting floats to ints doesn't always work * * @access private * @param string $x * @return int */ protected static function safe_intval($x) { switch (true) { case is_int($x): // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding" case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM': return $x; } return (fmod($x, 0x80000000) & 0x7FFFFFFF) | ((fmod(floor($x / 0x80000000), 2) & 1) << 31); } /** * eval()'able string for in-line float to int * * @access private * @return string */ protected static function safe_intval_inline() { switch (true) { case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8: case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM': return '%s'; break; default: $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | '; return $safeint.'((fmod(floor($temp / 0x80000000), 2) & 1) << 31))'; } } /** * Sets up GCM parameters * * See steps 1-2 of https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=23 * for more info * * @access private */ private function setupGCM() { // don't keep on re-calculating $this->h if (!$this->h || $this->h->key != $this->key) { $cipher = new static('ecb'); $cipher->setKey($this->key); $cipher->disablePadding(); $this->h = self::$gcmField->newInteger( Strings::switchEndianness($cipher->encrypt("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")) ); $this->h->key = $this->key; } if (strlen($this->nonce) == 12) { $this->iv = $this->nonce."\0\0\0\1"; } else { $s = 16 * ceil(strlen($this->nonce) / 16) - strlen($this->nonce); $this->iv = $this->ghash( self::nullPad128($this->nonce).str_repeat("\0", 8).self::len64($this->nonce) ); } } /** * Performs GHASH operation * * See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=20 * for more info * * @see self::decrypt() * @see self::encrypt() * @access private * @param string $x * @return string */ private function ghash($x) { $h = $this->h; $y = ["\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"]; $x = str_split($x, 16); $n = 0; // the switchEndianness calls are necessary because the multiplication algorithm in BinaryField/Integer // interprets strings as polynomials in big endian order whereas in GCM they're interpreted in little // endian order per https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=19. // big endian order is what binary field elliptic curves use per http://www.secg.org/sec1-v2.pdf#page=18. // we could switchEndianness here instead of in the while loop but doing so in the while loop seems like it // might be slightly more performant //$x = Strings::switchEndianness($x); foreach ($x as $xn) { $xn = Strings::switchEndianness($xn); $t = $y[$n] ^ $xn; $temp = self::$gcmField->newInteger($t); $y[++$n] = $temp->multiply($h)->toBytes(); $y[$n] = substr($y[$n], 1); } $y[$n] = Strings::switchEndianness($y[$n]); return $y[$n]; } /** * Returns the bit length of a string in a packed format * * @see self::decrypt() * @see self::encrypt() * @see self::setupGCM() * @access private * @param string $str * @return string */ private static function len64($str) { return "\0\0\0\0".pack('N', 8 * strlen($str)); } /** * NULL pads a string to be a multiple of 128 * * @see self::decrypt() * @see self::encrypt() * @see self::setupGCM() * @access private * @param string $str * @return string */ protected static function nullPad128($str) { $len = strlen($str); return $str.str_repeat("\0", 16 * ceil($len / 16) - $len); } /** * Calculates Poly1305 MAC * * On my system ChaCha20, with libsodium, takes 0.5s. With this custom Poly1305 implementation * it takes 1.2s. * * @see self::decrypt() * @see self::encrypt() * @access private * @param string $text * @return string */ protected function poly1305($text) { $s = $this->poly1305Key; // strlen($this->poly1305Key) == 32 $r = Strings::shift($s, 16); $r = strrev($r); $r &= "\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xff"; $s = strrev($s); $r = self::$poly1305Field->newInteger(new BigInteger($r, 256)); $s = self::$poly1305Field->newInteger(new BigInteger($s, 256)); $a = self::$poly1305Field->newInteger(new BigInteger()); $blocks = str_split($text, 16); foreach ($blocks as $block) { $n = strrev($block.chr(1)); $n = self::$poly1305Field->newInteger(new BigInteger($n, 256)); $a = $a->add($n); $a = $a->multiply($r); } $r = $a->toBigInteger()->add($s->toBigInteger()); $mask = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; return strrev($r->toBytes()) & $mask; } } <?php /** * Base Class for all block ciphers * * PHP version 5 * * @category Crypt * @package BlockCipher * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; /** * Base Class for all block cipher classes * * @package BlockCipher * @author Jim Wigginton <terrafrost@php.net> */ abstract class BlockCipher extends SymmetricKey { } <?php /** * Base Class for all stream ciphers * * PHP version 5 * * @category Crypt * @package StreamCipher * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; /** * Base Class for all stream cipher classes * * @package StreamCipher * @author Jim Wigginton <terrafrost@php.net> */ abstract class StreamCipher extends SymmetricKey { } <?php /** * OpenSSH Key Handler * * PHP version 5 * * Place in $HOME/.ssh/authorized_keys * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Random; /** * OpenSSH Formatted RSA Key Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSH { /** * Default comment * * @var string * @access private */ protected static $comment = 'phpseclib-generated-key'; /** * Binary key flag * * @var bool * @access private */ protected static $binary = false; /** * Sets the default comment * * @access public * @param string $comment */ public static function setComment($comment) { self::$comment = str_replace(["\r", "\n"], '', $comment); } /** * Break a public or private key down into its constituent components * * $type can be either ssh-dss or ssh-rsa * * @access public * @param string $key * @param string $type * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } // key format is described here: // https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD if (strpos($key, 'BEGIN OPENSSH PRIVATE KEY') !== false) { $key = preg_replace('#(?:^-.*?-[\r\n]*$)|\s#ms', '', $key); $key = Base64::decode($key); $magic = Strings::shift($key, 15); if ($magic != "openssh-key-v1\0") { throw new \RuntimeException('Expected openssh-key-v1'); } list($ciphername, $kdfname, $kdfoptions, $numKeys) = Strings::unpackSSH2('sssN', $key); if ($numKeys != 1) { // if we wanted to support multiple keys we could update PublicKeyLoader to preview what the # of keys // would be; it'd then call Common\Keys\OpenSSH.php::load() and get the paddedKey. it'd then pass // that to the appropriate key loading parser $numKey times or something throw new \RuntimeException('Although the OpenSSH private key format supports multiple keys phpseclib does not'); } if (strlen($kdfoptions) || $kdfname != 'none' || $ciphername != 'none') { /* OpenSSH private keys use a customized version of bcrypt. specifically, instead of encrypting OrpheanBeholderScryDoubt 64 times OpenSSH's bcrypt variant encrypts OxychromaticBlowfishSwatDynamite 64 times. so we can't use crypt(). bcrypt is basically Blowfish with an altered key expansion. whereas Blowfish just runs the key through the key expansion bcrypt interleaves the key expansion with the salt and password. this renders openssl / mcrypt unusuable. this forces us to use a pure-PHP implementation of bcrypt. the problem with that is that pure-PHP is too slow to be practically useful. in addition to encrypting a different string 64 times the OpenSSH implementation also performs bcrypt from scratch $rounds times. calling crypt() 64x with bcrypt takes 0.7s. PHP is going to be naturally slower. pure-PHP is 215x slower than OpenSSL for AES and pure-PHP is 43x slower for bcrypt. 43 * 0.7 = 30s. no one wants to wait 30s to load a private key. another way to think about this.. according to wikipedia's article on Blowfish, "Each new key requires pre-processing equivalent to encrypting about 4 kilobytes of text". key expansion is done (9+64*2)*160 times. multiply that by 4 and it turns out that Blowfish, OpenSSH style, is the equivalent of encrypting ~80mb of text. more supporting evidence: sodium_compat does not implement Argon2 (another password hashing algorithm) because "It's not feasible to polyfill scrypt or Argon2 into PHP and get reasonable performance. Users would feel motivated to select parameters that downgrade security to avoid denial of service (DoS) attacks. The only winning move is not to play" -- https://github.com/paragonie/sodium_compat/blob/master/README.md */ throw new \RuntimeException('Encrypted OpenSSH private keys are not supported'); //list($salt, $rounds) = Strings::unpackSSH2('sN', $kdfoptions); } list($publicKey, $paddedKey) = Strings::unpackSSH2('ss', $key); list($type) = Strings::unpackSSH2('s', $publicKey); list($checkint1, $checkint2) = Strings::unpackSSH2('NN', $paddedKey); // any leftover bytes in $paddedKey are for padding? but they should be sequential bytes. eg. 1, 2, 3, etc. if ($checkint1 != $checkint2) { throw new \RuntimeException('The two checkints do not match'); } self::checkType($type); return compact('type', 'publicKey', 'paddedKey'); } $parts = explode(' ', $key, 3); if (!isset($parts[1])) { $key = base64_decode($parts[0]); $comment = isset($parts[1]) ? $parts[1] : false; } else { $asciiType = $parts[0]; self::checkType($parts[0]); $key = base64_decode($parts[1]); $comment = isset($parts[2]) ? $parts[2] : false; } if ($key === false) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } list($type) = Strings::unpackSSH2('s', $key); self::checkType($type); if (isset($asciiType) && $asciiType != $type) { throw new \RuntimeException('Two different types of keys are claimed: ' . $asciiType . ' and ' . $type); } if (strlen($key) <= 4) { throw new \UnexpectedValueException('Key appears to be malformed'); } $publicKey = $key; return compact('type', 'publicKey', 'comment'); } /** * Toggle between binary and printable keys * * Printable keys are what are generated by default. These are the ones that go in * $HOME/.ssh/authorized_key. * * @access public * @param bool $enabled */ public static function setBinaryOutput($enabled) { self::$binary = $enabled; } /** * Checks to see if the type is valid * * @access private * @param string $candidate */ private static function checkType($candidate) { if (!in_array($candidate, static::$types)) { throw new \RuntimeException('The key type is not equal to: ' . implode(',', static::$types)); } } /** * Wrap a private key appropriately * * @access public * @param string $publicKey * @param string $privateKey * @return string */ protected static function wrapPrivateKey($publicKey, $privateKey, $options) { list(, $checkint) = unpack('N', Random::string(4)); $comment = isset($options['comment']) ? $options['comment'] : self::$comment; $paddedKey = Strings::packSSH2('NN', $checkint, $checkint) . $privateKey . Strings::packSSH2('s', $comment); /* from http://tools.ietf.org/html/rfc4253#section-6 : Note that the length of the concatenation of 'packet_length', 'padding_length', 'payload', and 'random padding' MUST be a multiple of the cipher block size or 8, whichever is larger. */ $paddingLength = (7 * strlen($paddedKey)) % 8; for ($i = 1; $i <= $paddingLength; $i++) { $paddedKey.= chr($i); } $key = Strings::packSSH2('sssNss', 'none', 'none', '', 1, $publicKey, $paddedKey); $key = "openssh-key-v1\0$key"; return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" . chunk_split(Base64::encode($key), 70) . "-----END OPENSSH PRIVATE KEY-----"; } } <?php /** * PKCS#8 Formatted Key Handler * * PHP version 5 * * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set) * * Processes keys with the following headers: * * -----BEGIN ENCRYPTED PRIVATE KEY----- * -----BEGIN PRIVATE KEY----- * -----BEGIN PUBLIC KEY----- * * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 * is specific to private keys it's basically creating a DER-encoded wrapper * for keys. This just extends that same concept to public keys (much like ssh-keygen) * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Crypt\DES; use phpseclib\Crypt\RC2; use phpseclib\Crypt\RC4; use phpseclib\Crypt\AES; use phpseclib\Crypt\TripleDES; use phpseclib\Crypt\Random; use phpseclib\Math\BigInteger; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; use phpseclib\Exception\UnsupportedAlgorithmException; /** * PKCS#8 Formatted Key Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS8 extends PKCS { /** * Default encryption algorithm * * @var string * @access private */ private static $defaultEncryptionAlgorithm = 'id-PBES2'; /** * Default encryption scheme * * Only used when defaultEncryptionAlgorithm is id-PBES2 * * @var string * @access private */ private static $defaultEncryptionScheme = 'aes128-CBC-PAD'; /** * Default PRF * * Only used when defaultEncryptionAlgorithm is id-PBES2 * * @var string * @access private */ private static $defaultPRF = 'id-hmacWithSHA256'; /** * Default Iteration Count * * @var int * @access private */ private static $defaultIterationCount = 2048; /** * OIDs loaded * * @var bool * @access private */ private static $oidsLoaded = false; /** * Sets the default encryption algorithm * * @access public * @param string $algo */ public static function setEncryptionAlgorithm($algo) { self::$defaultEncryptionAlgorithm = $algo; } /** * Sets the default encryption algorithm for PBES2 * * @access public * @param string $algo */ public static function setEncryptionScheme($algo) { self::$defaultEncryptionScheme = $algo; } /** * Sets the iteration count * * @access public * @param int $count */ public static function setIterationCount($count) { self::$defaultIterationCount = $count; } /** * Sets the PRF for PBES2 * * @access public * @param string $algo */ public static function setPRF($algo) { self::$defaultPRF = $algo; } /** * Returns a SymmetricKey object based on a PBES1 $algo * * @return \phpseclib\Crypt\Common\SymmetricKey * @access public * @param string $algo */ private static function getPBES1EncryptionObject($algo) { $algo = preg_match('#^pbeWith(?:MD2|MD5|SHA1|SHA)And(.*?)-CBC$#', $algo, $matches) ? $matches[1] : substr($algo, 13); // strlen('pbeWithSHAAnd') == 13 switch ($algo) { case 'DES': $cipher = new DES('cbc'); break; case 'RC2': $cipher = new RC2('cbc'); break; case '3-KeyTripleDES': $cipher = new TripleDES('cbc'); break; case '2-KeyTripleDES': $cipher = new TripleDES('cbc'); $cipher->setKeyLength(128); break; case '128BitRC2': $cipher = new RC2('cbc'); $cipher->setKeyLength(128); break; case '40BitRC2': $cipher = new RC2('cbc'); $cipher->setKeyLength(40); break; case '128BitRC4': $cipher = new RC4(); $cipher->setKeyLength(128); break; case '40BitRC4': $cipher = new RC4(); $cipher->setKeyLength(40); break; default: throw new UnsupportedAlgorithmException("$algo is not a supported algorithm"); } return $cipher; } /** * Returns a hash based on a PBES1 $algo * * @return string * @access public * @param string $algo */ private static function getPBES1Hash($algo) { if (preg_match('#^pbeWith(MD2|MD5|SHA1|SHA)And.*?-CBC$#', $algo, $matches)) { return $matches[1] == 'SHA' ? 'sha1' : $matches[1]; } return 'sha1'; } /** * Returns a KDF baesd on a PBES1 $algo * * @return string * @access public * @param string $algo */ private static function getPBES1KDF($algo) { switch ($algo) { case 'pbeWithMD2AndDES-CBC': case 'pbeWithMD2AndRC2-CBC': case 'pbeWithMD5AndDES-CBC': case 'pbeWithMD5AndRC2-CBC': case 'pbeWithSHA1AndDES-CBC': case 'pbeWithSHA1AndRC2-CBC': return 'pbkdf1'; } return 'pkcs12'; } /** * Returns a SymmetricKey object baesd on a PBES2 $algo * * @return SymmetricKey * @access public * @param string $algo */ private static function getPBES2EncryptionObject($algo) { switch ($algo) { case 'desCBC': $cipher = new TripleDES('cbc'); break; case 'des-EDE3-CBC': $cipher = new TripleDES('cbc'); break; case 'rc2CBC': $cipher = new RC2('cbc'); // in theory this can be changed $cipher->setKeyLength(128); break; case 'rc5-CBC-PAD': throw new UnsupportedAlgorithmException('rc5-CBC-PAD is not supported for PBES2 PKCS#8 keys'); case 'aes128-CBC-PAD': case 'aes192-CBC-PAD': case 'aes256-CBC-PAD': $cipher = new AES('cbc'); $cipher->setKeyLength(substr($algo, 3, 3)); break; default: throw new UnsupportedAlgorithmException("$algo is not supported"); } return $cipher; } /** * Initialize static variables * * @access private */ private static function initialize_static_variables() { if (!static::$childOIDsLoaded) { ASN1::loadOIDs(is_array(static::OID_NAME) ? array_combine(static::OID_NAME, static::OID_VALUE) : [static::OID_NAME => static::OID_VALUE] ); static::$childOIDsLoaded = true; } if (!self::$oidsLoaded) { // from https://tools.ietf.org/html/rfc2898 ASN1::loadOIDs([ // PBES1 encryption schemes 'pbeWithMD2AndDES-CBC' => '1.2.840.113549.1.5.1', 'pbeWithMD2AndRC2-CBC' => '1.2.840.113549.1.5.4', 'pbeWithMD5AndDES-CBC' => '1.2.840.113549.1.5.3', 'pbeWithMD5AndRC2-CBC' => '1.2.840.113549.1.5.6', 'pbeWithSHA1AndDES-CBC'=> '1.2.840.113549.1.5.10', 'pbeWithSHA1AndRC2-CBC'=> '1.2.840.113549.1.5.11', // from PKCS#12: // https://tools.ietf.org/html/rfc7292 'pbeWithSHAAnd128BitRC4' => '1.2.840.113549.1.12.1.1', 'pbeWithSHAAnd40BitRC4' => '1.2.840.113549.1.12.1.2', 'pbeWithSHAAnd3-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.3', 'pbeWithSHAAnd2-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.4', 'pbeWithSHAAnd128BitRC2-CBC' => '1.2.840.113549.1.12.1.5', 'pbeWithSHAAnd40BitRC2-CBC' => '1.2.840.113549.1.12.1.6', 'id-PBKDF2' => '1.2.840.113549.1.5.12', 'id-PBES2' => '1.2.840.113549.1.5.13', 'id-PBMAC1' => '1.2.840.113549.1.5.14', // from PKCS#5 v2.1: // http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf 'id-hmacWithSHA1' => '1.2.840.113549.2.7', 'id-hmacWithSHA224' => '1.2.840.113549.2.8', 'id-hmacWithSHA256' => '1.2.840.113549.2.9', 'id-hmacWithSHA384'=> '1.2.840.113549.2.10', 'id-hmacWithSHA512'=> '1.2.840.113549.2.11', 'id-hmacWithSHA512-224'=> '1.2.840.113549.2.12', 'id-hmacWithSHA512-256'=> '1.2.840.113549.2.13', 'desCBC' => '1.3.14.3.2.7', 'des-EDE3-CBC' => '1.2.840.113549.3.7', 'rc2CBC' => '1.2.840.113549.3.2', 'rc5-CBC-PAD' => '1.2.840.113549.3.9', 'aes128-CBC-PAD' => '2.16.840.1.101.3.4.1.2', 'aes192-CBC-PAD'=> '2.16.840.1.101.3.4.1.22', 'aes256-CBC-PAD'=> '2.16.840.1.101.3.4.1.42' ]); self::$oidsLoaded = true; } } /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ protected static function load($key, $password = '') { self::initialize_static_variables(); if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } if (self::$format != self::MODE_DER) { $decoded = ASN1::extractBER($key); if ($decoded !== false) { $key = $decoded; } elseif (self::$format == self::MODE_PEM) { throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text'); } } $decoded = ASN1::decodeBER($key); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER'); } $meta = []; $decrypted = ASN1::asn1map($decoded[0], Maps\EncryptedPrivateKeyInfo::MAP); if (strlen($password) && is_array($decrypted)) { $algorithm = $decrypted['encryptionAlgorithm']['algorithm']; switch ($algorithm) { // PBES1 case 'pbeWithMD2AndDES-CBC': case 'pbeWithMD2AndRC2-CBC': case 'pbeWithMD5AndDES-CBC': case 'pbeWithMD5AndRC2-CBC': case 'pbeWithSHA1AndDES-CBC': case 'pbeWithSHA1AndRC2-CBC': case 'pbeWithSHAAnd3-KeyTripleDES-CBC': case 'pbeWithSHAAnd2-KeyTripleDES-CBC': case 'pbeWithSHAAnd128BitRC2-CBC': case 'pbeWithSHAAnd40BitRC2-CBC': case 'pbeWithSHAAnd128BitRC4': case 'pbeWithSHAAnd40BitRC4': $cipher = self::getPBES1EncryptionObject($algorithm); $hash = self::getPBES1Hash($algorithm); $kdf = self::getPBES1KDF($algorithm); $meta['meta']['algorithm'] = $algorithm; $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']); extract(ASN1::asn1map($temp[0], Maps\PBEParameter::MAP)); $iterationCount = (int) $iterationCount->toString(); $cipher->setPassword($password, $kdf, $hash, $salt, $iterationCount); $key = $cipher->decrypt($decrypted['encryptedData']); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER 2'); } break; case 'id-PBES2': $meta['meta']['algorithm'] = $algorithm; $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']); $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP); extract($temp); $cipher = self::getPBES2EncryptionObject($encryptionScheme['algorithm']); $meta['meta']['cipher'] = $encryptionScheme['algorithm']; $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']); $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP); extract($temp); if (!$cipher instanceof RC2) { $cipher->setIV($encryptionScheme['parameters']['octetString']); } else { $temp = ASN1::decodeBER($encryptionScheme['parameters']); extract(ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP)); $effectiveKeyLength = (int) $rc2ParametersVersion->toString(); switch ($effectiveKeyLength) { case 160: $effectiveKeyLength = 40; break; case 120: $effectiveKeyLength = 64; break; case 58: $effectiveKeyLength = 128; break; //default: // should be >= 256 } $cipher->setIV($iv); $cipher->setKeyLength($effectiveKeyLength); } $meta['meta']['keyDerivationFunc'] = $keyDerivationFunc['algorithm']; switch ($keyDerivationFunc['algorithm']) { case 'id-PBKDF2': $temp = ASN1::decodeBER($keyDerivationFunc['parameters']); $prf = ['algorithm' => 'id-hmacWithSHA1']; $params = ASN1::asn1map($temp[0], Maps\PBKDF2params::MAP); extract($params); $meta['meta']['prf'] = $prf['algorithm']; $hash = str_replace('-', '/', substr($prf['algorithm'], 11)); $params = [ $password, 'pbkdf2', $hash, $salt, (int) $iterationCount->toString() ]; if (isset($keyLength)) { $params[] = (int) $keyLength->toString(); } call_user_func_array([$cipher, 'setPassword'], $params); $key = $cipher->decrypt($decrypted['encryptedData']); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER 3'); } break; default: throw new UnsupportedAlgorithmException('Only PBKDF2 is supported for PBES2 PKCS#8 keys'); } break; case 'id-PBMAC1': //$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']); //$value = ASN1::asn1map($temp[0], Maps\PBMAC1params::MAP); // since i can't find any implementation that does PBMAC1 it is unsupported throw new UnsupportedAlgorithmException('Only PBES1 and PBES2 PKCS#8 keys are supported.'); // at this point we'll assume that the key conforms to PublicKeyInfo } } $private = ASN1::asn1map($decoded[0], Maps\OneAsymmetricKey::MAP); if (is_array($private)) { if (isset($private['privateKeyAlgorithm']['parameters']) && !$private['privateKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][1]['content'][1])) { $temp = $decoded[0]['content'][1]['content'][1]; $private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length'])); } if (is_array(static::OID_NAME)) { if (!in_array($private['privateKeyAlgorithm']['algorithm'], static::OID_NAME)) { throw new UnsupportedAlgorithmException($private['privateKeyAlgorithm']['algorithm'] . ' is not a supported key type'); } } else { if ($private['privateKeyAlgorithm']['algorithm'] != static::OID_NAME) { throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key'); } } if (isset($private['publicKey'])) { if ($private['publicKey'][0] != "\0") { throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($private['publicKey'][0])); } $private['publicKey'] = substr($private['publicKey'], 1); } return $private + $meta; } // EncryptedPrivateKeyInfo and PublicKeyInfo have largely identical "signatures". the only difference // is that the former has an octet string and the later has a bit string. the first byte of a bit // string represents the number of bits in the last byte that are to be ignored but, currently, // bit strings wanting a non-zero amount of bits trimmed are not supported $public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP); if (is_array($public)) { if ($public['publicKey'][0] != "\0") { throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($public['publicKey'][0])); } if (is_array(static::OID_NAME)) { if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) { throw new UnsupportedAlgorithmException($private['publicKeyAlgorithm']['algorithm'] . ' is not a supported key type'); } } else { if ($public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) { throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['publicKeyAlgorithm']['algorithm'] . ' key'); } } if (isset($public['publicKeyAlgorithm']['parameters']) && !$public['publicKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][0]['content'][1])) { $temp = $decoded[0]['content'][0]['content'][1]; $public['publicKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length'])); } $public['publicKey'] = substr($public['publicKey'], 1); return $public; } return false; } /** * Wrap a private key appropriately * * @access public * @param string $key * @param string $attr * @param mixed $params * @param string $password * @param string $oid optional * @param string $publicKey optional * @param array $options optional * @return string */ protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '', array $options = []) { self::initialize_static_variables(); $key = [ 'version' => 'v1', 'privateKeyAlgorithm' => [ 'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid, 'parameters' => $params ], 'privateKey' => $key ]; if (!empty($attr)) { $key['attributes'] = $attr; } if (!empty($publicKey)) { $key['version'] = 'v2'; $key['publicKey'] = $publicKey; } $key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP); if (!empty($password) && is_string($password)) { $salt = Random::string(8); $iterationCount = isset($options['iterationCount']) ? $options['iterationCount'] : self::$defaultIterationCount; $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm; $encryptionScheme = isset($options['encryptionScheme']) ? $options['encryptionScheme'] : self::$defaultEncryptionScheme; $prf = isset($options['PRF']) ? $options['PRF'] : self::$defaultPRF; if ($encryptionAlgorithm == 'id-PBES2') { $crypto = self::getPBES2EncryptionObject($encryptionScheme); $hash = str_replace('-', '/', substr($prf, 11)); $kdf = 'pbkdf2'; $iv = Random::string($crypto->getBlockLength() >> 3); $PBKDF2params = [ 'salt' => $salt, 'iterationCount' => $iterationCount, 'prf' => ['algorithm' => $prf, 'parameters' => null] ]; $PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP); if (!$crypto instanceof RC2) { $params = ['octetString' => $iv]; } else { $params = [ 'rc2ParametersVersion' => 58, 'iv' => $iv ]; $params = ASN1::encodeDER($params, Maps\RC2CBCParameter::MAP); $params = new ASN1\Element($params); } $params = [ 'keyDerivationFunc' => [ 'algorithm' => 'id-PBKDF2', 'parameters' => new ASN1\Element($PBKDF2params) ], 'encryptionScheme' => [ 'algorithm' => $encryptionScheme, 'parameters' => $params ] ]; $params = ASN1::encodeDER($params, Maps\PBES2params::MAP); $crypto->setIV($iv); } else { $crypto = self::getPBES1EncryptionObject($encryptionAlgorithm); $hash = self::getPBES1Hash($encryptionAlgorithm); $kdf = self::getPBES1KDF($encryptionAlgorithm); $params = [ 'salt' => $salt, 'iterationCount' => $iterationCount ]; $params = ASN1::encodeDER($params, Maps\PBEParameter::MAP); } $crypto->setPassword($password, $kdf, $hash, $salt, $iterationCount); $key = $crypto->encrypt($key); $key = [ 'encryptionAlgorithm' => [ 'algorithm' => $encryptionAlgorithm, 'parameters' => new ASN1\Element($params) ], 'encryptedData' => $key ]; $key = ASN1::encodeDER($key, Maps\EncryptedPrivateKeyInfo::MAP); return "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END ENCRYPTED PRIVATE KEY-----"; } return "-----BEGIN PRIVATE KEY-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END PRIVATE KEY-----"; } /** * Wrap a public key appropriately * * @access public * @param string $key * @param mixed $params * @return string */ protected static function wrapPublicKey($key, $params, $oid = null) { self::initialize_static_variables(); $key = [ 'publicKeyAlgorithm' => [ 'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid, 'parameters' => $params ], 'publicKey' => "\0" . $key ]; $key = ASN1::encodeDER($key, Maps\PublicKeyInfo::MAP); return "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END PUBLIC KEY-----"; } } <?php /** * PKCS1 Formatted Key Handler * * PHP version 5 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common\Keys; use ParagonIE\ConstantTime\Base64; use ParagonIE\ConstantTime\Hex; use phpseclib\Crypt\Random; use phpseclib\Crypt\AES; use phpseclib\Crypt\DES; use phpseclib\Crypt\TripleDES; use phpseclib\File\ASN1; use phpseclib\Exception\UnsupportedAlgorithmException; /** * PKCS1 Formatted Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS1 extends PKCS { /** * Default encryption algorithm * * @var string * @access private */ private static $defaultEncryptionAlgorithm = 'AES-128-CBC'; /** * Sets the default encryption algorithm * * @access public * @param string $algo */ public static function setEncryptionAlgorithm($algo) { self::$defaultEncryptionAlgorithm = $algo; } /** * Returns the mode constant corresponding to the mode string * * @access public * @param string $mode * @return int * @throws \UnexpectedValueException if the block cipher mode is unsupported */ private static function getEncryptionMode($mode) { switch ($mode) { case 'CBC': case 'ECB': case 'CFB': case 'OFB': case 'CTR': return $mode; } throw new \UnexpectedValueException('Unsupported block cipher mode of operation'); } /** * Returns a cipher object corresponding to a string * * @access public * @param string $algo * @return string * @throws \UnexpectedValueException if the encryption algorithm is unsupported */ private static function getEncryptionObject($algo) { $modes = '(CBC|ECB|CFB|OFB|CTR)'; switch (true) { case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches): $cipher = new AES(self::getEncryptionMode($matches[2])); $cipher->setKeyLength($matches[1]); return $cipher; case preg_match("#^DES-EDE3-$modes$#", $algo, $matches): return new TripleDES(self::getEncryptionMode($matches[1])); case preg_match("#^DES-$modes$#", $algo, $matches): return new DES(self::getEncryptionMode($matches[1])); default: throw new UnsupportedAlgorithmException($algo . ' is not a supported algorithm'); } } /** * Generate a symmetric key for PKCS#1 keys * * @access private * @param string $password * @param string $iv * @param int $length * @return string */ private static function generateSymmetricKey($password, $iv, $length) { $symkey = ''; $iv = substr($iv, 0, 8); while (strlen($symkey) < $length) { $symkey.= md5($symkey . $password . $iv, true); } return substr($symkey, 0, $length); } /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ protected static function load($key, $password) { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here: http://tools.ietf.org/html/rfc1421#section-4.6.1.1 http://tools.ietf.org/html/rfc1421#section-4.6.1.3 DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's own implementation. ie. the implementation *is* the standard and any bugs that may exist in that implementation are part of the standard, as well. * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { $iv = Hex::decode(trim($matches[2])); // remove the Proc-Type / DEK-Info sections as they're no longer needed $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key); $ciphertext = ASN1::extractBER($key); if ($ciphertext === false) { $ciphertext = $key; } $crypto = self::getEncryptionObject($matches[1]); $crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3)); $crypto->setIV($iv); $key = $crypto->decrypt($ciphertext); } else { if (self::$format != self::MODE_DER) { $decoded = ASN1::extractBER($key); if ($decoded !== false) { $key = $decoded; } elseif (self::$format == self::MODE_PEM) { throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text'); } } } return $key; } /** * Wrap a private key appropriately * * @access public * @param string $key * @param string $type * @param string $password * @param array $options optional * @return string */ protected static function wrapPrivateKey($key, $type, $password, array $options = []) { if (empty($password) || !is_string($password)) { return "-----BEGIN $type PRIVATE KEY-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END $type PRIVATE KEY-----"; } $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm; $cipher = self::getEncryptionObject($encryptionAlgorithm); $iv = Random::string($cipher->getBlockLength() >> 3); $cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3)); $cipher->setIV($iv); $iv = strtoupper(Hex::encode($iv)); return "-----BEGIN $type PRIVATE KEY-----\r\n" . "Proc-Type: 4,ENCRYPTED\r\n" . "DEK-Info: " . $encryptionAlgorithm. ",$iv\r\n" . "\r\n" . chunk_split(Base64::encode($cipher->encrypt($key)), 64) . "-----END $type PRIVATE KEY-----"; } /** * Wrap a public key appropriately * * @access public * @param string $key * @param string $type * @return string */ protected static function wrapPublicKey($key, $type) { return "-----BEGIN $type PUBLIC KEY-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END $type PUBLIC KEY-----"; } }<?php /** * PKCS Formatted Key Handler * * PHP version 5 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common\Keys; /** * PKCS1 Formatted Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS { /** * Auto-detect the format */ const MODE_ANY = 0; /** * Require base64-encoded PEM's be supplied */ const MODE_PEM = 1; /** * Require raw DER's be supplied */ const MODE_DER = 2; /**#@-*/ /** * Is the key a base-64 encoded PEM, DER or should it be auto-detected? * * @access private * @param int */ protected static $format = self::MODE_ANY; /** * Require base64-encoded PEM's be supplied * * @access public */ public static function requirePEM() { self::$format = self::MODE_PEM; } /** * Require raw DER's be supplied * * @access public */ public static function requireDER() { self::$format = self::MODE_DER; } /** * Accept any format and auto detect the format * * This is the default setting * * @access public */ public static function requireAny() { self::$format = self::MODE_ANY; } }<?php /** * PuTTY Formatted Key Handler * * PHP version 5 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common\Keys; use ParagonIE\ConstantTime\Base64; use ParagonIE\ConstantTime\Hex; use phpseclib\Crypt\AES; use phpseclib\Crypt\Hash; use phpseclib\Crypt\Random; use phpseclib\Common\Functions\Strings; use phpseclib\Exception\UnsupportedAlgorithmException; /** * PuTTY Formatted Key Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PuTTY { /** * Default comment * * @var string * @access private */ private static $comment = 'phpseclib-generated-key'; /** * Sets the default comment * * @access public * @param string $comment */ public static function setComment($comment) { self::$comment = str_replace(["\r", "\n"], '', $comment); } /** * Generate a symmetric key for PuTTY keys * * @access public * @param string $password * @param int $length * @return string */ private static function generateSymmetricKey($password, $length) { $symkey = ''; $sequence = 0; while (strlen($symkey) < $length) { $temp = pack('Na*', $sequence++, $password); $symkey.= Hex::decode(sha1($temp)); } return substr($symkey, 0, $length); } /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password * @return array */ protected static function load($key, $password) { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } if (strpos($key, 'BEGIN SSH2 PUBLIC KEY') !== false) { $data = preg_split('#[\r\n]+#', $key); $data = array_splice($data, 2, -1); $data = implode('', $data); $components = call_user_func([static::PUBLIC_HANDLER, 'load'], $data); if ($components === false) { throw new \UnexpectedValueException('Unable to decode public key'); } if (!preg_match('#Comment: "(.+)"#', $key, $matches)) { throw new \UnexpectedValueException('Key is missing a comment'); } $components['comment'] = str_replace(['\\\\', '\"'], ['\\', '"'], $matches[1]); return $components; } $components = []; $key = preg_split('#\r\n|\r|\n#', trim($key)); $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0])); $components['type'] = $type; if (!in_array($type, static::$types)) { $error = count(static::$types) == 1 ? 'Only ' . static::$types[0] . ' keys are supported. ' : ''; throw new UnsupportedAlgorithmException($error . 'This is an unsupported ' . $type . ' key'); } $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); $components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2])); $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); $public = Base64::decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); $source = Strings::packSSH2('ssss', $type, $encryption, $components['comment'], $public); extract(unpack('Nlength', Strings::shift($public, 4))); $newtype = Strings::shift($public, $length); if ($newtype != $type) { throw new \RuntimeException('The binary type does not match the human readable type field'); } $components['public'] = $public; $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4])); $private = Base64::decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength)))); switch ($encryption) { case 'aes256-cbc': $symkey = self::generateSymmetricKey($password, 32); $crypto = new AES('cbc'); } $hashkey = 'putty-private-key-file-mac-key'; if ($encryption != 'none') { $hashkey.= $password; $crypto->setKey($symkey); $crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3)); $crypto->disablePadding(); $private = $crypto->decrypt($private); } $source.= Strings::packSSH2('s', $private); $hash = new Hash('sha1'); $hash->setKey(sha1($hashkey, true)); $hmac = trim(preg_replace('#Private-MAC: (.+)#', '$1', $key[$publicLength + $privateLength + 5])); $hmac = Hex::decode($hmac); if (!hash_equals($hash->hash($source), $hmac)) { throw new \UnexpectedValueException('MAC validation error'); } $components['private'] = $private; return $components; } /** * Wrap a private key appropriately * * @access private * @param string $public * @param string $private * @param string $type * @param string $password * @param array $options optional * @return string */ protected static function wrapPrivateKey($public, $private, $type, $password, array $options = []) { $key = "PuTTY-User-Key-File-2: " . $type . "\r\nEncryption: "; $encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none'; $key.= $encryption; $key.= "\r\nComment: " . self::$comment . "\r\n"; $public = Strings::packSSH2('s', $type) . $public; $comment = isset($options['comment']) ? $options['comment'] : self::$comment; $source = Strings::packSSH2('ssss', $type, $encryption, $comment, $public); $public = Base64::encode($public); $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; $key.= chunk_split($public, 64); if (empty($password) && !is_string($password)) { $source.= Strings::packSSH2('s', $private); $hashkey = 'putty-private-key-file-mac-key'; } else { $private.= Random::string(16 - (strlen($private) & 15)); $source.= Strings::packSSH2('s', $private); $crypto = new AES('cbc'); $crypto->setKey(self::generateSymmetricKey($password, 32)); $crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3)); $crypto->disablePadding(); $private = $crypto->encrypt($private); $hashkey = 'putty-private-key-file-mac-key' . $password; } $private = Base64::encode($private); $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n"; $key.= chunk_split($private, 64); $hash = new Hash('sha1'); $hash->setKey(sha1($hashkey, true)); $key.= 'Private-MAC: ' . Hex::encode($hash->hash($source)) . "\r\n"; return $key; } /** * Wrap a public key appropriately * * This is basically the format described in RFC 4716 (https://tools.ietf.org/html/rfc4716) * * @access private * @param string $key * @param string $type * @return string */ protected static function wrapPublicKey($key, $type) { $key = pack('Na*a*', strlen($type), $type, $key); $key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" . 'Comment: "' . str_replace(['\\', '"'], ['\\\\', '\"'], self::$comment) . "\"\r\n" . chunk_split(Base64::encode($key), 64) . '---- END SSH2 PUBLIC KEY ----'; return $key; } } <?php /** * Base Class for all asymmetric key ciphers * * PHP version 5 * * @category Crypt * @package AsymmetricKey * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; use phpseclib\Exception\UnsupportedFormatException; use phpseclib\Exception\NoKeyLoadedException; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Hash; use phpseclib\Crypt\RSA; use phpseclib\Crypt\DSA; use phpseclib\Crypt\ECDSA; /** * Base Class for all stream cipher classes * * @package AsymmetricKey * @author Jim Wigginton <terrafrost@php.net> */ abstract class AsymmetricKey { /** * Precomputed Zero * * @var \phpseclib\Math\BigInteger * @access private */ protected static $zero; /** * Precomputed One * * @var \phpseclib\Math\BigInteger * @access private */ protected static $one; /** * Format of the loaded key * * @var string * @access private */ protected $format; /** * Hash function * * @var \phpseclib\Crypt\Hash * @access private */ protected $hash; /** * HMAC function * * @var \phpseclib\Crypt\Hash * @access private */ private $hmac; /** * Enable Blinding? * * @var bool * @access private */ protected static $enableBlinding = true; /** * Supported plugins (lower case) * * @see self::initialize_static_variables() * @var array * @access private */ private static $plugins = []; /** * Supported plugins (original case) * * @see self::initialize_static_variables() * @var array * @access private */ private static $origPlugins = []; /** * Supported signature formats (lower case) * * @see self::initialize_static_variables() * @var array * @access private */ private static $signatureFormats = []; /** * Supported signature formats (original case) * * @see self::initialize_static_variables() * @var array * @access private */ private static $signatureFileFormats = []; /** * Available Engines * * @var boolean[] * @access private */ protected static $engines = []; /** * The constructor */ protected function __construct() { self::initialize_static_variables(); $this->hash = new Hash('sha256'); $this->hmac = new Hash('sha256'); } /** * Initialize static variables */ protected static function initialize_static_variables() { if (!isset(self::$zero)) { self::$zero= new BigInteger(0); self::$one = new BigInteger(1); } self::loadPlugins('Keys'); if (static::ALGORITHM != 'RSA') { self::loadPlugins('Signature'); } } /** * Load the key * * @param string $key * @param string $type * @param string $password * @return array|bool */ protected static function load($key, $type, $password) { self::initialize_static_variables(); $components = false; if ($type === false) { foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) { try { $components = $format::load($key, $password); } catch (\Exception $e) { $components = false; } if ($components !== false) { break; } } } else { $format = strtolower($type); if (isset(self::$plugins[static::ALGORITHM]['Keys'][$format])) { $format = self::$plugins[static::ALGORITHM]['Keys'][$format]; $components = $format::load($key, $password); } } if ($components === false) { throw new NoKeyLoadedException('Unable to read key'); } $components['format'] = $format; return $components; } /** * Validate Plugin * * @access private * @param string $format * @param string $type * @param string $method optional * @return mixed */ protected static function validatePlugin($format, $type, $method = NULL) { $type = strtolower($type); if (!isset(self::$plugins[static::ALGORITHM][$format][$type])) { throw new UnsupportedFormatException("$type is not a supported format"); } $type = self::$plugins[static::ALGORITHM][$format][$type]; if (isset($method) && !method_exists($type, $method)) { throw new UnsupportedFormatException("$type does not implement $method"); } return $type; } /** * Load Plugins * * @access private * @param $format */ private static function loadPlugins($format) { if (!isset(self::$plugins[static::ALGORITHM][$format])) { self::$plugins[static::ALGORITHM][$format] = []; foreach (new \DirectoryIterator(__DIR__ . '/../' . static::ALGORITHM . '/' . $format . '/') as $file) { if ($file->getExtension() != 'php') { continue; } $name = $file->getBasename('.php'); $type = 'phpseclib\Crypt\\' . static::ALGORITHM . '\\' . $format . '\\' . $name; $reflect = new \ReflectionClass($type); if ($reflect->isTrait()) { continue; } self::$plugins[static::ALGORITHM][$format][strtolower($name)] = $type; self::$origPlugins[static::ALGORITHM][$format][] = $name; } } } /** * Returns a list of supported formats. * * @access public * @return array */ public static function getSupportedKeyFormats() { self::initialize_static_variables(); return self::$plugins[static::ALGORITHM]['Keys']; } /** * Add a fileformat plugin * * The plugin needs to either already be loaded or be auto-loadable. * Loading a plugin whose shortname overwrite an existing shortname will overwrite the old plugin. * * @see self::load() * @param string $fullname * @access public * @return bool */ public static function addFileFormat($fullname) { self::initialize_static_variables(); if (class_exists($fullname)) { $meta = new \ReflectionClass($fullname); $shortname = $meta->getShortName(); self::$plugins[static::ALGORITHM]['Keys'][strtolower($shortname)] = $fullname; self::$origPlugins[static::ALGORITHM]['Keys'][] = $shortname; } } /** * Returns the format of the loaded key. * * If the key that was loaded wasn't in a valid or if the key was auto-generated * with RSA::createKey() then this will return false. * * @see self::load() * @access public * @return mixed */ public function getLoadedFormat() { if ($this->format === false) { return false; } $meta = new \ReflectionClass($this->format); return $meta->getShortName(); } /** * Tests engine validity * * @access public * @param int $val */ public static function useBestEngine() { static::$engines = [ 'PHP' => true, 'OpenSSL' => extension_loaded('openssl'), // this test can be satisfied by either of the following: // http://php.net/manual/en/book.sodium.php // https://github.com/paragonie/sodium_compat 'libsodium' => function_exists('sodium_crypto_sign_keypair') ]; return static::$engines; } /** * Flag to use internal engine only (useful for unit testing) * * @access public */ public static function useInternalEngine() { static::$engines = [ 'PHP' => true, 'OpenSSL' => false, 'libsodium' => false ]; } /** * __toString() magic method * * @return string */ public function __toString() { return $this->toString('PKCS8'); } /** * Determines which hashing function should be used * * @access public * @param string $hash */ public function withHash($hash) { $new = clone $this; $new->hash = new Hash($hash); $new->hmac = new Hash($hash); return $new; } /** * Compute the pseudorandom k for signature generation, * using the process specified for deterministic DSA. * * @access public * @param string $h1 * @return string */ protected function computek($h1) { $v = str_repeat("\1", strlen($h1)); $k = str_repeat("\0", strlen($h1)); $x = $this->int2octets($this->x); $h1 = $this->bits2octets($h1); $this->hmac->setKey($k); $k = $this->hmac->hash($v . "\0" . $x . $h1); $this->hmac->setKey($k); $v = $this->hmac->hash($v); $k = $this->hmac->hash($v . "\1" . $x . $h1); $this->hmac->setKey($k); $v = $this->hmac->hash($v); $qlen = $this->q->getLengthInBytes(); while (true) { $t = ''; while (strlen($t) < $qlen) { $v = $this->hmac->hash($v); $t = $t . $v; } $k = $this->bits2int($t); if (!$k->equals(self::$zero) && $k->compare($this->q) < 0) { break; } $k = $this->hmac->hash($v . "\0"); $this->hmac->setKey($k); $v = $this->hmac->hash($v); } return $k; } /** * Integer to Octet String * * @access private * @param \phpseclib\Math\BigInteger $v * @return string */ private function int2octets($v) { $out = $v->toBytes(); $rolen = $this->q->getLengthInBytes(); if (strlen($out) < $rolen) { return str_pad($out, $rolen, "\0", STR_PAD_LEFT); } else if (strlen($out) > $rolen) { return substr($out, -$rolen); } else { return $out; } } /** * Bit String to Integer * * @access private * @param string $in * @return \phpseclib\Math\BigInteger */ protected function bits2int($in) { $v = new BigInteger($in, 256); $vlen = strlen($in) << 3; $qlen = $this->q->getLength(); if ($vlen > $qlen) { return $v->bitwise_rightShift($vlen - $qlen); } return $v; } /** * Bit String to Octet String * * @access private * @param string $in * @return string */ private function bits2octets($in) { $z1 = $this->bits2int($in); $z2 = $z1->subtract($this->q); return $z2->compare(self::$zero) < 0 ? $this->int2octets($z1) : $this->int2octets($z2); } } <?php /** * PublicKey interface * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common; /** * PublicKey interface * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ interface PublicKey { public function verify($message, $signature); //public function encrypt($plaintext); public function toString($type, array $options = []); public function getFingerprint($algorithm); } <?php /** * Raw Signature Handler * * PHP version 5 * * Handles signatures as arrays * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\Common\Signature; use phpseclib\Math\BigInteger; /** * Raw Signature Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Raw { /** * Loads a signature * * @access public * @param array $sig * @return array|bool */ public static function load($sig) { switch (true) { case !is_array($sig): case !isset($sig['r']) || !isset($sig['s']): case !$sig['r'] instanceof BigInteger: case !$sig['s'] instanceof BigInteger: return false; } return [ 'r' => $sig['r'], 's' => $sig['s'] ]; } /** * Returns a signature in the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $r * @param \phpseclib\Math\BigInteger $s * @return string */ public static function save(BigInteger $r, BigInteger $s) { return compact('r', 's'); } } <?php /** * DSA Private Key * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA; use phpseclib\Crypt\DSA; use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common; /** * DSA Private Key * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PrivateKey extends DSA implements Common\PrivateKey { use Common\PasswordProtected; /** * DSA secret exponent x * * @var \phpseclib\Math\BigInteger * @access private */ protected $x; /** * Returns the public key * * If you do "openssl rsa -in private.rsa -pubout -outform PEM" you get a PKCS8 formatted key * that contains a publicKeyAlgorithm AlgorithmIdentifier and a publicKey BIT STRING. * An AlgorithmIdentifier contains an OID and a parameters field. With RSA public keys this * parameters field is NULL. With DSA PKCS8 public keys it is not - it contains the p, q and g * variables. The publicKey BIT STRING contains, simply, the y variable. This can be verified * by getting a DSA PKCS8 public key: * * "openssl dsa -in private.dsa -pubout -outform PEM" * * ie. just swap out rsa with dsa in the rsa command above. * * A PKCS1 public key corresponds to the publicKey portion of the PKCS8 key. In the case of RSA * the publicKey portion /is/ the key. In the case of DSA it is not. You cannot verify a signature * without the parameters and the PKCS1 DSA public key format does not include the parameters. * * @see self::getPrivateKey() * @access public * @param string $type optional * @return mixed */ public function getPublicKey() { $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey'); if (!isset($this->y)) { $this->y = $this->g->powMod($this->x, $this->p); } $key = $type::savePublicKey($this->p, $this->q, $this->g, $this->y); return DSA::load($key, 'PKCS8') ->withHash($this->hash->getHash()) ->withSignatureFormat($this->shortFormat); } /** * Create a signature * * @see self::verify() * @access public * @param string $message * @return mixed */ public function sign($message) { $format = $this->format; if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { $signature = ''; $result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash()); if ($result) { if ($this->shortFormat == 'ASN1') { return $signature; } extract(ASN1Signature::load($signature)); return $format::save($r, $s); } } $h = $this->hash->hash($message); $h = $this->bits2int($h); while (true) { $k = BigInteger::randomRange(self::$one, $this->q->subtract(self::$one)); $r = $this->g->powMod($k, $this->p); list(, $r) = $r->divide($this->q); if ($r->equals(self::$zero)) { continue; } $kinv = $k->modInverse($this->q); $temp = $h->add($this->x->multiply($r)); $temp = $kinv->multiply($temp); list(, $s) = $temp->divide($this->q); if (!$s->equals(self::$zero)) { break; } } // the following is an RFC6979 compliant implementation of deterministic DSA // it's unused because it's mainly intended for use when a good CSPRNG isn't // available. if phpseclib's CSPRNG isn't good then even key generation is // suspect /* $h1 = $this->hash->hash($message); $k = $this->computek($h1); $r = $this->g->powMod($k, $this->p); list(, $r) = $r->divide($this->q); $kinv = $k->modInverse($this->q); $h1 = $this->bits2int($h1); $temp = $h1->add($this->x->multiply($r)); $temp = $kinv->multiply($temp); list(, $s) = $temp->divide($this->q); */ return $format::save($r, $s); } /** * Returns the private key * * @param string $type * @param array $options optional * @return string */ public function toString($type, array $options = []) { $type = self::validatePlugin('Keys', $type, 'savePrivateKey'); if (!isset($this->y)) { $this->y = $this->g->powMod($this->x, $this->p); } return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password, $options); } } <?php /** * Raw DSA Key Handler * * PHP version 5 * * Reads and creates arrays as DSA keys * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Keys; use phpseclib\Math\BigInteger; /** * Raw DSA Key Handler * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Raw { /** * Break a public or private key down into its constituent components * * @access public * @param array $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_array($key)) { throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key)); } switch (true) { case !isset($key['p']) || !isset($key['q']) || !isset($key['g']): case !$key['p'] instanceof BigInteger: case !$key['q'] instanceof BigInteger: case !$key['g'] instanceof BigInteger: case !isset($key['x']) && !isset($key['y']): case isset($key['x']) && !$key['x'] instanceof BigInteger: case isset($key['y']) && !$key['y'] instanceof BigInteger: throw new \UnexpectedValueException('Key appears to be malformed'); } $options = ['p' => 1, 'q' => 1, 'g' => 1, 'x' => 1, 'y' => 1]; return array_intersect_key($key, $options); } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $x * @param string $password optional * @return string */ public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '') { return compact('p', 'q', 'g', 'y', 'x'); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @return string */ public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y) { return compact('p', 'q', 'g', 'y'); } } <?php /** * XML Formatted DSA Key Handler * * While XKMS defines a private key format for RSA it does not do so for DSA. Quoting that standard: * * "[XKMS] does not specify private key parameters for the DSA signature algorithm since the algorithm only * supports signature modes and so the application of server generated keys and key recovery is of limited * value" * * PHP version 5 * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; /** * XML Formatted DSA Key Handler * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class XML { /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $use_errors = libxml_use_internal_errors(true); $dom = new \DOMDocument(); if (substr($key, 0, 5) != '<?xml') { $key = '<xml>' . $key . '</xml>'; } if (!$dom->loadXML($key)) { throw new \UnexpectedValueException('Key does not appear to contain XML'); } $xpath = new \DOMXPath($dom); $keys = ['p', 'q', 'g', 'y', 'j', 'seed', 'pgencounter']; foreach ($keys as $key) { // $dom->getElementsByTagName($key) is case-sensitive $temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']"); if (!$temp->length) { continue; } $value = new BigInteger(Base64::decode($temp->item(0)->nodeValue), 256); switch ($key) { case 'p': // a prime modulus meeting the [DSS] requirements // Parameters P, Q, and G can be public and common to a group of users. They might be known // from application context. As such, they are optional but P and Q must either both appear // or both be absent $components['p'] = $value; break; case 'q': // an integer in the range 2**159 < Q < 2**160 which is a prime divisor of P-1 $components['q'] = $value; break; case 'g': // an integer with certain properties with respect to P and Q $components['g'] = $value; break; case 'y': // G**X mod P (where X is part of the private key and not made public) $components['y'] = $value; // the remaining options do not do anything case 'j': // (P - 1) / Q // Parameter J is available for inclusion solely for efficiency as it is calculatable from // P and Q case 'seed': // a DSA prime generation seed // Parameters seed and pgenCounter are used in the DSA prime number generation algorithm // specified in [DSS]. As such, they are optional but must either both be present or both // be absent case 'pgencounter': // a DSA prime generation counter } } libxml_use_internal_errors($use_errors); if (!isset($components['y'])) { throw new \UnexpectedValueException('Key is missing y component'); } switch (true) { case !isset($components['p']): case !isset($components['q']): case !isset($components['g']): return ['y' => $components['y']]; } return $components; } /** * Convert a public key to the appropriate format * * See https://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @return string */ public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y) { return "<DSAKeyValue>\r\n" . ' <P>' . Base64::encode($p->toBytes()) . "</P>\r\n" . ' <Q>' . Base64::encode($q->toBytes()) . "</Q>\r\n" . ' <G>' . Base64::encode($g->toBytes()) . "</G>\r\n" . ' <Y>' . Base64::encode($y->toBytes()) . "</Y>\r\n" . '</DSAKeyValue>'; } } <?php /** * OpenSSH Formatted DSA Key Handler * * PHP version 5 * * Place in $HOME/.ssh/authorized_keys * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Keys; use ParagonIE\ConstantTime\Base64; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\OpenSSH as Progenitor; /** * OpenSSH Formatted DSA Key Handler * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSH extends Progenitor { /** * Supported Key Types * * @var array */ protected static $types = ['ssh-dss']; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { $parsed = parent::load($key, $password); if (isset($parsed['paddedKey'])) { list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']); if ($type != $parsed['type']) { throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])"); } list($p, $q, $g, $y, $x, $comment) = Strings::unpackSSH2('i5s', $parsed['paddedKey']); return compact('p', 'q', 'g', 'y', 'x', 'comment'); } list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $parsed['publicKey']); $comment = $parsed['comment']; return compact('p', 'q', 'g', 'y', 'comment'); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @param array $options optional * @return string */ public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = []) { if ($q->getLength() != 160) { throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160'); } // from <http://tools.ietf.org/html/rfc4253#page-15>: // string "ssh-dss" // mpint p // mpint q // mpint g // mpint y $DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y); if (isset($options['binary']) ? $options['binary'] : self::$binary) { return $DSAPublicKey; } $comment = isset($options['comment']) ? $options['comment'] : self::$comment; $DSAPublicKey = 'ssh-dss ' . base64_encode($DSAPublicKey) . ' ' . $comment; return $DSAPublicKey; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $y * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = []) { $publicKey = self::savePublicKey($p, $q, $g, $y, ['binary' => true]); $privateKey = Strings::packSSH2('si5', 'ssh-dss', $p, $q, $g, $y, $x); return self::wrapPrivateKey($publicKey, $privateKey, $options); } } <?php /** * PKCS#8 Formatted DSA Key Handler * * PHP version 5 * * Processes keys with the following headers: * * -----BEGIN ENCRYPTED PRIVATE KEY----- * -----BEGIN PRIVATE KEY----- * -----BEGIN PUBLIC KEY----- * * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8 * is specific to private keys it's basically creating a DER-encoded wrapper * for keys. This just extends that same concept to public keys (much like ssh-keygen) * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; /** * PKCS#8 Formatted DSA Key Handler * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS8 extends Progenitor { /** * OID Name * * @var string * @access private */ const OID_NAME = 'id-dsa'; /** * OID Value * * @var string * @access private */ const OID_VALUE = '1.2.840.10040.4.1'; /** * Child OIDs loaded * * @var bool * @access private */ protected static $childOIDsLoaded = false; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { if (!is_string($key)) { throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key)); } $isPublic = strpos($key, 'PUBLIC') !== false; $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; switch (true) { case !$isPublic && $type == 'publicKey': throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key'); case $isPublic && $type == 'privateKey': throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); } $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER of parameters'); } $components = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP); if (!is_array($components)) { throw new \RuntimeException('Unable to perform ASN1 mapping on parameters'); } $decoded = ASN1::decodeBER($key[$type]); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER'); } $var = $type == 'privateKey' ? 'x' : 'y'; $components[$var] = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP); if (!$components[$var] instanceof BigInteger) { throw new \RuntimeException('Unable to perform ASN1 mapping'); } if (isset($key['meta'])) { $components['meta'] = $key['meta']; } return $components; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $y * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = []) { $params = [ 'p' => $p, 'q' => $q, 'g' => $g ]; $params = ASN1::encodeDER($params, Maps\DSAParams::MAP); $params = new ASN1\Element($params); $key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP); return self::wrapPrivateKey($key, [], $params, $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @param array $options optional * @return string */ public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = []) { $params = [ 'p' => $p, 'q' => $q, 'g' => $g ]; $params = ASN1::encodeDER($params, Maps\DSAParams::MAP); $params = new ASN1\Element($params); $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP); return self::wrapPublicKey($key, $params); } } <?php /** * PKCS#1 Formatted DSA Key Handler * * PHP version 5 * * Used by File/X509.php * * Processes keys with the following headers: * * -----BEGIN DSA PRIVATE KEY----- * -----BEGIN DSA PUBLIC KEY----- * -----BEGIN DSA PARAMETERS----- * * Analogous to ssh-keygen's pem format (as specified by -m) * * Also, technically, PKCS1 decribes RSA but I am not aware of a formal specification for DSA. * The DSA private key format seems to have been adapted from the RSA private key format so * we're just re-using that as the name. * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Crypt\Common\Keys\PKCS1 as Progenitor; use phpseclib\File\ASN1; use phpseclib\File\ASN1\Maps; use ParagonIE\ConstantTime\Base64; /** * PKCS#1 Formatted DSA Key Handler * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS1 extends Progenitor { /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { $key = parent::load($key, $password); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { throw new \RuntimeException('Unable to decode BER'); } $key = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP); if (is_array($key)) { return $key; } $key = ASN1::asn1map($decoded[0], Maps\DSAPrivateKey::MAP); if (is_array($key)) { return $key; } $key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP); if (is_array($key)) { return $key; } throw new \RuntimeException('Unable to perform ASN1 mapping'); } /** * Convert DSA parameters to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @return string */ public static function saveParameters(BigInteger $p, BigInteger $q, BigInteger $g) { $key = [ 'p' => $p, 'q' => $q, 'g' => $g ]; $key = ASN1::encodeDER($key, Maps\DSAParams::MAP); return "-----BEGIN DSA PARAMETERS-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END DSA PARAMETERS-----\r\n"; } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $y * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = []) { $key = [ 'version' => 0, 'p' => $p, 'q' => $q, 'g' => $g, 'y' => $y, 'x' => $x ]; $key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP); return self::wrapPrivateKey($key, 'DSA', $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @return string */ public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y) { $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP); return self::wrapPublicKey($key, 'DSA'); } } <?php /** * PuTTY Formatted DSA Key Handler * * puttygen does not generate DSA keys with an N of anything other than 160, however, * it can still load them and convert them. PuTTY will load them, too, but SSH servers * won't accept them. Since PuTTY formatted keys are primarily used with SSH this makes * keys with N > 160 kinda useless, hence this handlers not supporting such keys. * * PHP version 5 * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Keys; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\PuTTY as Progenitor; /** * PuTTY Formatted DSA Key Handler * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PuTTY extends Progenitor { /** * Public Handler * * @var string * @access private */ const PUBLIC_HANDLER = 'phpseclib\Crypt\DSA\Keys\OpenSSH'; /** * Algorithm Identifier * * @var array * @access private */ protected static $types = ['ssh-dss']; /** * Break a public or private key down into its constituent components * * @access public * @param string $key * @param string $password optional * @return array */ public static function load($key, $password = '') { $components = parent::load($key, $password); if (!isset($components['private'])) { return $components; } extract($components); unset($components['public'], $components['private']); list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $public); list($x) = Strings::unpackSSH2('i', $private); return compact('p', 'q', 'g', 'y', 'x', 'comment'); } /** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $x * @param string $password optional * @param array $options optional * @return string */ public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = false, array $options = []) { if ($q->getLength() != 160) { throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160'); } $public = Strings::packSSH2('iiii', $p, $q, $g, $y); $private = Strings::packSSH2('i', $x); return self::wrapPrivateKey($public, $private, 'ssh-dsa', $password, $options); } /** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $p * @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $y * @return string */ public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y) { if ($q->getLength() != 160) { throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160'); } return self::wrapPublicKey(Strings::packSSH2('iiii', $p, $q, $g, $y), 'ssh-dsa'); } } <?php /** * DSA Parameters * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA; use phpseclib\Crypt\DSA; /** * DSA Parameters * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Parameters extends DSA { /** * Returns the parameters * * @param string $type * @param array $options optional * @return string */ public function toString($type = 'PKCS1', array $options = []) { $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters'); return $type::saveParameters($this->p, $this->q, $this->g, $options); } } <?php /** * DSA Public Key * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA; use phpseclib\Crypt\DSA; use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature; use phpseclib\Crypt\Common; /** * DSA Public Key * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PublicKey extends DSA implements Common\PublicKey { use Common\Fingerprint; /** * Verify a signature * * @see self::verify() * @access public * @param string $message * @param string $signature * @param string $format optional * @return mixed */ public function verify($message, $signature) { $format = $this->format; $params = $format::load($signature); if ($params === false || count($params) != 2) { return false; } extract($params); if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; $result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash()); if ($result != -1) { return (bool) $result; } } $q_1 = $this->q->subtract(self::$one); if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) { return false; } $w = $s->modInverse($this->q); $h = $this->hash->hash($message); $h = $this->bits2int($h); list(, $u1) = $h->multiply($w)->divide($this->q); list(, $u2) = $r->multiply($w)->divide($this->q); $v1 = $this->g->powMod($u1, $this->p); $v2 = $this->y->powMod($u2, $this->p); list(, $v) = $v1->multiply($v2)->divide($this->p); list(, $v) = $v->divide($this->q); return $v->equals($r); } /** * Returns the public key * * @param string $type * @param array $options optional * @return string */ public function toString($type, array $options = []) { $type = self::validatePlugin('Keys', $type, 'savePublicKey'); return $type::savePublicKey($this->p, $this->q, $this->g, $this->y, $options); } } <?php /** * SSH2 Signature Handler * * PHP version 5 * * Handles signatures in the format used by SSH2 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Signature; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; /** * SSH2 Signature Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SSH2 { /** * Loads a signature * * @access public * @param string $sig * @return mixed */ public static function load($sig) { if (!is_string($sig)) { return false; } $result = Strings::unpackSSH2('ss', $sig); if ($result === false) { return false; } list($type, $blob) = $result; if ($type != 'ssh-dss' || strlen($blob) != 40) { return false; } return [ 'r' => new BigInteger(substr($blob, 0, 20), 256), 's' => new BigInteger(substr($blob, 20), 256) ]; } /** * Returns a signature in the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $r * @param \phpseclib\Math\BigInteger $s * @return string */ public static function save(BigInteger $r, BigInteger $s) { if ($r->getLength() > 160 || $s->getLength() > 160) { return false; } return Strings::packSSH2('ss', 'ssh-dss', str_pad($r->toBytes(), 20, "\0", STR_PAD_LEFT) . str_pad($s->toBytes(), 20, "\0", STR_PAD_LEFT) ); } } <?php /** * Raw DSA Signature Handler * * PHP version 5 * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Signature; use phpseclib\Crypt\Common\Signature\Raw as Progenitor; /** * Raw DSA Signature Handler * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Raw extends Progenitor { } <?php /** * ASN1 Signature Handler * * PHP version 5 * * Handles signatures in the format described in * https://tools.ietf.org/html/rfc3279#section-2.2.2 * * @category Crypt * @package Common * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt\DSA\Signature; use phpseclib\Math\BigInteger; use phpseclib\File\ASN1 as Encoder; use phpseclib\File\ASN1\Maps; /** * ASN1 Signature Handler * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ASN1 { /** * Loads a signature * * @access public * @param string $sig * @return array|bool */ public static function load($sig) { if (!is_string($sig)) { return false; } $decoded = Encoder::decodeBER($sig); if (empty($decoded)) { return false; } $components = Encoder::asn1map($decoded[0], Maps\DssSigValue::MAP); return $components; } /** * Returns a signature in the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $r * @param \phpseclib\Math\BigInteger $s * @return string */ public static function save(BigInteger $r, BigInteger $s) { return ASN1::encodeDER(compact('r', 's'), Maps\DssSigValue::MAP); } } <?php /** * Pure-PHP implementation of Blowfish. * * Uses mcrypt, if available, and an internal implementation, otherwise. * * PHP version 5 * * Useful resources are as follows: * * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish} * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $blowfish = new \phpseclib\Crypt\Blowfish(); * * $blowfish->setKey('12345678901234567890123456789012'); * * $plaintext = str_repeat('a', 1024); * * echo $blowfish->decrypt($blowfish->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package Blowfish * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\BlockCipher; /** * Pure-PHP implementation of Blowfish. * * @package Blowfish * @author Jim Wigginton <terrafrost@php.net> * @author Hans-Juergen Petrich <petrich@tronic-media.com> * @access public */ class Blowfish extends BlockCipher { /** * Block Length of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::block_size * @var int * @access private */ protected $block_size = 8; /** * The mcrypt specific name of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @var string * @access private */ protected $cipher_name_mcrypt = 'blowfish'; /** * Optimizing value while CFB-encrypting * * @see \phpseclib\Crypt\Common\SymmetricKey::cfb_init_len * @var int * @access private */ protected $cfb_init_len = 500; /** * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each * * S-Box 0 * * @access private * @var array */ private static $sbox0 = [ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ]; /** * S-Box 1 * * @access private * @var array */ private static $sbox1 = [ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ]; /** * S-Box 2 * * @access private * @var array */ private static $sbox2 = [ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ]; /** * S-Box 3 * * @access private * @var array */ private static $sbox3 = [ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ]; /** * P-Array consists of 18 32-bit subkeys * * @var array * @access private */ private static $parray = [ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b ]; /** * The BCTX-working Array * * Holds the expanded key [p] and the key-depended s-boxes [sb] * * @var array * @access private */ private $bctx; /** * Holds the last used key * * @var array * @access private */ private $kl; /** * The Key Length (in bytes) * * @see \phpseclib\Crypt\Common\SymmetricKey::setKeyLength() * @var int * @access private * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. */ protected $key_length = 16; /** * Default Constructor. * * @param int $mode * @access public * @throws \InvalidArgumentException if an invalid / unsupported mode is provided */ public function __construct($mode) { if ($mode == self::MODE_STREAM) { throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode'); } parent::__construct($mode); } /** * Sets the key length. * * Key lengths can be between 32 and 448 bits. * * @access public * @param int $length */ public function setKeyLength($length) { if ($length < 32 || $length > 448) { throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes between 32 and 448 bits are supported'); } $this->key_length = $length >> 3; parent::setKeyLength($length); } /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { if ($engine == self::ENGINE_OPENSSL) { if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) { return false; } if ($this->key_length < 16) { return false; } self::$cipher_name_openssl_ecb = 'bf-ecb'; $this->cipher_name_openssl = 'bf-' . $this->openssl_translate_mode(); } return parent::isValidEngineHelper($engine); } /** * Setup the key (expansion) * * @see \phpseclib\Crypt\Common\SymmetricKey::_setupKey() * @access private */ protected function setupKey() { if (isset($this->kl['key']) && $this->key === $this->kl['key']) { // already expanded return; } $this->kl = ['key' => $this->key]; /* key-expanding p[] and S-Box building sb[] */ $this->bctx = [ 'p' => [], 'sb' => [ self::$sbox0, self::$sbox1, self::$sbox2, self::$sbox3 ] ]; // unpack binary string in unsigned chars $key = array_values(unpack('C*', $this->key)); $keyl = count($key); for ($j = 0, $i = 0; $i < 18; ++$i) { // xor P1 with the first 32-bits of the key, xor P2 with the second 32-... for ($data = 0, $k = 0; $k < 4; ++$k) { $data = ($data << 8) | $key[$j]; if (++$j >= $keyl) { $j = 0; } } $this->bctx['p'][] = self::$parray[$i] ^ $data; } // encrypt the zero-string, replace P1 and P2 with the encrypted data, // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys $data = "\0\0\0\0\0\0\0\0"; for ($i = 0; $i < 18; $i += 2) { list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data))); $this->bctx['p'][$i ] = $l; $this->bctx['p'][$i + 1] = $r; } for ($i = 0; $i < 4; ++$i) { for ($j = 0; $j < 256; $j += 2) { list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data))); $this->bctx['sb'][$i][$j ] = $l; $this->bctx['sb'][$i][$j + 1] = $r; } } } /** * Encrypts a block * * @access private * @param string $in * @return string */ protected function encryptBlock($in) { $p = $this->bctx['p']; // extract($this->bctx['sb'], EXTR_PREFIX_ALL, 'sb'); // slower $sb_0 = $this->bctx['sb'][0]; $sb_1 = $this->bctx['sb'][1]; $sb_2 = $this->bctx['sb'][2]; $sb_3 = $this->bctx['sb'][3]; $in = unpack('N*', $in); $l = $in[1]; $r = $in[2]; for ($i = 0; $i < 16; $i+= 2) { $l^= $p[$i]; $r^= self::safe_intval((self::safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]); $r^= $p[$i + 1]; $l^= self::safe_intval((self::safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]); } return pack('N*', $r ^ $p[17], $l ^ $p[16]); } /** * Decrypts a block * * @access private * @param string $in * @return string */ protected function decryptBlock($in) { $p = $this->bctx['p']; $sb_0 = $this->bctx['sb'][0]; $sb_1 = $this->bctx['sb'][1]; $sb_2 = $this->bctx['sb'][2]; $sb_3 = $this->bctx['sb'][3]; $in = unpack('N*', $in); $l = $in[1]; $r = $in[2]; for ($i = 17; $i > 2; $i-= 2) { $l^= $p[$i]; $r^= self::safe_intval((self::safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]); $r^= $p[$i - 1]; $l^= self::safe_intval((self::safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]); } return pack('N*', $r ^ $p[0], $l ^ $p[1]); } /** * Setup the performance-optimized function for de/encrypt() * * @see \phpseclib\Crypt\Common\SymmetricKey::_setupInlineCrypt() * @access private */ protected function setupInlineCrypt() { $p = $this->bctx['p']; $init_crypt = ' static $sb_0, $sb_1, $sb_2, $sb_3; if (!$sb_0) { $sb_0 = $this->bctx["sb"][0]; $sb_1 = $this->bctx["sb"][1]; $sb_2 = $this->bctx["sb"][2]; $sb_3 = $this->bctx["sb"][3]; } '; $safeint = self::safe_intval_inline(); // Generating encrypt code: $encrypt_block = ' $in = unpack("N*", $in); $l = $in[1]; $r = $in[2]; '; for ($i = 0; $i < 16; $i+= 2) { $encrypt_block.= ' $l^= ' . $p[$i] . '; $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]') . '; $r^= ' . $p[$i + 1] . '; $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]') . '; '; } $encrypt_block.= ' $in = pack("N*", $r ^ ' . $p[17] . ', $l ^ ' . $p[16] . ' ); '; // Generating decrypt code: $decrypt_block = ' $in = unpack("N*", $in); $l = $in[1]; $r = $in[2]; '; for ($i = 17; $i > 2; $i-= 2) { $decrypt_block.= ' $l^= ' . $p[$i] . '; $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]') . '; $r^= ' . $p[$i - 1] . '; $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]') . '; '; } $decrypt_block.= ' $in = pack("N*", $r ^ ' . $p[0] . ', $l ^ ' . $p[1] . ' ); '; $this->inline_crypt = $this->createInlineCryptFunction( [ 'init_crypt' => $init_crypt, 'init_encrypt' => '', 'init_decrypt' => '', 'encrypt_block' => $encrypt_block, 'decrypt_block' => $decrypt_block ] ); } } <?php /** * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA. * * PHP version 5 * * Here's an example of how to encrypt and decrypt text with this library: * <code> * <?php * include 'vendor/autoload.php'; * * $private = \phpseclib\Crypt\RSA::createKey(); * $public = $private->getPublicKey(); * * $plaintext = 'terrafrost'; * * $ciphertext = $public->encrypt($plaintext); * * echo $private->decrypt($ciphertext); * ?> * </code> * * Here's an example of how to create signatures and verify signatures with this library: * <code> * <?php * include 'vendor/autoload.php'; * * $private = \phpseclib\Crypt\RSA::createKey(); * $public = $private->getPublicKey(); * * $plaintext = 'terrafrost'; * * $signature = $private->sign($plaintext); * * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified'; * ?> * </code> * * @category Crypt * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\AsymmetricKey; use phpseclib\Crypt\RSA\PrivateKey; use phpseclib\Crypt\RSA\PublicKey; use phpseclib\Math\BigInteger; use phpseclib\Exceptions\UnsupportedAlgorithmException; use phpseclib\Exceptions\InconsistentSetupException; use phpseclib\Crypt\RSA\Keys\PSS; /** * Pure-PHP PKCS#1 compliant implementation of RSA. * * @package RSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RSA extends AsymmetricKey { /** * Algorithm Name * * @var string * @access private */ const ALGORITHM = 'RSA'; /**#@+ * @access public * @see self::encrypt() * @see self::decrypt() */ /** * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding} * (OAEP) for encryption / decryption. * * Uses sha256 by default * * @see self::setHash() * @see self::setMGFHash() */ const ENCRYPTION_OAEP = 1; /** * Use PKCS#1 padding. * * Although self::PADDING_OAEP / self::PADDING_PSS offers more security, including PKCS#1 padding is necessary for purposes of backwards * compatibility with protocols (like SSH-1) written before OAEP's introduction. */ const ENCRYPTION_PKCS1 = 2; /** * Do not use any padding * * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc. */ const ENCRYPTION_NONE = 4; /** * Use PKCS#1 padding with PKCS1 v1.5 compatibility * * A PKCS1 v2.1 encrypted message may not successfully decrypt with a PKCS1 v1.5 implementation (such as OpenSSL). */ const ENCRYPTION_PKCS15_COMPAT = 8; /**#@-*/ /**#@+ * @access public * @see self::sign() * @see self::verify() * @see self::setHash() */ /** * Use the Probabilistic Signature Scheme for signing * * Uses sha256 and 0 as the salt length * * @see self::setSaltLength() * @see self::setMGFHash() * @see self::setHash() */ const SIGNATURE_PSS = 16; /** * Use a relaxed version of PKCS#1 padding for signature verification */ const SIGNATURE_RELAXED_PKCS1 = 32; /** * Use PKCS#1 padding for signature verification */ const SIGNATURE_PKCS1 = 64; /**#@-*/ /** * Encryption padding mode * * @var int * @access private */ protected $encryptionPadding = self::ENCRYPTION_OAEP; /** * Signature padding mode * * @var int * @access private */ protected $signaturePadding = self::SIGNATURE_PSS; /** * Length of hash function output * * @var int * @access private */ protected $hLen; /** * Length of salt * * @var int * @access private */ protected $sLen; /** * Label * * @var string * @access private */ protected $label = ''; /** * Hash function for the Mask Generation Function * * @var \phpseclib\Crypt\Hash * @access private */ protected $mgfHash; /** * Length of MGF hash function output * * @var int * @access private */ protected $mgfHLen; /** * Modulus (ie. n) * * @var \phpseclib\Math\BigInteger * @access private */ protected $modulus; /** * Modulus length * * @var \phpseclib\Math\BigInteger * @access private */ protected $k; /** * Exponent (ie. e or d) * * @var \phpseclib\Math\BigInteger * @access private */ protected $exponent; /** * Default public exponent * * @var int * @link http://en.wikipedia.org/wiki/65537_%28number%29 * @access private */ private static $defaultExponent = 65537; /** * Smallest Prime * * Per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller * than 256 bits. As a consequence if the key you're trying to create is 1024 bits and you've set smallestPrime * to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). At least if * engine is set to self::ENGINE_INTERNAL. If Engine is set to self::ENGINE_OPENSSL then smallest Prime is * ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key generation when there's * a chance neither gmp nor OpenSSL are installed) * * @var int * @access private */ private static $smallestPrime = 4096; /** * Sets the public exponent for key generation * * This will be 65537 unless changed. * * @access public * @param int $val */ public static function setExponent($val) { self::$defaultExponent = $val; } /** * Sets the smallest prime number in bits. Used for key generation * * This will be 4096 unless changed. * * @access public * @param int $val */ public static function setSmallestPrime($val) { self::$smallestPrime = $val; } /** * Create a private key * * The public key can be extracted from the private key * * @return RSA * @access public * @param int $bits */ public static function createKey($bits = 2048) { self::initialize_static_variables(); static $e; if (!isset($e)) { $e = new BigInteger(self::$defaultExponent); } $regSize = $bits >> 1; // divide by two to see how many bits P and Q would be if ($regSize > self::$smallestPrime) { $num_primes = floor($bits / self::$smallestPrime); $regSize = self::$smallestPrime; } else { $num_primes = 2; } $n = clone self::$one; $exponents = $coefficients = $primes = []; $lcm = [ 'top' => clone self::$one, 'bottom' => false ]; do { for ($i = 1; $i <= $num_primes; $i++) { if ($i != $num_primes) { $primes[$i] = BigInteger::randomPrime($regSize); } else { extract(BigInteger::minMaxBits($bits)); /** @var BigInteger $min * @var BigInteger $max */ list($min) = $min->divide($n); $min = $min->add(self::$one); list($max) = $max->divide($n); $primes[$i] = BigInteger::randomRangePrime($min, $max); } // the first coefficient is calculated differently from the rest // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) if ($i > 2) { $coefficients[$i] = $n->modInverse($primes[$i]); } $n = $n->multiply($primes[$i]); $temp = $primes[$i]->subtract(self::$one); // textbook RSA implementations use Euler's totient function instead of the least common multiple. // see http://en.wikipedia.org/wiki/Euler%27s_totient_function $lcm['top'] = $lcm['top']->multiply($temp); $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); } list($temp) = $lcm['top']->divide($lcm['bottom']); $gcd = $temp->gcd($e); $i0 = 1; } while (!$gcd->equals(self::$one)); $coefficients[2] = $primes[2]->modInverse($primes[1]); $d = $e->modInverse($temp); foreach ($primes as $i => $prime) { $temp = $prime->subtract(self::$one); $exponents[$i] = $e->modInverse($temp); } // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>: // RSAPrivateKey ::= SEQUENCE { // version Version, // modulus INTEGER, -- n // publicExponent INTEGER, -- e // privateExponent INTEGER, -- d // prime1 INTEGER, -- p // prime2 INTEGER, -- q // exponent1 INTEGER, -- d mod (p-1) // exponent2 INTEGER, -- d mod (q-1) // coefficient INTEGER, -- (inverse of q) mod p // otherPrimeInfos OtherPrimeInfos OPTIONAL // } $privatekey = new PrivateKey; $privatekey->modulus = $n; $privatekey->k = $bits >> 3; $privatekey->publicExponent = $e; $privatekey->exponent = $d; $privatekey->privateExponent = $e; $privatekey->primes = $primes; $privatekey->exponents = $exponents; $privatekey->coefficients = $coefficients; /* $publickey = new PublicKey; $publickey->modulus = $n; $publickey->k = $bits >> 3; $publickey->exponent = $e; $publickey->publicExponent = $e; $publickey->isPublic = true; */ return $privatekey; } /** * Loads a public or private key * * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) * * @return bool * @access public * @param string $key * @param string $type optional * @param string $password optional */ public static function load($key, $type = false, $password = false) { self::initialize_static_variables(); $components = parent::load($key, $type, $password); $key = $components['isPublicKey'] ? new PublicKey : new PrivateKey; $key->format = $components['format']; $key->modulus = $components['modulus']; $key->publicExponent = $components['publicExponent']; $key->k = $key->modulus->getLengthInBytes(); if ($components['isPublicKey']) { $key->exponent = $key->publicExponent; } else { $key->privateExponent = $components['privateExponent']; $key->exponent = $key->privateExponent; $key->primes = $components['primes']; $key->exponents = $components['exponents']; $key->coefficients = $components['coefficients']; } if ($components['format'] == PSS::class) { $key = $key->withPadding(self::SIGNATURE_PSS); if (isset($components['hash'])) { $key = $key->withHash($components['hash']); } if (isset($components['MGFHash'])) { $key = $key->withMGFHash($components['MGFHash']); } if (isset($components['saltLength'])) { $key = $key->withSaltLength($components['saltLength']); } } return $key; } /** * Constructor * * PublicKey and PrivateKey objects can only be created from abstract RSA class */ protected function __construct() { parent::__construct(); $this->hLen = $this->hash->getLengthInBytes(); $this->mgfHash = new Hash('sha256'); $this->mgfHLen = $this->mgfHash->getLengthInBytes(); } /** * Integer-to-Octet-String primitive * * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}. * * @access private * @param bool|\phpseclib\Math\BigInteger $x * @param int $xLen * @return bool|string */ protected function i2osp($x, $xLen) { if ($x === false) { return false; } $x = $x->toBytes(); if (strlen($x) > $xLen) { return false; } return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); } /** * Octet-String-to-Integer primitive * * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}. * * @access private * @param string $x * @return \phpseclib\Math\BigInteger */ protected function os2ip($x) { return new BigInteger($x, 256); } /** * EMSA-PKCS1-V1_5-ENCODE * * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}. * * @access private * @param string $m * @param int $emLen * @throws \LengthException if the intended encoded message length is too short * @return string */ protected function emsa_pkcs1_v1_5_encode($m, $emLen) { $h = $this->hash->hash($m); // see http://tools.ietf.org/html/rfc3447#page-43 switch ($this->hash->getHash()) { case 'md2': $t = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02\x05\x00\x04\x10"; break; case 'md5': $t = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10"; break; case 'sha1': $t = "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14"; break; case 'sha256': $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"; break; case 'sha384': $t = "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30"; break; case 'sha512': $t = "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40"; break; // from https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf#page=40 case 'sha224': $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c"; break; case 'sha512/224': $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x05\x05\x00\x04\x1c"; break; case 'sha512/256': $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x05\x00\x04\x20"; } $t.= $h; $tLen = strlen($t); if ($emLen < $tLen + 11) { throw new \LengthException('Intended encoded message length too short'); } $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); $em = "\0\1$ps\0$t"; return $em; } /** * MGF1 * * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}. * * @access private * @param string $mgfSeed * @param int $maskLen * @return string */ protected function mgf1($mgfSeed, $maskLen) { // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output. $t = ''; $count = ceil($maskLen / $this->mgfHLen); for ($i = 0; $i < $count; $i++) { $c = pack('N', $i); $t.= $this->mgfHash->hash($mgfSeed . $c); } return substr($t, 0, $maskLen); } /** * Returns the key size * * More specifically, this returns the size of the modulo in bits. * * @access public * @return int */ public function getLength() { return !isset($this->modulus) ? 0 : $this->modulus->getLength(); } /** * Determines which hashing function should be used * * Used with signature production / verification and (if the encryption mode is self::PADDING_OAEP) encryption and * decryption. * * @access public * @param string $hash */ public function withHash($hash) { $new = clone $this; // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. switch (strtolower($hash)) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': case 'sha224': case 'sha512/224': case 'sha512/256': $new->hash = new Hash($hash); break; default: throw new UnsupportedAlgorithmException( 'The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256' ); } $new->hLen = $new->hash->getLengthInBytes(); return $new; } /** * Determines which hashing function should be used for the mask generation function * * The mask generation function is used by self::PADDING_OAEP and self::PADDING_PSS and although it's * best if Hash and MGFHash are set to the same thing this is not a requirement. * * @access public * @param string $hash */ public function withMGFHash($hash) { $new = clone $this; // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. switch (strtolower($hash)) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': case 'sha224': case 'sha512/224': case 'sha512/256': $new->mgfHash = new Hash($hash); break; default: throw new UnsupportedAlgorithmException( 'The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256' ); } $new->mgfHLen = $new->mgfHash->getLengthInBytes(); return $new; } /** * Determines the salt length * * Used by RSA::PADDING_PSS * * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}: * * Typical salt lengths in octets are hLen (the length of the output * of the hash function Hash) and 0. * * @access public * @param int $sLen */ public function withSaltLength($sLen) { $new = clone $this; $new->sLen = $sLen; return $new; } /** * Determines the label * * Used by RSA::PADDING_OAEP * * To quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}: * * Both the encryption and the decryption operations of RSAES-OAEP take * the value of a label L as input. In this version of PKCS #1, L is * the empty string; other uses of the label are outside the scope of * this document. * * @access public * @param string $label */ public function withLabel($label) { $new = clone $this; $new->label = $label; return $new; } /** * Determines the padding modes * * Example: $key->withPadding(RSA::ENCRYPTION_PKCS1 | RSA::SIGNATURE_PKCS1); * * @access public * @param string $label */ public function withPadding($padding) { $masks = [ self::ENCRYPTION_OAEP, self::ENCRYPTION_PKCS1, self::ENCRYPTION_NONE, self::ENCRYPTION_PKCS15_COMPAT ]; $numSelected = 0; $selected = 0; foreach ($masks as $mask) { if ($padding & $mask) { $selected = $mask; $numSelected++; } } if ($numSelected > 1) { throw new InconsistentSetupException('Multiple encryption padding modes have been selected; at most only one should be selected'); } $encryptionPadding = $selected; $masks = [ self::SIGNATURE_PSS, self::SIGNATURE_RELAXED_PKCS1, self::SIGNATURE_PKCS1 ]; $numSelected = 0; $selected = 0; foreach ($masks as $mask) { if ($padding & $mask) { $selected = $mask; $numSelected++; } } if ($numSelected > 1) { throw new InconsistentSetupException('Multiple signature padding modes have been selected; at most only one should be selected'); } $signaturePadding = $selected; $new = clone $this; $new->encryptionPadding = $encryptionPadding; $new->signaturePadding = $signaturePadding; return $new; } /** * Returns the current engine being used * * @see self::useInternalEngine() * @see self::useBestEngine() * @access public * @return string */ public function getEngine() { return 'PHP'; } /** * Enable RSA Blinding * * @access public */ public static function enableBlinding() { static::$enableBlinding = true; } /** * Disable RSA Blinding * * @access public */ public static function disableBlinding() { static::$enableBlinding = false; } }<?php /** * Pure-PHP implementation of Rijndael. * * Uses mcrypt, if available/possible, and an internal implementation, otherwise. * * PHP version 5 * * If {@link self::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If * {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's * 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until * {@link self::setKey() setKey()} is called, again, at which point, it'll be recalculated. * * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example, * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256. * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224 * are first defined as valid key / block lengths in * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}: * Extensions: Other block and Cipher Key lengths. * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224). * * {@internal The variable names are the same as those in * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}} * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $rijndael = new \phpseclib\Crypt\Rijndael(); * * $rijndael->setKey('abcdefghijklmnop'); * * $size = 10 * 1024; * $plaintext = ''; * for ($i = 0; $i < $size; $i++) { * $plaintext.= 'a'; * } * * echo $rijndael->decrypt($rijndael->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package Rijndael * @author Jim Wigginton <terrafrost@php.net> * @copyright 2008 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\BlockCipher; use phpseclib\Common\Functions\Strings; use phpseclib\Exception\BadModeException; use phpseclib\Exception\InsufficientSetupException; use phpseclib\Exception\BadDecryptionException; /** * Pure-PHP implementation of Rijndael. * * @package Rijndael * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Rijndael extends BlockCipher { /** * The mcrypt specific name of the cipher * * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not. * \phpseclib\Crypt\Rijndael determines automatically whether mcrypt is useable * or not for the current $block_size/$key_length. * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly. * * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @see \phpseclib\Crypt\Common\SymmetricKey::engine * @see self::isValidEngine() * @var string * @access private */ protected $cipher_name_mcrypt = 'rijndael-128'; /** * The Key Schedule * * @see self::setup() * @var array * @access private */ private $w; /** * The Inverse Key Schedule * * @see self::setup() * @var array * @access private */ private $dw; /** * The Block Length divided by 32 * * @see self::setBlockLength() * @var int * @access private * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. */ private $Nb = 4; /** * The Key Length (in bytes) * * @see self::setKeyLength() * @var int * @access private * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu * of that, we'll just precompute it once. */ protected $key_length = 16; /** * The Key Length divided by 32 * * @see self::setKeyLength() * @var int * @access private * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4 */ private $Nk = 4; /** * The Number of Rounds * * @var int * @access private * @internal The max value is 14, the min value is 10. */ private $Nr; /** * Shift offsets * * @var array * @access private */ private $c; /** * Holds the last used key- and block_size information * * @var array * @access private */ private $kl; /** * Default Constructor. * * @param int $mode * @access public * @throws \InvalidArgumentException if an invalid / unsupported mode is provided */ public function __construct($mode) { if ($mode == self::MODE_STREAM) { throw new BadModeException('Block ciphers cannot be ran in stream mode'); } parent::__construct($mode); } /** * Sets the key length. * * Valid key lengths are 128, 160, 192, 224, and 256. * * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to * 192/256 bits as, for example, mcrypt will do. * * That said, if you want be compatible with other Rijndael and AES implementations, * you should not setKeyLength(160) or setKeyLength(224). * * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use * the mcrypt php extension, even if available. * This results then in slower encryption. * * @access public * @throws \LengthException if the key length is invalid * @param int $length */ public function setKeyLength($length) { switch ($length) { case 128: case 160: case 192: case 224: case 256: $this->key_length = $length >> 3; break; default: throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported'); } parent::setKeyLength($length); } /** * Sets the key. * * Rijndael supports five different key lengths * * @see setKeyLength() * @access public * @param string $key * @throws \LengthException if the key length isn't supported */ public function setKey($key) { switch (strlen($key)) { case 16: case 20: case 24: case 28: case 32: break; default: throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 20, 24, 28 or 32 are supported'); } parent::setKey($key); } /** * Sets the block length * * Valid block lengths are 128, 160, 192, 224, and 256. * * @access public * @param int $length */ public function setBlockLength($length) { switch ($length) { case 128: case 160: case 192: case 224: case 256: break; default: throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported'); } $this->Nb = $length >> 5; $this->block_size = $length >> 3; $this->changed = true; $this->setEngine(); } /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { switch ($engine) { case self::ENGINE_LIBSODIUM: return function_exists('sodium_crypto_aead_aes256gcm_is_available') && sodium_crypto_aead_aes256gcm_is_available() && $this->mode == self::MODE_GCM && $this->key_length == 32 && $this->nonce && strlen($this->nonce) == 12 && $this->block_size == 16; case self::ENGINE_OPENSSL_GCM: if (!extension_loaded('openssl')) { return false; } $methods = openssl_get_cipher_methods(); return $this->mode == self::MODE_GCM && version_compare(PHP_VERSION, '7.1.0', '>=') && in_array('aes-' . $this->getKeyLength() . '-gcm', $methods) && $this->block_size == 16; case self::ENGINE_OPENSSL: if ($this->block_size != 16) { return false; } self::$cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb'; $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->openssl_translate_mode(); break; case self::ENGINE_MCRYPT: $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); if ($this->key_length % 8) { // is it a 160/224-bit key? // mcrypt is not usable for them, only for 128/192/256-bit keys return false; } } return parent::isValidEngineHelper($engine); } /** * Encrypts a block * * @access private * @param string $in * @return string */ protected function encryptBlock($in) { static $tables; if (empty($tables)) { $tables = &$this->getTables(); } $t0 = $tables[0]; $t1 = $tables[1]; $t2 = $tables[2]; $t3 = $tables[3]; $sbox = $tables[4]; $state = []; $words = unpack('N*', $in); $c = $this->c; $w = $this->w; $Nb = $this->Nb; $Nr = $this->Nr; // addRoundKey $wc = $Nb - 1; foreach ($words as $word) { $state[] = $word ^ $w[++$wc]; } // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf $temp = []; for ($round = 1; $round < $Nr; ++$round) { $i = 0; // $c[0] == 0 $j = $c[1]; $k = $c[2]; $l = $c[3]; while ($i < $Nb) { $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^ $t1[$state[$j] >> 16 & 0x000000FF] ^ $t2[$state[$k] >> 8 & 0x000000FF] ^ $t3[$state[$l] & 0x000000FF] ^ $w[++$wc]; ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } $state = $temp; } // subWord for ($i = 0; $i < $Nb; ++$i) { $state[$i] = $sbox[$state[$i] & 0x000000FF] | ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); } // shiftRows + addRoundKey $i = 0; // $c[0] == 0 $j = $c[1]; $k = $c[2]; $l = $c[3]; while ($i < $Nb) { $temp[$i] = ($state[$i] & 0xFF000000) ^ ($state[$j] & 0x00FF0000) ^ ($state[$k] & 0x0000FF00) ^ ($state[$l] & 0x000000FF) ^ $w[$i]; ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } return pack('N*',...$temp); } /** * Decrypts a block * * @access private * @param string $in * @return string */ protected function decryptBlock($in) { static $invtables; if (empty($invtables)) { $invtables = &$this->getInvTables(); } $dt0 = $invtables[0]; $dt1 = $invtables[1]; $dt2 = $invtables[2]; $dt3 = $invtables[3]; $isbox = $invtables[4]; $state = []; $words = unpack('N*', $in); $c = $this->c; $dw = $this->dw; $Nb = $this->Nb; $Nr = $this->Nr; // addRoundKey $wc = $Nb - 1; foreach ($words as $word) { $state[] = $word ^ $dw[++$wc]; } $temp = []; for ($round = $Nr - 1; $round > 0; --$round) { $i = 0; // $c[0] == 0 $j = $Nb - $c[1]; $k = $Nb - $c[2]; $l = $Nb - $c[3]; while ($i < $Nb) { $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^ $dt1[$state[$j] >> 16 & 0x000000FF] ^ $dt2[$state[$k] >> 8 & 0x000000FF] ^ $dt3[$state[$l] & 0x000000FF] ^ $dw[++$wc]; ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } $state = $temp; } // invShiftRows + invSubWord + addRoundKey $i = 0; // $c[0] == 0 $j = $Nb - $c[1]; $k = $Nb - $c[2]; $l = $Nb - $c[3]; while ($i < $Nb) { $word = ($state[$i] & 0xFF000000) | ($state[$j] & 0x00FF0000) | ($state[$k] & 0x0000FF00) | ($state[$l] & 0x000000FF); $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] | ($isbox[$word >> 8 & 0x000000FF] << 8) | ($isbox[$word >> 16 & 0x000000FF] << 16) | ($isbox[$word >> 24 & 0x000000FF] << 24)); ++$i; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } return pack('N*',...$temp); } /** * Setup the key (expansion) * * @see \phpseclib\Crypt\Common\SymmetricKey::setupKey() * @access private */ protected function setupKey() { // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse static $rcon = [0, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 ]; if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) { // already expanded return; } $this->kl = ['key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size]; $this->Nk = $this->key_length >> 2; // see Rijndael-ammended.pdf#page=44 $this->Nr = max($this->Nk, $this->Nb) + 6; // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44, // "Table 8: Shift offsets in Shiftrow for the alternative block lengths" // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14, // "Table 2: Shift offsets for different block lengths" switch ($this->Nb) { case 4: case 5: case 6: $this->c = [0, 1, 2, 3]; break; case 7: $this->c = [0, 1, 2, 4]; break; case 8: $this->c = [0, 1, 3, 4]; } $w = array_values(unpack('N*words', $this->key)); $length = $this->Nb * ($this->Nr + 1); for ($i = $this->Nk; $i < $length; $i++) { $temp = $w[$i - 1]; if ($i % $this->Nk == 0) { // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent". // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord $temp = $this->subWord($temp) ^ $rcon[$i / $this->Nk]; } elseif ($this->Nk > 6 && $i % $this->Nk == 4) { $temp = $this->subWord($temp); } $w[$i] = $w[$i - $this->Nk] ^ $temp; } // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns // and generate the inverse key schedule. more specifically, // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3), // "The key expansion for the Inverse Cipher is defined as follows: // 1. Apply the Key Expansion. // 2. Apply InvMixColumn to all Round Keys except the first and the last one." // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" list($dt0, $dt1, $dt2, $dt3) = $this->getInvTables(); $temp = $this->w = $this->dw = []; for ($i = $row = $col = 0; $i < $length; $i++, $col++) { if ($col == $this->Nb) { if ($row == 0) { $this->dw[0] = $this->w[0]; } else { // subWord + invMixColumn + invSubWord = invMixColumn $j = 0; while ($j < $this->Nb) { $dw = $this->subWord($this->w[$row][$j]); $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^ $dt1[$dw >> 16 & 0x000000FF] ^ $dt2[$dw >> 8 & 0x000000FF] ^ $dt3[$dw & 0x000000FF]; $j++; } $this->dw[$row] = $temp; } $col = 0; $row++; } $this->w[$row][$col] = $w[$i]; } $this->dw[$row] = $this->w[$row]; // Converting to 1-dim key arrays (both ascending) $this->dw = array_reverse($this->dw); $w = array_pop($this->w); $dw = array_pop($this->dw); foreach ($this->w as $r => $wr) { foreach ($wr as $c => $wc) { $w[] = $wc; $dw[] = $this->dw[$r][$c]; } } $this->w = $w; $this->dw = $dw; } /** * Performs S-Box substitutions * * @return array * @access private * @param int $word */ private function subWord($word) { static $sbox; if (empty($sbox)) { list(, , , , $sbox) = self::getTables(); } return $sbox[$word & 0x000000FF] | ($sbox[$word >> 8 & 0x000000FF] << 8) | ($sbox[$word >> 16 & 0x000000FF] << 16) | ($sbox[$word >> 24 & 0x000000FF] << 24); } /** * Provides the mixColumns and sboxes tables * * @see self::encryptBlock() * @see self::setupInlineCrypt() * @see self::subWord() * @access private * @return array &$tables */ protected function &getTables() { static $tables; if (empty($tables)) { // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1), // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so // those are the names we'll use. $t3 = array_map('intval', [ // with array_map('intval',...) we ensure we have only int's and not // some slower floats converted by php automatically on high values 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C ]); foreach ($t3 as $t3i) { $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF); $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF); $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF); } $tables = [ // The Precomputed mixColumns tables t0 - t3 $t0, $t1, $t2, $t3, // The SubByte S-Box [ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 ] ]; } return $tables; } /** * Provides the inverse mixColumns and inverse sboxes tables * * @see self::decryptBlock() * @see self::setupInlineCrypt() * @see self::setupKey() * @access private * @return array &$tables */ protected function &getInvTables() { static $tables; if (empty($tables)) { $dt3 = array_map('intval', [ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 ]); foreach ($dt3 as $dt3i) { $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF); $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF); $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF); }; $tables = [ // The Precomputed inverse mixColumns tables dt0 - dt3 $dt0, $dt1, $dt2, $dt3, // The inverse SubByte S-Box [ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ] ]; } return $tables; } /** * Setup the performance-optimized function for de/encrypt() * * @see \phpseclib\Crypt\Common\SymmetricKey::setupInlineCrypt() * @access private */ protected function setupInlineCrypt() { $w = $this->w; $dw = $this->dw; $init_encrypt = ''; $init_decrypt = ''; $Nr = $this->Nr; $Nb = $this->Nb; $c = $this->c; // Generating encrypt code: $init_encrypt.= ' static $tables; if (empty($tables)) { $tables = &$this->getTables(); } $t0 = $tables[0]; $t1 = $tables[1]; $t2 = $tables[2]; $t3 = $tables[3]; $sbox = $tables[4]; '; $s = 'e'; $e = 's'; $wc = $Nb - 1; // Preround: addRoundKey $encrypt_block = '$in = unpack("N*", $in);'."\n"; for ($i = 0; $i < $Nb; ++$i) { $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; } // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey for ($round = 1; $round < $Nr; ++$round) { list($s, $e) = [$e, $s]; for ($i = 0; $i < $Nb; ++$i) { $encrypt_block.= '$'.$e.$i.' = $t0[($'.$s.$i .' >> 24) & 0xff] ^ $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ '.$w[++$wc].";\n"; } } // Finalround: subWord + shiftRows + addRoundKey for ($i = 0; $i < $Nb; ++$i) { $encrypt_block.= '$'.$e.$i.' = $sbox[ $'.$e.$i.' & 0xff] | ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; } $encrypt_block .= '$in = pack("N*"'."\n"; for ($i = 0; $i < $Nb; ++$i) { $encrypt_block.= ', ($'.$e.$i .' & '.((int)0xFF000000).') ^ ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^ ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^ ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^ '.$w[$i]."\n"; } $encrypt_block .= ');'; // Generating decrypt code: $init_decrypt.= ' static $invtables; if (empty($invtables)) { $invtables = &$this->getInvTables(); } $dt0 = $invtables[0]; $dt1 = $invtables[1]; $dt2 = $invtables[2]; $dt3 = $invtables[3]; $isbox = $invtables[4]; '; $s = 'e'; $e = 's'; $wc = $Nb - 1; // Preround: addRoundKey $decrypt_block = '$in = unpack("N*", $in);'."\n"; for ($i = 0; $i < $Nb; ++$i) { $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; } // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey for ($round = 1; $round < $Nr; ++$round) { list($s, $e) = [$e, $s]; for ($i = 0; $i < $Nb; ++$i) { $decrypt_block.= '$'.$e.$i.' = $dt0[($'.$s.$i .' >> 24) & 0xff] ^ $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ '.$dw[++$wc].";\n"; } } // Finalround: subWord + shiftRows + addRoundKey for ($i = 0; $i < $Nb; ++$i) { $decrypt_block.= '$'.$e.$i.' = $isbox[ $'.$e.$i.' & 0xff] | ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; } $decrypt_block .= '$in = pack("N*"'."\n"; for ($i = 0; $i < $Nb; ++$i) { $decrypt_block.= ', ($'.$e.$i. ' & '.((int)0xFF000000).') ^ ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^ ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^ ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^ '.$dw[$i]."\n"; } $decrypt_block .= ');'; $this->inline_crypt = $this->createInlineCryptFunction( [ 'init_crypt' => '', 'init_encrypt' => $init_encrypt, 'init_decrypt' => $init_decrypt, 'encrypt_block' => $encrypt_block, 'decrypt_block' => $decrypt_block ] ); } /** * Encrypts a message. * * @see self::decrypt() * @see parent::encrypt() * @access public * @param string $plaintext * @return string */ public function encrypt($plaintext) { $this->setup(); switch ($this->engine) { case self::ENGINE_LIBSODIUM: $this->newtag = sodium_crypto_aead_aes256gcm_encrypt($plaintext, $this->aad, $this->nonce, $this->key); return Strings::shift($this->newtag, strlen($plaintext)); case self::ENGINE_OPENSSL_GCM: return openssl_encrypt( $plaintext, 'aes-' . $this->getKeyLength() . '-gcm', $this->key, OPENSSL_RAW_DATA, $this->nonce, $this->newtag, $this->aad ); } return parent::encrypt($plaintext); } /** * Decrypts a message. * * @see self::encrypt() * @see parent::decrypt() * @access public * @param string $ciphertext * @return string */ public function decrypt($ciphertext) { $this->setup(); switch ($this->engine) { case self::ENGINE_LIBSODIUM: if ($this->oldtag === false) { throw new InsufficientSetupException('Authentication Tag has not been set'); } if (strlen($this->oldtag) != 16) { break; } $plaintext = sodium_crypto_aead_aes256gcm_decrypt($ciphertext . $this->oldtag, $this->aad, $this->nonce, $this->key); if ($plaintext === false) { $this->oldtag = false; throw new BadDecryptionException('Error decrypting ciphertext with libsodium'); } return $plaintext; case self::ENGINE_OPENSSL_GCM: if ($this->oldtag === false) { throw new InsufficientSetupException('Authentication Tag has not been set'); } $plaintext = openssl_decrypt( $ciphertext, 'aes-' . $this->getKeyLength() . '-gcm', $this->key, OPENSSL_RAW_DATA, $this->nonce, $this->oldtag, $this->aad ); if ($plaintext === false) { $this->oldtag = false; throw new BadDecryptionException('Error decrypting ciphertext with OpenSSL'); } return $plaintext; } return parent::decrypt($ciphertext); } } <?php /** * Pure-PHP FIPS 186-4 compliant implementation of DSA. * * PHP version 5 * * Here's an example of how to create signatures and verify signatures with this library: * <code> * <?php * include 'vendor/autoload.php'; * * $private = \phpseclib\Crypt\DSA::createKey(); * $public = $private->getPublicKey(); * * $plaintext = 'terrafrost'; * * $signature = $private->sign($plaintext); * * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified'; * ?> * </code> * * @category Crypt * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\AsymmetricKey; use phpseclib\Crypt\DSA\PrivateKey; use phpseclib\Crypt\DSA\PublicKey; use phpseclib\Crypt\DSA\Parameters; use phpseclib\Math\BigInteger; use phpseclib\Exception\InsufficientSetupException; /** * Pure-PHP FIPS 186-4 compliant implementation of DSA. * * @package DSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DSA extends AsymmetricKey { /** * Algorithm Name * * @var string * @access private */ const ALGORITHM = 'DSA'; /** * DSA Prime P * * @var \phpseclib\Math\BigInteger * @access private */ protected $p; /** * DSA Group Order q * * Prime divisor of p-1 * * @var \phpseclib\Math\BigInteger * @access private */ protected $q; /** * DSA Group Generator G * * @var \phpseclib\Math\BigInteger * @access private */ protected $g; /** * DSA public key value y * * @var \phpseclib\Math\BigInteger * @access private */ protected $y; /** * Signature Format * * @var string * @access private */ protected $format; /** * Signature Format (Short) * * @var string * @access private */ protected $shortFormat; /** * Create DSA parameters * * @access public * @param int $L * @param int $N * @return \phpseclib\Crypt\DSA|bool */ public static function createParameters($L = 2048, $N = 224) { self::initialize_static_variables(); if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } switch (true) { case $N == 160: /* in FIPS 186-1 and 186-2 N was fixed at 160 whereas K had an upper bound of 1024. RFC 4253 (SSH Transport Layer Protocol) references FIPS 186-2 and as such most SSH DSA implementations only support keys with an N of 160. puttygen let's you set the size of L (but not the size of N) and uses 2048 as the default L value. that's not really compliant with any of the FIPS standards, however, for the purposes of maintaining compatibility with puttygen, we'll support it */ //case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160: // FIPS 186-3 changed this as follows: //case $L == 1024 && $N == 160: case $L == 2048 && $N == 224: case $L == 2048 && $N == 256: case $L == 3072 && $N == 256: break; default: throw new \InvalidArgumentException('Invalid values for N and L'); } $two = new BigInteger(2); $q = BigInteger::randomPrime($N); $divisor = $q->multiply($two); do { $x = BigInteger::random($L); list(, $c) = $x->divide($divisor); $p = $x->subtract($c->subtract(self::$one)); } while ($p->getLength() != $L || !$p->isPrime()); $p_1 = $p->subtract(self::$one); list($e) = $p_1->divide($q); // quoting http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=50 , // "h could be obtained from a random number generator or from a counter that // changes after each use". PuTTY (sshdssg.c) starts h off at 1 and increments // it on each loop. wikipedia says "commonly h = 2 is used" so we'll just do that $h = clone $two; while (true) { $g = $h->powMod($e, $p); if (!$g->equals(self::$one)) { break; } $h = $h->add(self::$one); } $dsa = new Parameters; $dsa->p = $p; $dsa->q = $q; $dsa->g = $g; return $dsa; } /** * Create public / private key pair. * * This method is a bit polymorphic. It can take a DSA/Parameters object, L / N as two distinct parameters or * no parameters (at which point L and N will be generated with this method) * * Returns the private key, from which the publickey can be extracted * * @param $args[] * @access public * @return DSA\PrivateKey */ public static function createKey(...$args) { self::initialize_static_variables(); if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) { $params = self::createParameters($args[0], $args[1]); } else if (count($args) == 1 && $args[0] instanceof Parameters) { $params = $args[0]; } else if (!count($args)) { $params = self::createParameters(); } else { throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.'); } $private = new PrivateKey; $private->p = $params->p; $private->q = $params->q; $private->g = $params->g; $private->x = BigInteger::randomRange(self::$one, $private->q->subtract(self::$one)); $private->y = $private->g->powMod($private->x, $private->p); //$public = clone $private; //unset($public->x); return $private ->withHash($params->hash->getHash()) ->withSignatureFormat($params->shortFormat); } /** * Loads a public or private key * * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) * @return bool * @access public * @param string $key * @param string $type optional * @param string $password optional */ public static function load($key, $type = false, $password = false) { self::initialize_static_variables(); if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } $components = parent::load($key, $type, $password); if (!isset($components['x']) && !isset($components['y'])) { $new = new Parameters; } else if (isset($components['x'])) { $new = new PrivateKey; $new->x = $components['x']; } else { $new = new PublicKey; } $new->p = $components['p']; $new->q = $components['q']; $new->g = $components['g']; if (isset($components['y'])) { $new->y = $components['y']; } return $new; } /** * Constructor * * PublicKey and PrivateKey objects can only be created from abstract RSA class */ protected function __construct() { $this->format = self::validatePlugin('Signature', 'ASN1'); $this->shortFormat = 'ASN1'; parent::__construct(); } /** * Returns the key size * * More specifically, this L (the length of DSA Prime P) and N (the length of DSA Group Order q) * * @access public * @return array */ public function getLength() { return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()]; } /** * Returns the current engine being used * * @see self::useInternalEngine() * @see self::useBestEngine() * @access public * @return string */ public function getEngine() { return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ? 'OpenSSL' : 'PHP'; } /** * Returns the parameters * * A public / private key is only returned if the currently loaded "key" contains an x or y * value. * * @see self::getPublicKey() * @access public * @param string $type optional * @return mixed */ public function getParameters() { $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters'); $key = $type::saveParameters($this->p, $this->q, $this->g); return DSA::load($key, 'PKCS1') ->withHash($this->hash->getHash()) ->withSignatureFormat($this->shortFormat); } /** * Determines the signature padding mode * * Valid values are: ASN1, SSH2, Raw * * @access public * @param string $padding */ public function withSignatureFormat($format) { $new = clone $this; $new->shortFormat = $format; $new->format = self::validatePlugin('Signature', $format); return $new; } }<?php /** * Pure-PHP implementation of ECDSA. * * PHP version 5 * * Here's an example of how to create signatures and verify signatures with this library: * <code> * <?php * include 'vendor/autoload.php'; * * $private = \phpseclib\Crypt\ECDSA::createKey('secp256k1'); * $public = $private->getPublicKey(); * * $plaintext = 'terrafrost'; * * $signature = $private->sign($plaintext); * * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified'; * ?> * </code> * * @category Crypt * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\AsymmetricKey; use phpseclib\Crypt\ECDSA\PrivateKey; use phpseclib\Crypt\ECDSA\PublicKey; use phpseclib\Crypt\ECDSA\Parameters; use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib\Crypt\ECDSA\Curves\Ed25519; use phpseclib\Crypt\ECDSA\Curves\Ed448; use phpseclib\Crypt\ECDSA\Keys\PKCS1; use phpseclib\File\ASN1\Maps\ECParameters; use phpseclib\File\ASN1; use phpseclib\Exception\UnsupportedCurveException; use phpseclib\Exception\UnsupportedAlgorithmException; /** * Pure-PHP implementation of ECDSA. * * @package ECDSA * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ECDSA extends AsymmetricKey { /** * Algorithm Name * * @var string * @access private */ const ALGORITHM = 'ECDSA'; /** * Public Key QA * * @var object[] */ protected $QA; /** * Curve * * @var \phpseclib\Crypt\ECDSA\BaseCurves\Base */ protected $curve; /** * Signature Format * * @var string * @access private */ protected $format; /** * Signature Format (Short) * * @var string * @access private */ protected $shortFormat; /** * Curve Name * * @var string */ private $curveName; /** * Curve Order * * Used for deterministic ECDSA * * @var \phpseclib\Math\BigInteger */ protected $q; /** * Alias for the private key * * Used for deterministic ECDSA. AsymmetricKey expects $x. I don't like x because * with x you have x * the base point yielding an (x, y)-coordinate that is the * public key. But the x is different depending on which side of the equal sign * you're on. It's less ambiguous if you do dA * base point = (x, y)-coordinate. * * @var \phpseclib\Math\BigInteger */ protected $x; /** * Context * * @var string */ protected $context; /** * Create public / private key pair. * * @access public * @param string $curve * @return \phpseclib\Crypt\ECDSA\PrivateKey */ public static function createKey($curve) { self::initialize_static_variables(); if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } $curve = strtolower($curve); if (self::$engines['libsodium'] && $curve == 'ed25519' && function_exists('sodium_crypto_sign_keypair')) { $kp = sodium_crypto_sign_keypair(); $privatekey = ECDSA::load(sodium_crypto_sign_secretkey($kp), 'libsodium'); //$publickey = ECDSA::load(sodium_crypto_sign_publickey($kp), 'libsodium'); $privatekey->curveName = 'Ed25519'; //$publickey->curveName = $curve; return $privatekey; } $privatekey = new PrivateKey; $curveName = $curve; $curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $curve; if (!class_exists($curve)) { throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported'); } $reflect = new \ReflectionClass($curve); $curveName = $reflect->isFinal() ? $reflect->getParentClass()->getShortName() : $reflect->getShortName(); $curve = new $curve(); $privatekey->dA = $dA = $curve->createRandomMultiplier(); $privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA); $privatekey->curve = $curve; //$publickey = clone $privatekey; //unset($publickey->dA); //unset($publickey->x); $privatekey->curveName = $curveName; //$publickey->curveName = $curveName; if ($privatekey->curve instanceof TwistedEdwardsCurve) { return $privatekey->withHash($curve::HASH); } return $privatekey; } /** * Loads a public or private key * * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) * @return bool * @access public * @param string $key * @param string $type optional * @param string $password optional */ public static function load($key, $type = false, $password = false) { self::initialize_static_variables(); if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } $components = parent::load($key, $type, $password); if (!isset($components['dA']) && !isset($components['QA'])) { $new = new Parameters; $new->curve = $components['curve']; return $new; } $new = isset($components['dA']) ? new PrivateKey : new PublicKey; $new->curve = $components['curve']; $new->QA = $components['QA']; if (isset($components['dA'])) { $new->dA = $components['dA']; } if ($new->curve instanceof TwistedEdwardsCurve) { return $new->withHash($components['curve']::HASH); } return $new; } /** * Constructor * * PublicKey and PrivateKey objects can only be created from abstract RSA class */ protected function __construct() { $this->format = self::validatePlugin('Signature', 'ASN1'); $this->shortFormat = 'ASN1'; parent::__construct(); } /** * Returns the curve * * Returns a string if it's a named curve, an array if not * * @access public * @return string|array */ public function getCurve() { if ($this->curveName) { return $this->curveName; } if ($this->curve instanceof TwistedEdwardsCurve) { $this->curveName = $this->curve instanceof Ed25519 ? 'Ed25519' : 'Ed448'; return $this->curveName; } $params = $this->getParameters()->toString('PKCS8', ['namedCurve' => true]); $decoded = ASN1::extractBER($params); $decoded = ASN1::decodeBER($decoded); $decoded = ASN1::asn1map($decoded[0], ECParameters::MAP); if (isset($decoded['namedCurve'])) { $this->curveName = $decoded['namedCurve']; return $decoded['namedCurve']; } if (!$namedCurves) { PKCS1::useSpecifiedCurve(); } return $decoded; } /** * Returns the key size * * Quoting https://tools.ietf.org/html/rfc5656#section-2, * * "The size of a set of elliptic curve domain parameters on a prime * curve is defined as the number of bits in the binary representation * of the field order, commonly denoted by p. Size on a * characteristic-2 curve is defined as the number of bits in the binary * representation of the field, commonly denoted by m. A set of * elliptic curve domain parameters defines a group of order n generated * by a base point P" * * @access public * @return int */ public function getLength() { return $this->curve->getLength(); } /** * Returns the current engine being used * * @see self::useInternalEngine() * @see self::useBestEngine() * @access public * @return string */ public function getEngine() { if ($this->curve instanceof TwistedEdwardsCurve) { return $this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context) ? 'libsodium' : 'PHP'; } return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ? 'OpenSSL' : 'PHP'; } /** * Returns the parameters * * @see self::getPublicKey() * @access public * @param string $type optional * @return mixed */ public function getParameters($type = 'PKCS1') { $type = self::validatePlugin('Keys', $type, 'saveParameters'); $key = $type::saveParameters($this->curve); return ECDSA::load($key, 'PKCS1') ->withHash($this->hash->getHash()) ->withSignatureFormat($this->shortFormat); } /** * Determines the signature padding mode * * Valid values are: ASN1, SSH2, Raw * * @access public * @param string $padding */ public function withSignatureFormat($format) { $new = clone $this; $new->shortFormat = $format; $new->format = self::validatePlugin('Signature', $format); return $new; } /** * Sets the context * * Used by Ed25519 / Ed448. * * @see self::sign() * @see self::verify() * @access public * @param string $context optional */ public function withContext($context = null) { if (!$this->curve instanceof TwistedEdwardsCurve) { throw new UnsupportedCurveException('Only Ed25519 and Ed448 support contexts'); } $new = clone $this; if (!isset($context)) { $new->context = null; return $new; } if (!is_string($context)) { throw new \InvalidArgumentException('setContext expects a string'); } if (strlen($context) > 255) { throw new \LengthException('The context is supposed to be, at most, 255 bytes long'); } $new->context = $context; return $new; } /** * Determines which hashing function should be used * * @access public * @param string $hash */ public function withHash($hash) { if ($this->curve instanceof Ed25519 && $hash != 'sha512') { throw new UnsupportedAlgorithmException('Ed25519 only supports sha512 as a hash'); } if ($this->curve instanceof Ed448 && $hash != 'shake256-912') { throw new UnsupportedAlgorithmException('Ed448 only supports shake256 with a length of 114 bytes'); } return parent::withHash($hash); } }<?php /** * Pure-PHP implementation of ChaCha20. * * PHP version 5 * * @category Crypt * @package ChaCha20 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2019 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\StreamCipher; use phpseclib\Exception\InsufficientSetupException; use phpseclib\Exception\BadDecryptionException; /** * Pure-PHP implementation of ChaCha20. * * @package ChaCha20 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class ChaCha20 extends Salsa20 { /** * The OpenSSL specific name of the cipher * * @var string */ protected $cipher_name_openssl = 'chacha20'; /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { switch ($engine) { case self::ENGINE_LIBSODIUM: // PHP 7.2.0 (30 Nov 2017) added support for libsodium // we could probably make it so that if $this->counter == 0 then the first block would be done with either OpenSSL // or PHP and then subsequent blocks would then be done with libsodium but idk - it's not a high priority atm // we could also make it so that if $this->counter == 0 and $this->continuousBuffer then do the first string // with libsodium and subsequent strings with openssl or pure-PHP but again not a high priority return function_exists('sodium_crypto_aead_chacha20poly1305_ietf_encrypt') && $this->key_length == 32 && (($this->usePoly1305 && !isset($this->poly1305Key) && $this->counter == 0) || $this->counter == 1) && !$this->continuousBuffer; case self::ENGINE_OPENSSL: // OpenSSL 1.1.0 (released 25 Aug 2016) added support for chacha20. // PHP didn't support OpenSSL 1.1.0 until 7.0.19 (11 May 2017) // if you attempt to provide openssl with a 128 bit key (as opposed to a 256 bit key) openssl will null // pad the key to 256 bits and still use the expansion constant for 256-bit keys. the fact that // openssl treats the IV as both the counter and nonce, however, let's us use openssl in continuous mode // whereas libsodium does not if ($this->key_length != 32) { return false; } } return parent::isValidEngineHelper($engine); } /** * Encrypts a message. * * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() * @see self::crypt() * @param string $plaintext * @return string $ciphertext */ public function encrypt($plaintext) { $this->setup(); if ($this->engine == self::ENGINE_LIBSODIUM) { return $this->encrypt_with_libsodium($plaintext); } return parent::encrypt($plaintext); } /** * Decrypts a message. * * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * At least if the continuous buffer is disabled. * * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @see self::crypt() * @param string $ciphertext * @return string $plaintext */ public function decrypt($ciphertext) { $this->setup(); if ($this->engine == self::ENGINE_LIBSODIUM) { return $this->decrypt_with_libsodium($ciphertext); } return parent::decrypt($ciphertext); } /** * Encrypts a message with libsodium * * @see self::encrypt() * @param string $plaintext * @return string $text */ private function encrypt_with_libsodium($plaintext) { $params = [$plaintext, $this->aad, $this->nonce, $this->key]; $ciphertext = strlen($this->nonce) == 8 ? sodium_crypto_aead_chacha20poly1305_encrypt(...$params) : sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params); if (!$this->usePoly1305) { return substr($ciphertext, 0, strlen($plaintext)); } $newciphertext = substr($ciphertext, 0, strlen($plaintext)); $this->newtag = $this->usingGeneratedPoly1305Key && strlen($this->nonce) == 12 ? substr($ciphertext, strlen($plaintext)) : $this->poly1305($newciphertext); return $newciphertext; } /** * Decrypts a message with libsodium * * @see self::decrypt() * @param string $ciphertext * @return string $text */ private function decrypt_with_libsodium($ciphertext) { $params = [$ciphertext, $this->aad, $this->nonce, $this->key]; if (isset($this->poly1305Key)) { if ($this->oldtag === false) { throw new InsufficientSetupException('Authentication Tag has not been set'); } if ($this->usingGeneratedPoly1305Key && strlen($this->nonce) == 12) { $plaintext = sodium_crypto_aead_chacha20poly1305_ietf_decrypt(...$params); $this->oldtag = false; if ($plaintext === false) { throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match'); } return $plaintext; } $newtag = $this->poly1305($ciphertext); if ($this->oldtag != substr($newtag, 0, strlen($this->oldtag))) { $this->oldtag = false; throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match'); } $this->oldtag = false; } $plaintext = strlen($this->nonce) == 8 ? sodium_crypto_aead_chacha20poly1305_encrypt(...$params) : sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params); return substr($plaintext, 0, strlen($ciphertext)); } /** * Sets the nonce. * * @param string $nonce */ public function setNonce($nonce) { if (!is_string($nonce)) { throw new \UnexpectedValueException('The nonce should be a string'); } /* from https://tools.ietf.org/html/rfc7539#page-7 "Note also that the original ChaCha had a 64-bit nonce and 64-bit block count. We have modified this here to be more consistent with recommendations in Section 3.2 of [RFC5116]." */ switch (strlen($nonce)) { case 8: // 64 bits case 12: // 96 bits break; default: throw new \LengthException('Nonce of size ' . strlen($nonce) . ' not supported by this algorithm. Only 64-bit nonces or 96-bit nonces are supported'); } $this->nonce = $nonce; $this->changed = true; $this->setEngine(); } /** * Setup the self::ENGINE_INTERNAL $engine * * (re)init, if necessary, the internal cipher $engine * * _setup() will be called each time if $changed === true * typically this happens when using one or more of following public methods: * * - setKey() * * - setNonce() * * - First run of encrypt() / decrypt() with no init-settings * * @see self::setKey() * @see self::setNonce() * @see self::disableContinuousBuffer() */ protected function setup() { if (!$this->changed) { return; } $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'counter' => $this->counter]; $this->changed = false; if ($this->nonce === false) { throw new InsufficientSetupException('No nonce has been defined'); } if ($this->key === false) { throw new InsufficientSetupException('No key has been defined'); } if ($this->usePoly1305 && !isset($this->poly1305Key)) { $this->usingGeneratedPoly1305Key = true; if ($this->engine == self::ENGINE_LIBSODIUM) { return; } $this->createPoly1305Key(); } $key = $this->key; if (strlen($key) == 16) { $constant = 'expand 16-byte k'; $key.= $key; } else { $constant = 'expand 32-byte k'; } $this->p1 = $constant . $key; $this->p2 = $this->nonce; if (strlen($this->nonce) == 8) { $this->p2 = "\0\0\0\0" . $this->p2; } } /** * The quarterround function * * @param int $a * @param int $b * @param int $c * @param int $d */ protected static function quarterRound(&$a, &$b, &$c, &$d) { $a+= $b; $d = self::leftRotate($d ^ $a, 16); $c+= $d; $b = self::leftRotate($b ^ $c, 12); $a+= $b; $d = self::leftRotate($d ^ $a, 8); $c+= $d; $b = self::leftRotate($b ^ $c, 7); } /** * The doubleround function * * @param int $x0...$x16 */ protected static function doubleRound(&$x0, &$x1, &$x2, &$x3, &$x4, &$x5, &$x6, &$x7, &$x8, &$x9, &$x10, &$x11, &$x12, &$x13, &$x14, &$x15) { // columnRound static::quarterRound($x0, $x4, $x8, $x12); static::quarterRound($x1, $x5, $x9, $x13); static::quarterRound($x2, $x6, $x10, $x14); static::quarterRound($x3, $x7, $x11, $x15); // rowRound static::quarterRound($x0, $x5, $x10, $x15); static::quarterRound($x1, $x6, $x11, $x12); static::quarterRound($x2, $x7, $x8, $x13); static::quarterRound($x3, $x4, $x9, $x14); } /** * The Salsa20 hash function function * * On my laptop this loop unrolled / function dereferenced version of parent::salsa20 encrypts 1mb of text in * 0.65s vs the 0.85s that it takes with the parent method. * * If we were free to assume that the host OS would always be 64-bits then the if condition in leftRotate could * be eliminated and we could knock this done to 0.60s. * * For comparison purposes, RC4 takes 0.16s and AES in CTR mode with the Eval engine takes 0.48s. * AES in CTR mode with the PHP engine takes 1.19s. Salsa20 / ChaCha20 do not benefit as much from the Eval * approach due to the fact that there are a lot less variables to de-reference, fewer loops to unroll, etc * * @param string $x */ protected static function salsa20($x) { list(, $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15) = unpack('V*', $x); $z0 = $x0; $z1 = $x1; $z2 = $x2; $z3 = $x3; $z4 = $x4; $z5 = $x5; $z6 = $x6; $z7 = $x7; $z8 = $x8; $z9 = $x9; $z10 = $x10; $z11 = $x11; $z12 = $x12; $z13 = $x13; $z14 = $x14; $z15 = $x15; // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); // columnRound $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); // rowRound $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); $x0+= $z0; $x1+= $z1; $x2+= $z2; $x3+= $z3; $x4+= $z4; $x5+= $z5; $x6+= $z6; $x7+= $z7; $x8+= $z8; $x9+= $z9; $x10+= $z10; $x11+= $z11; $x12+= $z12; $x13+= $z13; $x14+= $z14; $x15+= $z15; return pack('V*', $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15); } } <?php /** * Pure-PHP implementation of RC4. * * Uses mcrypt, if available, and an internal implementation, otherwise. * * PHP version 5 * * Useful resources are as follows: * * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm} * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4} * * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification. * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $rc4 = new \phpseclib\Crypt\RC4(); * * $rc4->setKey('abcdefgh'); * * $size = 10 * 1024; * $plaintext = ''; * for ($i = 0; $i < $size; $i++) { * $plaintext.= 'a'; * } * * echo $rc4->decrypt($rc4->encrypt($plaintext)); * ?> * </code> * * @category Crypt * @package RC4 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Crypt\Common\StreamCipher; /** * Pure-PHP implementation of RC4. * * @package RC4 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class RC4 extends StreamCipher { /**#@+ * @access private * @see \phpseclib\Crypt\RC4::_crypt() */ const ENCRYPT = 0; const DECRYPT = 1; /**#@-*/ /** * Block Length of the cipher * * RC4 is a stream cipher * so we the block_size to 0 * * @see \phpseclib\Crypt\Common\SymmetricKey::block_size * @var int * @access private */ protected $block_size = 0; /** * Key Length (in bytes) * * @see \phpseclib\Crypt\RC4::setKeyLength() * @var int * @access private */ protected $key_length = 128; // = 1024 bits /** * The mcrypt specific name of the cipher * * @see \phpseclib\Crypt\Common\SymmetricKey::cipher_name_mcrypt * @var string * @access private */ protected $cipher_name_mcrypt = 'arcfour'; /** * The Key * * @see self::setKey() * @var string * @access private */ protected $key; /** * The Key Stream for decryption and encryption * * @see self::setKey() * @var array * @access private */ private $stream; /** * Default Constructor. * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @return \phpseclib\Crypt\RC4 * @access public */ public function __construct() { parent::__construct('stream'); } /** * Test for engine validity * * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Common\SymmetricKey::isValidEngine() * * @see \phpseclib\Crypt\Common\SymmetricKey::__construct() * @param int $engine * @access protected * @return bool */ protected function isValidEngineHelper($engine) { if ($engine == self::ENGINE_OPENSSL) { if ($this->continuousBuffer) { return false; } if (version_compare(PHP_VERSION, '5.3.7') >= 0) { $this->cipher_name_openssl = 'rc4-40'; } else { switch (strlen($this->key)) { case 5: $this->cipher_name_openssl = 'rc4-40'; break; case 8: $this->cipher_name_openssl = 'rc4-64'; break; case 16: $this->cipher_name_openssl = 'rc4'; break; default: return false; } } } return parent::isValidEngineHelper($engine); } /** * RC4 does not use an IV * * @access public * @return bool */ public function usesIV() { return false; } /** * Sets the key length * * Keys can be between 1 and 256 bytes long. * * @access public * @param int $length * @throws \LengthException if the key length is invalid */ public function setKeyLength($length) { if ($length < 8 || $length > 2048) { throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 256 bytes are supported'); } $this->key_length = $length >> 3; parent::setKeyLength($length); } /** * Sets the key length * * Keys can be between 1 and 256 bytes long. * * @access public * @param string $key */ public function setKey($key) { $length = strlen($key); if ($length < 1 || $length > 256) { throw new \LengthException('Key size of ' . $length . ' bytes is not supported by RC4. Keys must be between 1 and 256 bytes long'); } parent::setKey($key); } /** * Encrypts a message. * * @see \phpseclib\Crypt\Common\SymmetricKey::decrypt() * @see self::crypt() * @access public * @param string $plaintext * @return string $ciphertext */ public function encrypt($plaintext) { if ($this->engine != self::ENGINE_INTERNAL) { return parent::encrypt($plaintext); } return $this->crypt($plaintext, self::ENCRYPT); } /** * Decrypts a message. * * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * At least if the continuous buffer is disabled. * * @see \phpseclib\Crypt\Common\SymmetricKey::encrypt() * @see self::crypt() * @access public * @param string $ciphertext * @return string $plaintext */ public function decrypt($ciphertext) { if ($this->engine != self::ENGINE_INTERNAL) { return parent::decrypt($ciphertext); } return $this->crypt($ciphertext, self::DECRYPT); } /** * Encrypts a block * * @access private * @param string $in */ protected function encryptBlock($in) { // RC4 does not utilize this method } /** * Decrypts a block * * @access private * @param string $in */ protected function decryptBlock($in) { // RC4 does not utilize this method } /** * Setup the key (expansion) * * @see \phpseclib\Crypt\Common\SymmetricKey::_setupKey() * @access private */ protected function setupKey() { $key = $this->key; $keyLength = strlen($key); $keyStream = range(0, 255); $j = 0; for ($i = 0; $i < 256; $i++) { $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; $temp = $keyStream[$i]; $keyStream[$i] = $keyStream[$j]; $keyStream[$j] = $temp; } $this->stream = []; $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = [ 0, // index $i 0, // index $j $keyStream ]; } /** * Encrypts or decrypts a message. * * @see self::encrypt() * @see self::decrypt() * @access private * @param string $text * @param int $mode * @return string $text */ private function crypt($text, $mode) { if ($this->changed) { $this->setup(); $this->changed = false; } $stream = &$this->stream[$mode]; if ($this->continuousBuffer) { $i = &$stream[0]; $j = &$stream[1]; $keyStream = &$stream[2]; } else { $i = $stream[0]; $j = $stream[1]; $keyStream = $stream[2]; } $len = strlen($text); for ($k = 0; $k < $len; ++$k) { $i = ($i + 1) & 255; $ksi = $keyStream[$i]; $j = ($j + $ksi) & 255; $ksj = $keyStream[$j]; $keyStream[$i] = $ksj; $keyStream[$j] = $ksi; $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]); } return $text; } } <?php /** * PublicKeyLoader * * Returns a PublicKey or PrivateKey object. * * @category Crypt * @package PublicKeyLoader * @author Jim Wigginton <terrafrost@php.net> * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Crypt; use phpseclib\Exception\NoKeyLoadedException; use phpseclib\Crypt\Common\PrivateKey; use phpseclib\File\X509; /** * PublicKeyLoader * * @package Common * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PublicKeyLoader { /** * Loads a public or private key * * @return AsymmetricKey * @access public * @param string $key * @param string $password optional */ public static function load($key, $password = false) { try { $new = ECDSA::load($key, false, $password); } catch (\Exception $e) {} if (!isset($new)) { try { $new = RSA::load($key, false, $password); } catch (\Exception $e) {} } if (!isset($new)) { try { $new = DSA::load($key, false, $password); } catch (\Exception $e) {} } if (isset($new)) { return $new instanceof PrivateKey ? $new->withPassword($password) : $new; } try { $x509 = new X509(); $x509->loadX509($key); $key = $x509->getPublicKey(); if ($key) { return $key; } } catch (\Exception $e) {} throw new NoKeyLoadedException('Unable to read key'); } } <?php /** * Pure-PHP ssh-agent client. * * PHP version 5 * * Here are some examples of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $agent = new \phpseclib\System\SSH\Agent(); * * $ssh = new \phpseclib\Net\SSH2('www.domain.tld'); * if (!$ssh->login('username', $agent)) { * exit('Login Failed'); * } * * echo $ssh->exec('pwd'); * echo $ssh->exec('ls -la'); * ?> * </code> * * @category System * @package SSH\Agent * @author Jim Wigginton <terrafrost@php.net> * @copyright 2014 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net * @internal See http://api.libssh.org/rfc/PROTOCOL.agent */ namespace phpseclib\System\SSH; use phpseclib\Crypt\RSA; use phpseclib\Exception\BadConfigurationException; use phpseclib\System\SSH\Agent\Identity; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\PublicKeyLoader; /** * Pure-PHP ssh-agent client identity factory * * requestIdentities() method pumps out \phpseclib\System\SSH\Agent\Identity objects * * @package SSH\Agent * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Agent { /**#@+ * Message numbers * * @access private */ // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) const SSH_AGENTC_REQUEST_IDENTITIES = 11; // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). const SSH_AGENT_IDENTITIES_ANSWER = 12; // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) const SSH_AGENTC_SIGN_REQUEST = 13; // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) const SSH_AGENT_SIGN_RESPONSE = 14; /**#@-*/ /**@+ * Agent forwarding status * * @access private */ // no forwarding requested and not active const FORWARD_NONE = 0; // request agent forwarding when opportune const FORWARD_REQUEST = 1; // forwarding has been request and is active const FORWARD_ACTIVE = 2; /**#@-*/ /** * Unused */ const SSH_AGENT_FAILURE = 5; /** * Socket Resource * * @var resource * @access private */ private $fsock; /** * Agent forwarding status * * @var int * @access private */ private $forward_status = self::FORWARD_NONE; /** * Buffer for accumulating forwarded authentication * agent data arriving on SSH data channel destined * for agent unix socket * * @var string * @access private */ private $socket_buffer = ''; /** * Tracking the number of bytes we are expecting * to arrive for the agent socket on the SSH data * channel * * @var int * @access private */ private $expected_bytes = 0; /** * The current request channel * * @var int * @access private */ private $request_channel; /** * Default Constructor * * @return \phpseclib\System\SSH\Agent * @throws \phpseclib\Exception\BadConfigurationException if SSH_AUTH_SOCK cannot be found * @throws \RuntimeException on connection errors * @access public */ public function __construct($address = null) { if (!$address) { switch (true) { case isset($_SERVER['SSH_AUTH_SOCK']): $address = $_SERVER['SSH_AUTH_SOCK']; break; case isset($_ENV['SSH_AUTH_SOCK']): $address = $_ENV['SSH_AUTH_SOCK']; break; default: throw new BadConfigurationException('SSH_AUTH_SOCK not found'); } } $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); if (!$this->fsock) { throw new \RuntimeException("Unable to connect to ssh-agent (Error $errno: $errstr)"); } } /** * Request Identities * * See "2.5.2 Requesting a list of protocol 2 keys" * Returns an array containing zero or more \phpseclib\System\SSH\Agent\Identity objects * * @return array * @throws \RuntimeException on receipt of unexpected packets * @access public */ public function requestIdentities() { if (!$this->fsock) { return []; } $packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES); if (strlen($packet) != fputs($this->fsock, $packet)) { throw new \RuntimeException('Connection closed while requesting identities'); } $length = current(unpack('N', fread($this->fsock, 4))); $packet = fread($this->fsock, $length); if (strlen($packet) != $length) { throw new \LengthException("Expected $length bytes; got " . strlen($packet)); } list($type, $keyCount) = Strings::unpackSSH2('CN', $packet); if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) { throw new \RuntimeException('Unable to request identities'); } $identities = []; for ($i = 0; $i < $keyCount; $i++) { list($key_blob, $comment) = Strings::unpackSSH2('ss', $packet); $temp = $key_blob; list($key_type) = Strings::unpackSSH2('s', $temp); switch ($key_type) { case 'ssh-rsa': case 'ssh-dss': case 'ssh-ed25519': case 'ecdsa-sha2-nistp256': case 'ecdsa-sha2-nistp384': case 'ecdsa-sha2-nistp521': $key = PublicKeyLoader::load($key_type . ' ' . base64_encode($key_blob)); } // resources are passed by reference by default if (isset($key)) { $identity = (new Identity($this->fsock)) ->withPublicKey($key) ->withPublicKeyBlob($key_blob); $identities[] = $identity; unset($key); } } return $identities; } /** * Signal that agent forwarding should * be requested when a channel is opened * * @param \phpseclib\Net\SSH2 $ssh * @return bool * @access public */ public function startSSHForwarding($ssh) { if ($this->forward_status == self::FORWARD_NONE) { $this->forward_status = self::FORWARD_REQUEST; } } /** * Request agent forwarding of remote server * * @param \phpseclib\Net\SSH2 $ssh * @return bool * @access private */ private function request_forwarding($ssh) { if (!$ssh->requestAgentForwarding()) { return false; } $this->forward_status = self::FORWARD_ACTIVE; return true; } /** * On successful channel open * * This method is called upon successful channel * open to give the SSH Agent an opportunity * to take further action. i.e. request agent forwarding * * @param \phpseclib\Net\SSH2 $ssh * @access private */ public function registerChannelOpen($ssh) { if ($this->forward_status == self::FORWARD_REQUEST) { $this->request_forwarding($ssh); } } /** * Forward data to SSH Agent and return data reply * * @param string $data * @return string Data from SSH Agent * @throws \RuntimeException on connection errors * @access public */ public function forwardData($data) { if ($this->expected_bytes > 0) { $this->socket_buffer.= $data; $this->expected_bytes -= strlen($data); } else { $agent_data_bytes = current(unpack('N', $data)); $current_data_bytes = strlen($data); $this->socket_buffer = $data; if ($current_data_bytes != $agent_data_bytes + 4) { $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes; return false; } } if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) { throw new \RuntimeException('Connection closed attempting to forward data to SSH agent'); } $this->socket_buffer = ''; $this->expected_bytes = 0; $agent_reply_bytes = current(unpack('N', fread($this->fsock, 4))); $agent_reply_data = fread($this->fsock, $agent_reply_bytes); $agent_reply_data = current(unpack('a*', $agent_reply_data)); return pack('Na*', $agent_reply_bytes, $agent_reply_data); } } <?php /** * Pure-PHP ssh-agent client. * * PHP version 5 * * @category System * @package SSH\Agent * @author Jim Wigginton <terrafrost@php.net> * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net * @internal See http://api.libssh.org/rfc/PROTOCOL.agent */ namespace phpseclib\System\SSH\Agent; use phpseclib\Crypt\RSA; use phpseclib\Crypt\DSA; use phpseclib\Crypt\ECDSA; use phpseclib\Exception\UnsupportedAlgorithmException; use phpseclib\System\SSH\Agent; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\PrivateKey; /** * Pure-PHP ssh-agent client identity object * * Instantiation should only be performed by \phpseclib\System\SSH\Agent class. * This could be thought of as implementing an interface that phpseclib\Crypt\RSA * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. * The methods in this interface would be getPublicKey and sign since those are the * methods phpseclib looks for to perform public key authentication. * * @package SSH\Agent * @author Jim Wigginton <terrafrost@php.net> * @access internal */ class Identity implements PrivateKey { /**@+ * Signature Flags * * See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3 * * @access private */ const SSH_AGENT_RSA2_256 = 2; const SSH_AGENT_RSA2_512 = 4; /**#@-*/ /** * Key Object * * @var \phpseclib\Crypt\RSA * @access private * @see self::getPublicKey() */ private $key; /** * Key Blob * * @var string * @access private * @see self::sign() */ private $key_blob; /** * Socket Resource * * @var resource * @access private * @see self::sign() */ private $fsock; /** * Signature flags * * @var int * @access private * @see self::sign() * @see self::setHash() */ private $flags = 0; /** * Curve Aliases * * @var array * @access private */ private static $curveAliases = [ 'secp256r1' => 'nistp256', 'secp384r1' => 'nistp384', 'secp521r1' => 'nistp521', 'Ed25519' => 'Ed25519' ]; /** * Default Constructor. * * @param resource $fsock * @return \phpseclib\System\SSH\Agent\Identity * @access private */ public function __construct($fsock) { $this->fsock = $fsock; } /** * Set Public Key * * Called by \phpseclib\System\SSH\Agent::requestIdentities() * * @param \phpseclib\Crypt\Common\PublicKey $key * @access private */ public function withPublicKey($key) { if ($key instanceof ECDSA) { if (is_array($key->getCurve()) || !isset(self::$curveAliases[$key->getCurve()])) { throw new UnsupportedAlgorithmException('The only supported curves are nistp256, nistp384, nistp512 and Ed25519'); } } $new = clone $this; $new->key = $key; return $new; } /** * Set Public Key * * Called by \phpseclib\System\SSH\Agent::requestIdentities(). The key blob could be extracted from $this->key * but this saves a small amount of computation. * * @param string $key_blob * @access private */ public function withPublicKeyBlob($key_blob) { $new = clone $this; $new->key_blob = $key_blob; return $new; } /** * Get Public Key * * Wrapper for $this->key->getPublicKey() * * @param string $type optional * @return mixed * @access public */ public function getPublicKey($type = 'PKCS8') { return $this->key; } /** * Sets the hash * * @param string $hash * @access public */ public function withHash($hash) { $new = clone $this; $hash = strtolower($hash); if ($this->key instanceof RSA) { $new->flags = 0; switch ($hash) { case 'sha1': break; case 'sha256': $new->flags = self::SSH_AGENT_RSA2_256; break; case 'sha512': $new->flags = self::SSH_AGENT_RSA2_512; break; default: throw new UnsupportedAlgorithmException('The only supported hashes for RSA are sha1, sha256 and sha512'); } } if ($this->key instanceof ECDSA) { switch ($this->key->getCurve()) { case 'secp256r1': $expectedHash = 'sha256'; break; case 'secp384r1': $expectedHash = 'sha384'; break; //case 'secp521r1': //case 'Ed25519': default: $expectedHash = 'sha512'; } if ($hash != $expectedHash) { throw new UnsupportedAlgorithmException('The only supported hash for ' . self::$curveAliases[$key->getCurve()] . ' is ' . $expectedHash); } } if ($this->key instanceof DSA) { if ($hash != 'sha1') { throw new UnsupportedAlgorithmException('The only supported hash for DSA is sha1'); } } return $new; } /** * Sets the padding * * Only PKCS1 padding is supported * * @param string $padding * @access public */ public function withPadding($padding) { if (!$this->key instanceof RSA) { throw new UnsupportedAlgorithmException('Only RSA keys support padding'); } if ($padding != RSA::SIGNATURE_PKCS1 && $padding != RSA::SIGNATURE_RELAXED_PKCS1) { throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures'); } return $this; } /** * Determines the signature padding mode * * Valid values are: ASN1, SSH2, Raw * * @access public * @param string $padding */ public function withSignatureFormat($format) { if ($this->key instanceof RSA) { throw new UnsupportedAlgorithmException('Only DSA and ECDSA keys support signature format setting'); } if ($format != 'SSH2') { throw new UnsupportedAlgorithmException('Only SSH2-formatted signatures are currently supported'); } return $this; } /** * Returns the curve * * Returns a string if it's a named curve, an array if not * * @access public * @return string|array */ public function getCurve() { if (!$this->key instanceof ECDSA) { throw new UnsupportedAlgorithmException('Only ECDSA keys have curves'); } return $this->key->getCurve(); } /** * Create a signature * * See "2.6.2 Protocol 2 private key signature request" * * @param string $message * @param int $padding optional * @return string * @throws \RuntimeException on connection errors * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported * @access public */ public function sign($message) { // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE $packet = Strings::packSSH2( 'CssN', Agent::SSH_AGENTC_SIGN_REQUEST, $this->key_blob, $message, $this->flags ); $packet = Strings::packSSH2('s', $packet); if (strlen($packet) != fputs($this->fsock, $packet)) { throw new \RuntimeException('Connection closed during signing'); } $length = current(unpack('N', fread($this->fsock, 4))); $packet = fread($this->fsock, $length); list($type, $signature_blob) = Strings::unpackSSH2('Cs', $packet); if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) { throw new \RuntimeException('Unable to retrieve signature'); } if (!$this->key instanceof RSA) { return $signature_blob; } list($type, $signature_blob) = Strings::unpackSSH2('ss', $signature_blob); return $signature_blob; } /** * Returns the private key * * @param string $type * @param array $options optional * @return string */ public function toString($type, array $options = []) { throw new \RuntimeException('ssh-agent does not provide a mechanism to get the private key'); } /** * Sets the password * * @access public * @param string|boolean $password */ public function withPassword($password = false) { throw new \RuntimeException('ssh-agent does not provide a mechanism to get the private key'); } } <?php /** * Prime Finite Fields * * Utilizes the factory design pattern * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math; use phpseclib\Math\Common\FiniteField; use phpseclib\Math\PrimeField\Integer; /** * Prime Finite Fields * * @package Math * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PrimeField extends FiniteField { /** * Instance Counter * * @var int */ private static $instanceCounter = 0; /** * Keeps track of current instance * * @var int */ protected $instanceID; /** * Default constructor */ public function __construct(BigInteger $modulo) { //if (!$modulo->isPrime()) { // throw new \UnexpectedValueException('PrimeField requires a prime number be passed to the constructor'); //} $this->modulo = $modulo; $this->instanceID = self::$instanceCounter++; Integer::setModulo($this->instanceID, $modulo); Integer::setRecurringModuloFunction($this->instanceID, $modulo->createRecurringModuloFunction()); } /** * Use a custom defined modular reduction function */ public function setReduction(callable $func) { $this->reduce = $func->bindTo($this, $this); } /** * Returns an instance of a dynamically generated PrimeFieldInteger class * * @return object */ public function newInteger(BigInteger $num) { return new Integer($this->instanceID, $num); } /** * Returns an integer on the finite field between one and the prime modulo * * @return object */ public function randomInteger() { static $one; if (!isset($one)) { $one = new BigInteger(1); } return new Integer($this->instanceID, BigInteger::randomRange($one, Integer::getModulo($this->instanceID))); } /** * Returns the length of the modulo in bytes * * @return integer */ public function getLengthInBytes() { return Integer::getModulo($this->instanceID)->getLengthInBytes(); } /** * Returns the length of the modulo in bits * * @return integer */ public function getLength() { return Integer::getModulo($this->instanceID)->getLength(); } }<?php /** * Binary Finite Fields * * Utilizes the factory design pattern * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Math; use ParagonIE\ConstantTime\Hex; use phpseclib\Math\Common\FiniteField; use phpseclib\Math\BinaryField\Integer; use phpseclib\Common\Functions\Strings; /** * Binary Finite Fields * * @package Math * @author Jim Wigginton <terrafrost@php.net> * @access public */ class BinaryField extends FiniteField { /** * Instance Counter * * @var int */ private static $instanceCounter = 0; /** * Keeps track of current instance * * @var int */ protected $instanceID; /** * Default constructor */ public function __construct(...$indices) { $m = array_shift($indices); $val = str_repeat('0', $m) . '1'; foreach ($indices as $index) { $val[$index] = '1'; } $modulo = static::base2ToBase256(strrev($val)); $mStart = 2 * $m - 2; $t = ceil($m / 8); $finalMask = chr((1 << ($m % 8)) - 1); if ($finalMask == "\0") { $finalMask = "\xFF"; } $bitLen = $mStart + 1; $pad = ceil($bitLen / 8); $h = $bitLen & 7; $h = $h ? 8 - $h : 0; $r = rtrim(substr($val, 0, -1), '0'); $u = [static::base2ToBase256(strrev($r))]; for ($i = 1; $i < 8; $i++) { $u[] = static::base2ToBase256(strrev(str_repeat('0', $i) . $r)); } // implements algorithm 2.40 (in section 2.3.5) in "Guide to Elliptic Curve Cryptography" // with W = 8 $reduce = function($c) use ($u, $mStart, $m, $t, $finalMask, $pad, $h) { $c = str_pad($c, $pad, "\0", STR_PAD_LEFT); for ($i = $mStart; $i >= $m;) { $g = $h >> 3; $mask = $h & 7; $mask = $mask ? 1 << (7 - $mask) : 0x80; for (; $mask > 0; $mask >>= 1, $i--, $h++) { if (ord($c[$g]) & $mask) { $temp = $i - $m; $j = $temp >> 3; $k = $temp & 7; $t1 = $j ? substr($c, 0, -$j) : $c; $length = strlen($t1); if ($length) { $t2 = str_pad($u[$k], $length, "\0", STR_PAD_LEFT); $temp = $t1 ^ $t2; $c = $j ? substr_replace($c, $temp, 0, $length) : $temp; } } } } $c = substr($c, -$t); if (strlen($c) == $t) { $c[0] = $c[0] & $finalMask; } return ltrim($c, "\0"); }; $this->instanceID = self::$instanceCounter++; Integer::setModulo($this->instanceID, $modulo); Integer::setRecurringModuloFunction($this->instanceID, $reduce); $this->randomMax = new BigInteger($modulo, 2); } /** * Returns an instance of a dynamically generated PrimeFieldInteger class * * @param string $num * @return object */ public function newInteger($num) { return new Integer($this->instanceID, $num instanceof BigInteger ? $num->toBytes() : $num); } /** * Returns an integer on the finite field between one and the prime modulo * * @return object */ public function randomInteger() { static $one; if (!isset($one)) { $one = new BigInteger(1); } return new Integer($this->instanceID, BigInteger::randomRange($one, $this->randomMax)->toBytes()); } /** * Returns the length of the modulo in bytes * * @return integer */ public function getLengthInBytes() { return strlen(Integer::getModulo($this->instanceID)); } /** * Returns the length of the modulo in bits * * @return integer */ public function getLength() { return strlen(Integer::getModulo($this->instanceID)) << 3; } /** * Converts a base-2 string to a base-256 string * * @param string $x * @param integer $size * @return string */ public static function base2ToBase256($x, $size = null) { $str = Strings::bits2bin($x); $pad = strlen($x) >> 3; if (strlen($x) & 3) { $pad++; } $str = str_pad($str, $pad, "\0", STR_PAD_LEFT); if (isset($size)) { $str = str_pad($str, $size, "\0", STR_PAD_LEFT); } return $str; } /** * Converts a base-256 string to a base-2 string * * @param string $x * @return string */ public static function base256ToBase2($x) { if (function_exists('gmp_import')) { return gmp_strval(gmp_import($x), 2); } return Strings::bin2bits($x); } }<?php /** * Binary Finite Fields * * In a binary finite field numbers are actually polynomial equations. If you * represent the number as a sequence of bits you get a sequence of 1's or 0's. * These 1's or 0's represent the coefficients of the x**n, where n is the * location of the given bit. When you add numbers over a binary finite field * the result should have a coefficient of 1 or 0 as well. Hence addition * and subtraction become the same operation as XOR. * eg. 1 + 1 + 1 == 3 % 2 == 1 or 0 - 1 == -1 % 2 == 1 * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Math\BinaryField; use phpseclib\Math\Common\FiniteField\Integer as Base; use phpseclib\Math\BigInteger; use phpseclib\Math\BinaryField; use ParagonIE\ConstantTime\Hex; /** * Binary Finite Fields * * @package Math * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Integer extends Base { /** * Holds the BinaryField's value * * @var string */ protected $value; /** * Keeps track of current instance * * @var int */ protected $instanceID; /** * Holds the PrimeField's modulo * * @var string[] */ protected static $modulo; /** * Holds a pre-generated function to perform modulo reductions * * @var callable[] */ protected static $reduce; /** * Default constructor */ public function __construct($instanceID, $num = '') { $this->instanceID = $instanceID; if (!strlen($num)) { $this->value = ''; } else { $reduce = static::$reduce[$instanceID]; $this->value = $reduce($num); } } /** * Set the modulo for a given instance */ public static function setModulo($instanceID, $modulo) { static::$modulo[$instanceID] = $modulo; } /** * Set the modulo for a given instance */ public static function setRecurringModuloFunction($instanceID, callable $function) { static::$reduce[$instanceID] = $function; } /** * Tests a parameter to see if it's of the right instance * * Throws an exception if the incorrect class is being utilized */ private static function checkInstance(self $x, self $y) { if ($x->instanceID != $y->instanceID) { throw new \UnexpectedValueException('The instances of the two BinaryField\Integer objects do not match'); } } /** * Tests the equality of two numbers. * * @return bool */ public function equals(self $x) { static::checkInstance($this, $x); return $this->value == $x->value; } /** * Compares two numbers. * * @return int */ public function compare(self $x) { static::checkInstance($this, $x); $a = $this->value; $b = $x->value; $length = max(strlen($a), strlen($b)); $a = str_pad($a, $length, "\0", STR_PAD_LEFT); $b = str_pad($b, $length, "\0", STR_PAD_LEFT); return strcmp($a, $b); } /** * Returns the degree of the polynomial * * @param string $x * @return int */ private static function deg($x) { $x = ltrim($x, "\0"); $xbit = decbin(ord($x[0])); $xlen = $xbit == '0' ? 0 : strlen($xbit); $len = strlen($x); if (!$len) { return -1; } return 8 * strlen($x) - 9 + $xlen; } /** * Perform polynomial division * * @return string[] * @link https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclidean_division */ private static function polynomialDivide($x, $y) { // in wikipedia's description of the algorithm, lc() is the leading coefficient. over a binary field that's // always going to be 1. $q = chr(0); $d = static::deg($y); $r = $x; while (($degr = static::deg($r)) >= $d) { $s = '1' . str_repeat('0', $degr - $d); $s = BinaryField::base2ToBase256($s); $length = max(strlen($s), strlen($q)); $q = !isset($q) ? $s : str_pad($q, $length, "\0", STR_PAD_LEFT) ^ str_pad($s, $length, "\0", STR_PAD_LEFT); $s = static::polynomialMultiply($s, $y); $length = max(strlen($r), strlen($s)); $r = str_pad($r, $length, "\0", STR_PAD_LEFT) ^ str_pad($s, $length, "\0", STR_PAD_LEFT); } return [ltrim($q, "\0"), ltrim($r, "\0")]; } /** * Perform polynomial multiplation in the traditional way * * @return string * @link https://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplication */ private static function regularPolynomialMultiply($x, $y) { $precomputed = [ltrim($x, "\0")]; $x = strrev(BinaryField::base256ToBase2($x)); $y = strrev(BinaryField::base256ToBase2($y)); if (strlen($x) == strlen($y)) { $length = strlen($x); } else { $length = max(strlen($x), strlen($y)); $x = str_pad($x, $length, '0'); $y = str_pad($y, $length, '0'); } $result = str_repeat('0', 2 * $length - 1); $result = BinaryField::base2ToBase256($result); $size = strlen($result); $x = strrev($x); // precompute left shift 1 through 7 for ($i = 1; $i < 8; $i++) { $precomputed[$i] = BinaryField::base2ToBase256($x . str_repeat('0', $i)); } for ($i = 0; $i < strlen($y); $i++) { if ($y[$i] == '1') { $temp = $precomputed[$i & 7] . str_repeat("\0", $i >> 3); $result^= str_pad($temp, $size, "\0", STR_PAD_LEFT); } } return $result; } /** * Perform polynomial multiplation * * Uses karatsuba multiplication to reduce x-bit multiplications to a series of 32-bit multiplications * * @return string * @link https://en.wikipedia.org/wiki/Karatsuba_algorithm */ private static function polynomialMultiply($x, $y) { if (strlen($x) == strlen($y)) { $length = strlen($x); } else { $length = max(strlen($x), strlen($y)); $x = str_pad($x, $length, "\0", STR_PAD_LEFT); $y = str_pad($y, $length, "\0", STR_PAD_LEFT); } switch (true) { case PHP_INT_SIZE == 8 && $length <= 4: return $length != 4 ? self::subMultiply(str_pad($x, 4, "\0", STR_PAD_LEFT), str_pad($y, 4, "\0", STR_PAD_LEFT)) : self::subMultiply($x, $y); case PHP_INT_SIZE == 4 || $length > 32: return self::regularPolynomialMultiply($x, $y); } $m = $length >> 1; $x1 = substr($x, 0, -$m); $x0 = substr($x, -$m); $y1 = substr($y, 0, -$m); $y0 = substr($y, -$m); $z2 = self::polynomialMultiply($x1, $y1); $z0 = self::polynomialMultiply($x0, $y0); $z1 = self::polynomialMultiply( self::subAdd2($x1, $x0), self::subAdd2($y1, $y0) ); $z1 = self::subAdd3($z1, $z2, $z0); $xy = self::subAdd3( $z2 . str_repeat("\0", 2 * $m), $z1 . str_repeat("\0", $m), $z0 ); return ltrim($xy, "\0"); } /** * Perform polynomial multiplication on 2x 32-bit numbers, returning * a 64-bit number * * @param string $x * @param string $y * @return string * @link https://www.bearssl.org/constanttime.html#ghash-for-gcm */ private static function subMultiply($x, $y) { $x = unpack('N', $x)[1]; $y = unpack('N', $y)[1]; $x0 = $x & 0x11111111; $x1 = $x & 0x22222222; $x2 = $x & 0x44444444; $x3 = $x & 0x88888888; $y0 = $y & 0x11111111; $y1 = $y & 0x22222222; $y2 = $y & 0x44444444; $y3 = $y & 0x88888888; $z0 = ($x0 * $y0) ^ ($x1 * $y3) ^ ($x2 * $y2) ^ ($x3 * $y1); $z1 = ($x0 * $y1) ^ ($x1 * $y0) ^ ($x2 * $y3) ^ ($x3 * $y2); $z2 = ($x0 * $y2) ^ ($x1 * $y1) ^ ($x2 * $y0) ^ ($x3 * $y3); $z3 = ($x0 * $y3) ^ ($x1 * $y2) ^ ($x2 * $y1) ^ ($x3 * $y0); $z0&= 0x1111111111111111; $z1&= 0x2222222222222222; $z2&= 0x4444444444444444; $z3&= -8608480567731124088; // 0x8888888888888888 gets interpreted as a float $z = $z0 | $z1 | $z2 | $z3; return pack('J', $z); } /** * Adds two numbers * * @param string $x * @param string $y * @return string */ private static function subAdd2($x, $y) { $length = max(strlen($x), strlen($y)); $x = str_pad($x, $length, "\0", STR_PAD_LEFT); $y = str_pad($y, $length, "\0", STR_PAD_LEFT); return $x ^ $y; } /** * Adds three numbers * * @param string $x * @param string $y * @return string */ private static function subAdd3($x, $y, $z) { $length = max(strlen($x), strlen($y), strlen($z)); $x = str_pad($x, $length, "\0", STR_PAD_LEFT); $y = str_pad($y, $length, "\0", STR_PAD_LEFT); $z = str_pad($z, $length, "\0", STR_PAD_LEFT); return $x ^ $y ^ $z; } /** * Adds two BinaryFieldIntegers. * * @return static */ public function add(self $y) { static::checkInstance($this, $y); $length = strlen(static::$modulo[$this->instanceID]); $x = str_pad($this->value, $length, "\0", STR_PAD_LEFT); $y = str_pad($y->value, $length, "\0", STR_PAD_LEFT); return new static($this->instanceID, $x ^ $y); } /** * Subtracts two BinaryFieldIntegers. * * @return static */ public function subtract(self $x) { return $this->add($x); } /** * Multiplies two BinaryFieldIntegers. * * @return static */ public function multiply(self $y) { static::checkInstance($this, $y); return new static($this->instanceID, static::polynomialMultiply($this->value, $y->value)); } /** * Returns the modular inverse of a BinaryFieldInteger * * @return static */ public function modInverse() { $remainder0 = static::$modulo[$this->instanceID]; $remainder1 = $this->value; if ($remainder1 == '') { return new static($this->instanceID); } $aux0 = "\0"; $aux1 = "\1"; while ($remainder1 != "\1") { list($q, $r) = static::polynomialDivide($remainder0, $remainder1); $remainder0 = $remainder1; $remainder1 = $r; // the auxiliary in row n is given by the sum of the auxiliary in // row n-2 and the product of the quotient and the auxiliary in row // n-1 $temp = static::polynomialMultiply($aux1, $q); $aux = str_pad($aux0, strlen($temp), "\0", STR_PAD_LEFT) ^ str_pad($temp, strlen($aux0), "\0", STR_PAD_LEFT); $aux0 = $aux1; $aux1 = $aux; } $temp = new static($this->instanceID); $temp->value = ltrim($aux1, "\0"); return $temp; } /** * Divides two PrimeFieldIntegers. * * @return static */ public function divide(self $x) { static::checkInstance($this, $x); $x = $x->modInverse(); return $this->multiply($x); } /** * Negate * * A negative number can be written as 0-12. With modulos, 0 is the same thing as the modulo * so 0-12 is the same thing as modulo-12 * * @return object */ public function negate() { $x = str_pad($this->value, strlen(static::$modulo[$this->instanceID]), "\0", STR_PAD_LEFT); return new static($this->instanceID, $x ^ static::$modulo[$this->instanceID]); } /** * Returns the modulo * * @return integer */ public static function getModulo($instanceID) { return static::$modulo[$instanceID]; } /** * Converts an Integer to a byte string (eg. base-256). * * @return string */ public function toBytes() { return str_pad($this->value, strlen(static::$modulo[$this->instanceID]), "\0", STR_PAD_LEFT); } /** * Converts an Integer to a hex string (eg. base-16). * * @return string */ public function toHex() { return Hex::encode($this->toBytes()); } /** * Converts an Integer to a bit string (eg. base-2). * * @return string */ public function toBits() { //return str_pad(BinaryField::base256ToBase2($this->value), strlen(static::$modulo[$this->instanceID]), '0', STR_PAD_LEFT); return BinaryField::base256ToBase2($this->value); } /** * Converts an Integer to a BigInteger * * @return string */ public function toBigInteger() { return new BigInteger($this->value, 256); } /** * __toString() magic method * * @access public */ public function __toString() { return (string) $this->toBigInteger(); } /** * __debugInfo() magic method * * @access public */ public function __debugInfo() { return ['value' => $this->toHex()]; } }<?php /** * Pure-PHP arbitrary precision integer arithmetic library. * * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available, * and an internal implementation, otherwise. * * PHP version 5 and 7 * * Here's an example of how to use this library: * <code> * <?php * $a = new \phpseclib\Math\BigInteger(2); * $b = new \phpseclib\Math\BigInteger(3); * * $c = $a->add($b); * * echo $c->toString(); // outputs 5 * ?> * </code> * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Math; use phpseclib\Exception\BadConfigurationException; /** * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 * numbers. * * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @access public */ class BigInteger implements \Serializable { /** * Main Engine * * @var string */ private static $mainEngine; /** * Modular Exponentiation Engine * * @var string */ private static $modexpEngine; /** * Selected Engines * * @var array */ private static $engines; /** * The actual BigInteger object * * @var object */ private $value; /** * Sets engine type. * * Throws an exception if the type is invalid * * @param string $main * @param array $modexps optional */ public static function setEngine($main, $modexps = ['DefaultEngine']) { self::$engines = []; $fqmain = 'phpseclib\\Math\\BigInteger\\Engines\\' . $main; if (!class_exists($fqmain) || !method_exists($fqmain, 'isValidEngine')) { throw new \InvalidArgumentException("$main is not a valid engine"); } if (!$fqmain::isValidEngine()) { throw new BadConfigurationException("$main is not setup correctly on this system"); } self::$mainEngine = $fqmain; if (!in_array('Default', $modexps)) { $modexps[] = 'DefaultEngine'; } $found = false; foreach ($modexps as $modexp) { try { $fqmain::setModExpEngine($modexp); $found = true; break; } catch (\Exception $e) { } } if (!$found) { throw new BadConfigurationException("No valid modular exponentiation engine found for $main"); } self::$modexpEngine = $modexp; self::$engines = [$main, $modexp]; } /** * Returns the engine type * * @return string[] */ public static function getEngine() { self::initialize_static_variables(); return self::$engines; } /** * Initialize static variables */ private static function initialize_static_variables() { if (!isset(self::$mainEngine)) { $engines = [ ['GMP'], ['PHP64', ['OpenSSL']], ['BCMath', ['OpenSSL']], ['PHP32', ['OpenSSL']] ]; foreach ($engines as $engine) { try { self::setEngine($engine[0], isset($engine[1]) ? $engine[1] : []); break; } catch (\Exception $e) { } } } } /** * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers. * * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. * * @param $x integer|BigInteger\Engines\Engine Base-10 number or base-$base number if $base set. * @param int $base * @return BigInteger */ public function __construct($x = 0, $base = 10) { self::initialize_static_variables(); if ($x instanceof self::$mainEngine) { $this->value = clone $x; } elseif ($x instanceof BigInteger\Engines\Engine) { $this->value = new static("$x"); $this->value->setPrecision($x->getPrecision()); } else { $this->value = new self::$mainEngine($x, $base); } } /** * Converts a BigInteger to a base-10 number. * * @return string */ public function toString() { return $this->value->toString(); } /** * __toString() magic method */ public function __toString() { return (string) $this->value; } /** * __debugInfo() magic method * * Will be called, automatically, when print_r() or var_dump() are called */ public function __debugInfo() { return $this->value->__debugInfo(); } /** * Converts a BigInteger to a byte string (eg. base-256). * * @param bool $twos_compliment * @return string */ public function toBytes($twos_compliment = false) { return $this->value->toBytes($twos_compliment); } /** * Converts a BigInteger to a hex string (eg. base-16). * * @param bool $twos_compliment * @return string */ public function toHex($twos_compliment = false) { return $this->value->toHex($twos_compliment); } /** * Converts a BigInteger to a bit string (eg. base-2). * * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're * saved as two's compliment. * * @param bool $twos_compliment * @return string */ function toBits($twos_compliment = false) { return $this->value->toBits($twos_compliment); } /** * Adds two BigIntegers. * * @param BigInteger $y * @return BigInteger */ public function add(BigInteger $y) { return new static($this->value->add($y->value)); } /** * Subtracts two BigIntegers. * * @param BigInteger $y * @return BigInteger */ function subtract(BigInteger $y) { return new static($this->value->subtract($y->value)); } /** * Multiplies two BigIntegers * * @param BigInteger $x * @return BigInteger */ public function multiply(BigInteger $x) { return new static($this->value->multiply($x->value)); } /** * Divides two BigIntegers. * * Returns an array whose first element contains the quotient and whose second element contains the * "common residue". If the remainder would be positive, the "common residue" and the remainder are the * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder * and the divisor (basically, the "common residue" is the first positive modulo). * * Here's an example: * <code> * <?php * $a = new \phpseclib\Math\BigInteger('10'); * $b = new \phpseclib\Math\BigInteger('20'); * * list($quotient, $remainder) = $a->divide($b); * * echo $quotient->toString(); // outputs 0 * echo "\r\n"; * echo $remainder->toString(); // outputs 10 * ?> * </code> * * @param BigInteger $y * @return BigInteger[] */ public function divide(BigInteger $y) { list($q, $r) = $this->value->divide($y->value); return [ new static($q), new static($r) ]; } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * @return BigInteger * @param BigInteger $n */ public function modInverse(BigInteger $n) { return new static($this->value->modInverse($n->value)); } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * @return BigInteger[] * @param BigInteger $n */ public function extendedGCD(BigInteger $n) { extract($this->value->extendedGCD($n->value)); /** * @var BigInteger $gcd * @var BigInteger $x * @var BigInteger $y */ return [ 'gcd' => new static($gcd), 'x' => new static($x), 'y' => new static($y) ]; } /** * Calculates the greatest common divisor * * Say you have 693 and 609. The GCD is 21. * * @param BigInteger $n * @return BigInteger */ public function gcd(BigInteger $n) { return new static($this->value->gcd($n->value)); } /** * Absolute value. * * @return BigInteger * @access public */ public function abs() { return new static($this->value->abs()); } /** * Set Precision * * Some bitwise operations give different results depending on the precision being used. Examples include left * shift, not, and rotates. * * @param int $bits */ public function setPrecision($bits) { $this->value->setPrecision($bits); } /** * Get Precision * * Returns the precision if it exists, false if it doesn't * * @return int|bool */ public function getPrecision() { return $this->value->getPrecision(); } /** * Serialize * * Will be called, automatically, when serialize() is called on a BigInteger object. * * phpseclib 1.0 serialized strings look like this: * O:15:"Math_BigInteger":1:{s:3:"hex";s:18:"00ab54a98ceb1f0ad2";} * * phpseclib 3.0 serialized strings look like this: * C:25:"phpseclib\Math\BigInteger":42:{a:1:{s:3:"hex";s:18:"00ab54a98ceb1f0ad2";}} * * @return string */ public function serialize() { $val = ['hex' => $this->toHex(true)]; $precision = $this->value->getPrecision(); if ($precision > 0) { $val['precision'] = $precision; } return serialize($val); } /** * Serialize * * Will be called, automatically, when unserialize() is called on a BigInteger object. * * @param string $serialized */ public function unserialize($serialized) { $r = unserialize($serialized); $temp = new static($r['hex'], -16); $this->value = $temp->value; if (isset($r['precision'])) { // recalculate $this->bitmask $this->setPrecision($r['precision']); } } /** * Performs modular exponentiation. * * @param BigInteger $e * @param BigInteger $n * @return BigInteger */ public function powMod(BigInteger $e, BigInteger $n) { return new static($this->value->powMod($e->value, $n->value)); } /** * Performs modular exponentiation. * * @param BigInteger $e * @param BigInteger $n * @return BigInteger */ public function modPow(BigInteger $e, BigInteger $n) { return new static($this->value->modPow($e->value, $n->value)); } /** * Compares two numbers. * * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is * demonstrated thusly: * * $x > $y: $x->compare($y) > 0 * $x < $y: $x->compare($y) < 0 * $x == $y: $x->compare($y) == 0 * * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). * * @param BigInteger $y * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. * @access public * @see self::equals() * @internal Could return $this->subtract($x), but that's not as fast as what we do do. */ public function compare(BigInteger $y) { return $this->value->compare($y->value); } /** * Tests the equality of two numbers. * * If you need to see if one number is greater than or less than another number, use BigInteger::compare() * * @param BigInteger $x * @return bool */ public function equals(BigInteger $x) { return $this->value->equals($x->value); } /** * Logical Not * * @return BigInteger */ public function bitwise_not() { return new static($this->value->bitwise_not()); } /** * Logical And * * @param BigInteger $x * @return BigInteger */ public function bitwise_and(BigInteger $x) { return new static($this->value->bitwise_and($x->value)); } /** * Logical Or * * @param BigInteger $x * @return BigInteger */ public function bitwise_or(BigInteger $x) { return new static($this->value->bitwise_or($x->value)); } /** * Logical Exclusive Or * * @param BigInteger $x * @return BigInteger */ public function bitwise_xor(BigInteger $x) { return new static($this->value->bitwise_xor($x->value)); } /** * Logical Right Shift * * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. * * @param int $shift * @return BigInteger */ public function bitwise_rightShift($shift) { return new static($this->value->bitwise_rightShift($shift)); } /** * Logical Left Shift * * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. * * @param int $shift * @return BigInteger */ public function bitwise_leftShift($shift) { return new static($this->value->bitwise_leftShift($shift)); } /** * Logical Left Rotate * * Instead of the top x bits being dropped they're appended to the shifted bit string. * * @param int $shift * @return BigInteger */ public function bitwise_leftRotate($shift) { return new static($this->value->bitwise_leftRotate($shift)); } /** * Logical Right Rotate * * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. * * @param int $shift * @return BigInteger */ public function bitwise_rightRotate($shift) { return new static($this->value->bitwise_rightRotate($shift)); } /** * Returns the smallest and largest n-bit number * * @param int $bits * @return BigInteger[] */ public static function minMaxBits($bits) { self::initialize_static_variables(); $class = self::$mainEngine; extract($class::minMaxBits($bits)); /** @var BigInteger $min * @var BigInteger $max */ return [ 'min' => new static($min), 'max' => new static($max) ]; } /** * Return the size of a BigInteger in bits * * @return int */ public function getLength() { return $this->value->getLength(); } /** * Return the size of a BigInteger in bytes * * @return int */ public function getLengthInBytes() { return $this->value->getLengthInBytes(); } /** * Generates a random number of a certain size * * Bit length is equal to $size * * @param int $size * @return BigInteger */ public static function random($size) { self::initialize_static_variables(); $class = self::$mainEngine; return new static($class::random($size)); } /** * Generates a random prime number of a certain size * * Bit length is equal to $size * * @param int $size * @return BigInteger */ public static function randomPrime($size) { self::initialize_static_variables(); $class = self::$mainEngine; return new static($class::randomPrime($size)); } /** * Generate a random prime number between a range * * If there's not a prime within the given range, false will be returned. * * @param BigInteger $min * @param BigInteger $max * @return false|BigInteger */ public static function randomRangePrime(BigInteger $min, BigInteger $max) { $class = self::$mainEngine; return new static($class::randomRangePrime($min->value, $max->value)); } /** * Generate a random number between a range * * Returns a random number between $min and $max where $min and $max * can be defined using one of the two methods: * * BigInteger::randomRange($min, $max) * BigInteger::randomRange($max, $min) * * @param BigInteger $min * @param BigInteger $max * @return BigInteger */ public static function randomRange(BigInteger $min, BigInteger $max) { $class = self::$mainEngine; return new static($class::randomRange($min->value, $max->value)); } /** * Checks a numer to see if it's prime * * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the * $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads * on a website instead of just one. * * @param int|bool $t * @return bool */ public function isPrime($t = false) { return $this->value->isPrime($t); } /** * Calculates the nth root of a biginteger. * * Returns the nth root of a positive biginteger, where n defaults to 2 * * @param int $n optional * @return BigInteger */ public function root($n = 2) { return new static($this->value->root($n)); } /** * Performs exponentiation. * * @param BigInteger $n * @return BigInteger */ public function pow(BigInteger $n) { return new static($this->value->pow($n->value)); } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param BigInteger[] $nums * @return BigInteger */ public static function min(...$nums) { $class = self::$mainEngine; $nums = array_map(function($num) { return $num->value; }, $nums); return new static($class::min(...$nums)); } /** * Return the maximum BigInteger between an arbitrary number of BigIntegers. * * @param BigInteger[] $nums * @return BigInteger */ public static function max(...$nums) { $class = self::$mainEngine; $nums = array_map(function($num) { return $num->value; }, $nums); return new static($class::max(...$nums)); } /** * Tests BigInteger to see if it is between two integers, inclusive * * @param BigInteger $min * @param BigInteger $max * @return bool */ public function between(BigInteger $min, BigInteger $max) { return $this->value->between($min->value, $max->value); } /** * Clone */ public function __clone() { $this->value = clone $this->value; } /** * Is Odd? * * @return boolean */ public function isOdd() { return $this->value->isOdd(); } /** * Tests if a bit is set * * @param int $x * @return boolean */ public function testBit($x) { return $this->value->testBit($x); } /** * Is Negative? * * @return boolean */ public function isNegative() { return $this->value->isNegative(); } /** * Negate * * Given $k, returns -$k * * @return BigInteger */ public function negate() { return new static($this->value->negate()); } /** * Scan for 1 and right shift by that amount * * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); * * @param BigInteger $r * @return int */ public static function scan1divide(BigInteger $r) { $class = self::$mainEngine; return $class::scan1divide($r->value); } /** * Create Recurring Modulo Function * * Sometimes it may be desirable to do repeated modulos with the same number outside of * modular exponentiation * * @return callable */ public function createRecurringModuloFunction() { $func = $this->value->createRecurringModuloFunction(); return function(BigInteger $x) use ($func) { return new static($func($x->value)); }; } /** * Bitwise Split * * Splits BigInteger's into chunks of $split bits * * @param int $split * @return \phpseclib\Math\BigInteger[] */ public function bitwise_split($split) { return array_map(function($val) { return new static($val); }, $this->value->bitwise_split($split)); } }<?php /** * Finite Fields Base Class * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Math\Common; /** * Finite Fields * * @package Math * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class FiniteField { }<?php /** * Finite Field Integer Base Class * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Math\Common\FiniteField; /** * Finite Field Integer * * @package Math * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Integer { }<?php /** * GMP Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\GMP; use phpseclib\Math\BigInteger\Engines\GMP; /** * GMP Modular Exponentiation Engine * * @package GMP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DefaultEngine extends GMP { /** * Performs modular exponentiation. * * @param GMP $x * @param GMP $e * @param GMP $n * @return GMP */ protected static function powModHelper(GMP $x, GMP $e, GMP $n) { $temp = new GMP(); $temp->value = gmp_powm($x->value, $e->value, $n->value); return $x->normalize($temp); } }<?php /** * PHP Barrett Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP\Reductions; use phpseclib\Math\BigInteger\Engines\PHP\Base; /** * PHP Barrett Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Barrett extends Base { /** * Barrett Modular Reduction * * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} / * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly, * so as not to require negative numbers (initially, this script didn't support negative numbers). * * Employs "folding", as described at * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." * * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that * usable on account of (1) its not using reasonable radix points as discussed in * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line * comments for details. * * @param array $n * @param array $m * @param string $class * @return array */ protected static function reduce(array $n, array $m, $class) { static $cache = [ self::VARIABLE => [], self::DATA => [] ]; $m_length = count($m); // if (self::compareHelper($n, $static::square($m)) >= 0) { if (count($n) > 2 * $m_length) { $lhs = new $class(); $rhs = new $class(); $lhs->value = $n; $rhs->value = $m; list(, $temp) = $lhs->divide($rhs); return $temp->value; } // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced if ($m_length < 5) { return self::regularBarrett($n, $m, $class); } // n = 2 * m.length if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); $cache[self::VARIABLE][] = $m; $lhs = new $class(); $lhs_value = &$lhs->value; $lhs_value = self::array_repeat(0, $m_length + ($m_length >> 1)); $lhs_value[] = 1; $rhs = new $class(); $rhs->value = $m; list($u, $m1) = $lhs->divide($rhs); $u = $u->value; $m1 = $m1->value; $cache[self::DATA][] = [ 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) 'm1'=> $m1 // m.length ]; } else { extract($cache[self::DATA][$key]); } $cutoff = $m_length + ($m_length >> 1); $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1) $msd = array_slice($n, $cutoff); // m.length >> 1 $lsd = self::trim($lsd); $temp = $class::multiplyHelper($msd, false, $m1, false); // m.length + (m.length >> 1) $n = $class::addHelper($lsd, false, $temp[self::VALUE], false); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers) //if ($m_length & 1) { // return self::regularBarrett($n[self::VALUE], $m, $class); //} // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 $temp = array_slice($n[self::VALUE], $m_length - 1); // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 $temp = $class::multiplyHelper($temp, false, $u, false); // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) $temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1); // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) $temp = $class::multiplyHelper($temp, false, $m, false); // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). $result = $class::subtractHelper($n[self::VALUE], false, $temp[self::VALUE], false); while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) { $result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $m, false); } return $result[self::VALUE]; } /** * (Regular) Barrett Modular Reduction * * For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this * is that this function does not fold the denominator into a smaller form. * * @param array $x * @param array $n * @param string $class * @return array */ private static function regularBarrett(array $x, array $n, $class) { static $cache = [ self::VARIABLE => [], self::DATA => [] ]; $n_length = count($n); if (count($x) > 2 * $n_length) { $lhs = new $class(); $rhs = new $class(); $lhs->value = $x; $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } if (($key = array_search($n, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); $cache[self::VARIABLE][] = $n; $lhs = new $class(); $lhs_value = &$lhs->value; $lhs_value = self::array_repeat(0, 2 * $n_length); $lhs_value[] = 1; $rhs = new $class(); $rhs->value = $n; list($temp, ) = $lhs->divide($rhs); // m.length $cache[self::DATA][] = $temp->value; } // 2 * m.length - (m.length - 1) = m.length + 1 $temp = array_slice($x, $n_length - 1); // (m.length + 1) + m.length = 2 * m.length + 1 $temp = $class::multiplyHelper($temp, false, $cache[self::DATA][$key], false); // (2 * m.length + 1) - (m.length - 1) = m.length + 2 $temp = array_slice($temp[self::VALUE], $n_length + 1); // m.length + 1 $result = array_slice($x, 0, $n_length + 1); // m.length + 1 $temp = self::multiplyLower($temp, false, $n, false, $n_length + 1, $class); // $temp == array_slice($class::regularMultiply($temp, false, $n, false)->value, 0, $n_length + 1) if (self::compareHelper($result, false, $temp[self::VALUE], $temp[self::SIGN]) < 0) { $corrector_value = self::array_repeat(0, $n_length + 1); $corrector_value[count($corrector_value)] = 1; $result = $class::addHelper($result, false, $corrector_value, false); $result = $result[self::VALUE]; } // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits $result = $class::subtractHelper($result, false, $temp[self::VALUE], $temp[self::SIGN]); while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $n, false) > 0) { $result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $n, false); } return $result[self::VALUE]; } /** * Performs long multiplication up to $stop digits * * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved. * * @see self::regularBarrett() * @param array $x_value * @param bool $x_negative * @param array $y_value * @param bool $y_negative * @param int $stop * @param string $class * @return array */ private static function multiplyLower(array $x_value, $x_negative, array $y_value, $y_negative, $stop, $class) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { // a 0 is being multiplied return [ self::VALUE => [], self::SIGN => false ]; } if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_length = count($x_value); $y_length = count($y_value); } $product_value = self::array_repeat(0, $x_length + $y_length); // the following for loop could be removed if the for loop following it // (the one with nested for loops) initially set $i to 0, but // doing so would also make the result in one set of unnecessary adds, // since on the outermost loops first pass, $product->value[$k] is going // to always be 0 $carry = 0; for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $carry = $class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$j] = (int) ($temp - $class::BASE_FULL * $carry); } if ($j < $stop) { $product_value[$j] = $carry; } // the above for loop is what the previous comment was talking about. the // following for loop is the "one with nested for loops" for ($i = 1; $i < $y_length; ++$i) { $carry = 0; for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $carry = $class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$k] = (int) ($temp - $class::BASE_FULL * $carry); } if ($k < $stop) { $product_value[$k] = $carry; } } return [ self::VALUE => self::trim($product_value), self::SIGN => $x_negative != $y_negative ]; } }<?php /** * PHP Classic Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP\Reductions; use phpseclib\Math\BigInteger\Engines\PHP\Base; /** * PHP Classic Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Classic extends Base { /** * Regular Division * * @param array $x * @param array $n * @param string $class * @return array */ protected static function reduce(array $x, array $n, $class) { $lhs = new $class(); $lhs->value = $x; $rhs = new $class(); $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } }<?php /** * PHP Montgomery Modular Exponentiation Engine with interleaved multiplication * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP\Reductions; use phpseclib\Math\BigInteger\Engines\PHP\Base; /** * PHP Montgomery Modular Exponentiation Engine with interleaved multiplication * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class MontgomeryMult extends Montgomery { /** * Montgomery Multiply * * Interleaves the montgomery reduction and long multiplication algorithms together as described in * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} * * @see self::_prepMontgomery() * @see self::_montgomery() * @access private * @param array $x * @param array $y * @param array $m * @param string $class * @return array */ public static function multiplyReduce(array $x, array $y, array $m, $class) { // the following code, although not callable, can be run independently of the above code // although the above code performed better in my benchmarks the following could might // perform better under different circumstances. in lieu of deleting it it's just been // made uncallable static $cache = [ self::VARIABLE => [], self::DATA => [] ]; if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); $cache[self::VARIABLE][] = $m; $cache[self::DATA][] = self::modInverse67108864($m, $class); } $n = max(count($x), count($y), count($m)); $x = array_pad($x, $n, 0); $y = array_pad($y, $n, 0); $m = array_pad($m, $n, 0); $a = [self::VALUE => self::array_repeat(0, $n + 1)]; for ($i = 0; $i < $n; ++$i) { $temp = $a[self::VALUE][0] + $x[$i] * $y[0]; $temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); $temp = $temp * $cache[self::DATA][$key]; $temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); $temp = $class::addHelper($class::regularMultiply([$x[$i]], $y), false, $class::regularMultiply([$temp], $m), false); $a = $class::addHelper($a[self::VALUE], false, $temp[self::VALUE], false); $a[self::VALUE] = array_slice($a[self::VALUE], 1); } if (self::compareHelper($a[self::VALUE], false, $m, false) >= 0) { $a = $class::subtractHelper($a[self::VALUE], false, $m, false); } return $a[self::VALUE]; } }<?php /** * PHP Montgomery Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP\Reductions; use phpseclib\Math\BigInteger\Engines\PHP\Montgomery as Progenitor; /** * PHP Montgomery Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Montgomery extends Progenitor { /** * Prepare a number for use in Montgomery Modular Reductions * * @param array $x * @param array $n * @param string $class * @return array */ protected static function prepareReduce(array $x, array $n, $class) { $lhs = new $class(); $lhs->value = array_merge(self::array_repeat(0, count($n)), $x); $rhs = new $class(); $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } /** * Montgomery Multiply * * Interleaves the montgomery reduction and long multiplication algorithms together as described in * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} * * @param array $x * @param array $n * @param string $class * @return array */ protected static function reduce(array $x, array $n, $class) { static $cache = [ self::VARIABLE => [], self::DATA => [] ]; if (($key = array_search($n, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); $cache[self::VARIABLE][] = $x; $cache[self::DATA][] = self::modInverse67108864($n, $class); } $k = count($n); $result = [self::VALUE => $x]; for ($i = 0; $i < $k; ++$i) { $temp = $result[self::VALUE][$i] * $cache[self::DATA][$key]; $temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31)); $temp = $class::regularMultiply([$temp], $n); $temp = array_merge(self::array_repeat(0, $i), $temp); $result = $class::addHelper($result[self::VALUE], false, $temp, false); } $result[self::VALUE] = array_slice($result[self::VALUE], $k); if (self::compareHelper($result, false, $n, false) >= 0) { $result = $class::subtractHelper($result[self::VALUE], false, $n, false); } return $result[self::VALUE]; } /** * Modular Inverse of a number mod 2**26 (eg. 67108864) * * Based off of the bnpInvDigit function implemented and justified in the following URL: * * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js} * * The following URL provides more info: * * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85} * * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to * 40 bits, which only 64-bit floating points will support. * * Thanks to Pedro Gimeno Fortea for input! * * @param array $x * @param string $class * @return int */ protected static function modInverse67108864(array $x, $class) // 2**26 == 67,108,864 { $x = -$x[0]; $result = $x & 0x3; // x**-1 mod 2**2 $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8 $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 $result = $class::BASE == 26 ? fmod($result * (2 - fmod($x * $result, $class::BASE_FULL)), $class::BASE_FULL) : // x**-1 mod 2**26 ($result * (2 - ($x * $result) % $class::BASE_FULL)) % $class::BASE_FULL; return $result & $class::MAX_DIGIT; } }<?php /** * PHP Dynamic Barrett Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP\Reductions; use phpseclib\Math\BigInteger\Engines\PHP\Base; use phpseclib\Math\BigInteger\Engines\PHP; /** * PHP Dynamic Barrett Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class EvalBarrett extends Base { /** * Custom Reduction Function * * @see self::generateCustomReduction */ private static $custom_reduction; /** * Barrett Modular Reduction * * This calls a dynamically generated loop unrolled function that's specific to a given modulo. * Array lookups are avoided as are if statements testing for how many bits the host OS supports, etc. * * @param array $n * @param array $m * @param string $class * @return array */ protected static function reduce(array $n, array $m, $class) { $inline = self::$custom_reduction; return $inline($n); } /** * Generate Custom Reduction * * @param PHP $m * @param string $class * @return callable */ protected static function generateCustomReduction(PHP $m, $class) { if (isset($n->reduce)) { self::$custom_reduction = $n->reduce; return $n->reduce; } $m_length = count($m->value); if ($m_length < 5) { $code = ' $lhs = new ' . $class . '(); $lhs->value = $x; $rhs = new ' . $class . '(); $rhs->value = [' . implode(',', array_map('self::float2string', $m->value)) . ']; list(, $temp) = $lhs->divide($rhs); return $temp->value; '; eval('$func = function ($x) { ' . $code . '};'); self::$custom_reduction = $func; //self::$custom_reduction = \Closure::bind($func, $m, $class); return $func; } $lhs = new $class(); $lhs_value = &$lhs->value; $lhs_value = self::array_repeat(0, $m_length + ($m_length >> 1)); $lhs_value[] = 1; $rhs = new $class(); list($u, $m1) = $lhs->divide($m); if ($class::BASE != 26) { $u = $u->value; } else { $lhs_value = self::array_repeat(0, 2 * $m_length); $lhs_value[] = 1; $rhs = new $class(); list($u) = $lhs->divide($m); $u = $u->value; } $m = $m->value; $m1 = $m1->value; $cutoff = count($m) + (count($m) >> 1); $code = ' if (count($n) > ' . (2 * count($m)) . ') { $lhs = new ' . $class . '(); $rhs = new ' . $class . '(); $lhs->value = $n; $rhs->value = [' . implode(',', array_map('self::float2string', $m)) . ']; list(, $temp) = $lhs->divide($rhs); return $temp->value; } $lsd = array_slice($n, 0, ' . $cutoff . '); $msd = array_slice($n, ' . $cutoff . ');'; $code.= self::generateInlineTrim('msd'); $code.= self::generateInlineMultiply('msd', $m1, 'temp', $class); $code.= self::generateInlineAdd('lsd', 'temp', 'n', $class); $code.= '$temp = array_slice($n, ' . (count($m) - 1) . ');'; $code.= self::generateInlineMultiply('temp', $u, 'temp2', $class); $code.= self::generateInlineTrim('temp2'); $code.= $class::BASE == 26 ? '$temp = array_slice($temp2, ' . (count($m) + 1) . ');' : '$temp = array_slice($temp2, ' . ((count($m) >> 1) + 1) . ');'; $code.= self::generateInlineMultiply('temp', $m, 'temp2', $class); $code.= self::generateInlineTrim('temp2'); /* if ($class::BASE == 26) { $code.= '$n = array_slice($n, 0, ' . (count($m) + 1) . '); $temp2 = array_slice($temp2, 0, ' . (count($m) + 1) . ');'; } */ $code.= self::generateInlineSubtract2('n', 'temp2', 'temp', $class); $subcode = self::generateInlineSubtract1('temp', $m, 'temp2', $class); $subcode.= '$temp = $temp2;'; $code.= self::generateInlineCompare($m, 'temp', $subcode); $code.= 'return $temp;'; eval('$func = function ($n) { ' . $code . '};'); self::$custom_reduction = $func; return $func; //self::$custom_reduction = \Closure::bind($func, $m, $class); } /** * Inline Trim * * Removes leading zeros * * @param string $name * @return string */ private static function generateInlineTrim($name) { return ' for ($i = count($' . $name . ') - 1; $i >= 0; --$i) { if ($' . $name . '[$i]) { break; } unset($' . $name . '[$i]); }'; } /** * Inline Multiply (unknown, known) * * @param string $input * @param array $arr * @param string $output * @param string $class * @return string */ private static function generateInlineMultiply($input, array $arr, $output, $class) { if (!count($arr)) { return 'return [];'; } $regular = ' $length = count($' . $input . '); if (!$length) { $' . $output . ' = []; }else{ $' . $output . ' = array_fill(0, $length + ' . count($arr) . ', 0); $carry = 0;'; for ($i = 0; $i < count($arr); $i++) { $regular.= ' $subtemp = $' . $input . '[0] * ' . $arr[$i]; $regular.= $i ? ' + $carry;' : ';'; $regular.= '$carry = '; $regular.= $class::BASE === 26 ? 'intval($subtemp / 0x4000000);' : '$subtemp >> 31;'; $regular.= '$' . $output . '[' . $i . '] = '; if ($class::BASE === 26) { $regular.= '(int) ('; } $regular.= '$subtemp - ' . $class::BASE_FULL . ' * $carry'; $regular.= $class::BASE === 26 ? ');' : ';'; } $regular.= '$' . $output . '[' . count($arr) . '] = $carry;'; $regular.= ' for ($i = 1; $i < $length; ++$i) {'; for ($j = 0; $j < count($arr); $j++) { $regular.= $j ? '$k++;' : '$k = $i;'; $regular.= ' $subtemp = $' . $output . '[$k] + $' . $input . '[$i] * ' . $arr[$j]; $regular.= $j ? ' + $carry;' : ';'; $regular.= '$carry = '; $regular.= $class::BASE === 26 ? 'intval($subtemp / 0x4000000);' : '$subtemp >> 31;'; $regular.= '$' . $output . '[$k] = '; if ($class::BASE === 26) { $regular.= '(int) ('; } $regular.= '$subtemp - ' . $class::BASE_FULL . ' * $carry'; $regular.= $class::BASE === 26 ? ');' : ';'; } $regular.= '$' . $output. '[++$k] = $carry; $carry = 0;'; $regular.= '}}'; //if (count($arr) < 2 * self::KARATSUBA_CUTOFF) { //} return $regular; } /** * Inline Addition * * @param string $x * @param string $y * @param string $result * @param string $class * @return string */ private static function generateInlineAdd($x, $y, $result, $class) { $code = ' $length = max(count($' . $x . '), count($' . $y . ')); $' . $result . ' = array_pad($' . $x . ', $length + 1, 0); $_' . $y . ' = array_pad($' . $y . ', $length, 0); $carry = 0; for ($i = 0, $j = 1; $j < $length; $i+=2, $j+=2) { $sum = ($' . $result . '[$j] + $_' . $y . '[$j]) * ' . $class::BASE_FULL . ' + $' . $result . '[$i] + $_' . $y . '[$i] + $carry; $carry = $sum >= ' . self::float2string($class::MAX_DIGIT2) . '; $sum = $carry ? $sum - ' . self::float2string($class::MAX_DIGIT2) . ' : $sum;'; $code.= $class::BASE === 26 ? '$upper = intval($sum / 0x4000000); $' . $result . '[$i] = (int) ($sum - ' . $class::BASE_FULL . ' * $upper);' : '$upper = $sum >> 31; $' . $result . '[$i] = $sum - ' . $class::BASE_FULL . ' * $upper;'; $code.= ' $' . $result . '[$j] = $upper; } if ($j == $length) { $sum = $' . $result . '[$i] + $_' . $y . '[$i] + $carry; $carry = $sum >= ' . self::float2string($class::BASE_FULL) . '; $' . $result . '[$i] = $carry ? $sum - ' . self::float2string($class::BASE_FULL) . ' : $sum; } if ($carry) { for (; $' . $result . '[$i] == ' . $class::MAX_DIGIT . '; ++$i) { $' . $result . '[$i] = 0; } ++$' . $result . '[$i]; }'; $code.= self::generateInlineTrim($result); return $code; } /** * Inline Subtraction 2 * * For when $known is more digits than $unknown. This is the harder use case to optimize for. * * @param string $known * @param string $unknown * @param string $result * @param string $class * @return string */ private static function generateInlineSubtract2($known, $unknown, $result, $class) { $code = ' $' . $result .' = $' . $known . '; $carry = 0; $size = count($' . $unknown . '); for ($i = 0, $j = 1; $j < $size; $i+= 2, $j+= 2) { $sum = ($' . $known . '[$j] - $' . $unknown . '[$j]) * ' . $class::BASE_FULL . ' + $' . $known . '[$i] - $' . $unknown . '[$i] - $carry; $carry = $sum < 0; if ($carry) { $sum+= ' . self::float2string($class::MAX_DIGIT2) . '; } $subtemp = '; $code.= $class::BASE === 26 ? 'intval($sum / 0x4000000);' : '$sum >> 31;'; $code.= '$' . $result . '[$i] = '; if ($class::BASE === 26) { $code.= '(int) ('; } $code.= '$sum - ' . $class::BASE_FULL . ' * $subtemp'; if ($class::BASE === 26) { $code.= ')'; } $code.= '; $' . $result . '[$j] = $subtemp; } if ($j == $size) { $sum = $' . $known . '[$i] - $' . $unknown . '[$i] - $carry; $carry = $sum < 0; $' . $result . '[$i] = $carry ? $sum + ' . $class::BASE_FULL . ' : $sum; ++$i; } if ($carry) { for (; !$' . $result . '[$i]; ++$i) { $' . $result . '[$i] = ' . $class::MAX_DIGIT . '; } --$' . $result . '[$i]; }'; $code.= self::generateInlineTrim($result); return $code; } /** * Inline Subtraction 1 * * For when $unknown is more digits than $known. This is the easier use case to optimize for. * * @param string $unknown * @param array $known * @param string $result * @param string $class * @return string */ private static function generateInlineSubtract1($unknown, array $known, $result, $class) { $code = '$' . $result . ' = $' . $unknown . ';'; for ($i = 0, $j = 1; $j < count($known); $i+=2, $j+=2) { $code.= '$sum = $' . $unknown . '[' . $j . '] * ' . $class::BASE_FULL . ' + $' . $unknown . '[' . $i . '] - '; $code.= self::float2string($known[$j] * $class::BASE_FULL + $known[$i]); if ($i != 0) { $code.= ' - $carry'; } $code.= '; if ($carry = $sum < 0) { $sum+= ' . self::float2string($class::MAX_DIGIT2) . '; } $subtemp = '; $code.= $class::BASE === 26 ? 'intval($sum / 0x4000000);' : '$sum >> 31;'; $code.= ' $' . $result . '[' . $i . '] = '; if ($class::BASE === 26) { $code.= ' (int) ('; } $code.= '$sum - ' . $class::BASE_FULL . ' * $subtemp'; if ($class::BASE === 26) { $code.= ')'; } $code.= '; $' . $result . '[' . $j . '] = $subtemp;'; } $code.= '$i = ' . $i . ';'; if ($j == count($known)) { $code.= ' $sum = $' . $unknown . '[' . $i . '] - ' . $known[$i] . ' - $carry; $carry = $sum < 0; $' . $result . '[' . $i . '] = $carry ? $sum + ' . $class::BASE_FULL . ' : $sum; ++$i;'; } $code.= ' if ($carry) { for (; !$' . $result . '[$i]; ++$i) { $' . $result . '[$i] = ' . $class::MAX_DIGIT . '; } --$' . $result . '[$i]; }'; $code.= self::generateInlineTrim($result); return $code; } /** * Inline Comparison * * If $unknown >= $known then loop * * @param array $known * @param string $unknown * @param string $subcode * @return string */ private static function generateInlineCompare(array $known, $unknown, $subcode) { $uniqid = uniqid(); $code = 'loop_' . $uniqid . ': $clength = count($' . $unknown . '); switch (true) { case $clength < ' . count($known) . ': goto end_' . $uniqid . '; case $clength > ' . count($known) . ':'; for ($i = count($known) - 1; $i >= 0; $i--) { $code.= ' case $' . $unknown . '[' . $i . '] > ' . $known[$i] . ': goto subcode_' . $uniqid . '; case $' . $unknown . '[' . $i . '] < ' . $known[$i] . ': goto end_' . $uniqid . ';'; } $code.= ' default: // do subcode } subcode_' . $uniqid . ':' . $subcode . ' goto loop_' . $uniqid . '; end_' . $uniqid . ':'; return $code; } /** * Convert a float to a string * * If you do echo floatval(pow(2, 52)) you'll get 4.6116860184274E+18. It /can/ be displayed without a loss of * precision but displayed in this way there will be precision loss, hence the need for this method. * * @param int|float $num * @return string */ private static function float2string($num) { if (!is_float($num)) { return $num; } if ($num < 0) { return '-' . self::float2string(abs($num)); } $temp = ''; while ($num) { $temp = fmod($num, 10) . $temp; $num = floor($num / 10); } return $temp; } }<?php /** * PHP Power of Two Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP\Reductions; use phpseclib\Math\BigInteger\Engines\PHP\Base; /** * PHP Power Of Two Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PowerOfTwo extends Base { /** * Prepare a number for use in Montgomery Modular Reductions * * @param array $x * @param array $n * @param string $class * @return array */ protected static function prepareReduce(array $x, array $n, $class) { return self::reduce($x, $n, $class); } /** * Power Of Two Reduction * * @param array $x * @param array $n * @param string $class * @return array */ protected static function reduce(array $x, array $n, $class) { $lhs = new $class(); $lhs->value = $x; $rhs = new $class(); $rhs->value = $n; $temp = new $class(); $temp->value = [1]; $result = $lhs->bitwise_and($rhs->subtract($temp)); return $result->value; } }<?php /** * OpenSSL Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP; use phpseclib\Math\BigInteger\Engines\OpenSSL as Progenitor; /** * OpenSSL Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSL extends Progenitor { }<?php /** * PHP Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP; use phpseclib\Math\BigInteger\Engines\PHP; /** * PHP Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Base extends PHP { /**#@+ * @access private */ /** * Cache constants * * $cache[self::VARIABLE] tells us whether or not the cached data is still valid. */ const VARIABLE = 0; /** * $cache[self::DATA] contains the cached data. */ const DATA = 1; /**#@-*/ /** * Test for engine validity * * @return bool */ public static function isValidEngine() { return static::class != __CLASS__; } /** * Performs modular exponentiation. * * The most naive approach to modular exponentiation has very unreasonable requirements, and * and although the approach involving repeated squaring does vastly better, it, too, is impractical * for our purposes. The reason being that division - by far the most complicated and time-consuming * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. * * Modular reductions resolve this issue. Although an individual modular reduction takes more time * then an individual division, when performed in succession (with the same modulo), they're a lot faster. * * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because * the product of two odd numbers is odd), but what about when RSA isn't used? * * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. * * @param \phpseclib\Math\BigInteger\Engines\PHP $x * @param \phpseclib\Math\BigInteger\Engines\PHP $e * @param \phpseclib\Math\BigInteger\Engines\PHP $n * @param string $class * @return \phpseclib\Math\BigInteger\Engines\PHP */ protected static function powModHelper(PHP $x, PHP $e, PHP $n, $class) { if (empty($e->value)) { $temp = new $class(); $temp->value = [1]; return $x->normalize($temp); } if ($e->value == [1]) { list(, $temp) = $x->divide($n); return $x->normalize($temp); } if ($e->value == [2]) { $temp = new $class; $temp->value = $class::square($x->value); list(, $temp) = $temp->divide($n); return $x->normalize($temp); } return $x->normalize(static::slidingWindow($x, $e, $n, $class)); } /** * Modular reduction preparation * * @param array $x * @param array $n * @param string $class * @see self::slidingWindow() * @return array */ protected static function prepareReduce(array $x, array $n, $class) { return static::reduce($x, $n, $class); } /** * Modular multiply * * @param array $x * @param array $y * @param array $n * @param string $class * @see self::slidingWindow() * @return array */ protected static function multiplyReduce(array $x, array $y, array $n, $class) { $temp = $class::multiplyHelper($x, false, $y, false); return static::reduce($temp[self::VALUE], $n, $class); } /** * Modular square * * @param array $x * @param array $n * @param string $class * @see self::slidingWindow() * @return array */ protected static function squareReduce(array $x, array $n, $class) { return static::reduce($class::square($x), $n, $class); } }<?php /** * PHP Default Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP; use phpseclib\Math\BigInteger\Engines\PHP\Reductions\EvalBarrett; /** * PHP Default Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DefaultEngine extends EvalBarrett { }<?php /** * PHP Montgomery Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\PHP; use phpseclib\Math\BigInteger\Engines\PHP\Reductions\PowerOfTwo; use phpseclib\Math\BigInteger\Engines\PHP; use phpseclib\Math\BigInteger\Engines\PHP\Base; use phpseclib\Math\BigInteger\Engines\Engine; /** * PHP Montgomery Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Montgomery extends Base { /** * Test for engine validity * * @return bool */ public static function isValidEngine() { return static::class != __CLASS__; } /** * Performs modular exponentiation. * * @param \phpseclib\Math\BigInteger\Engines\Engine $x * @param \phpseclib\Math\BigInteger\Engines\Engine $e * @param \phpseclib\Math\BigInteger\Engines\Engine $n * @param string $class * @return \phpseclib\Math\BigInteger\Engines\Engine */ protected static function slidingWindow(Engine $x, Engine $e, Engine $n, $class) { // is the modulo odd? if ($n->value[0] & 1) { return parent::slidingWindow($x, $e, $n, $class); } // if it's not, it's even // find the lowest set bit (eg. the max pow of 2 that divides $n) for ($i = 0; $i < count($n->value); ++$i) { if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j+= $class::BASE * $i; break; } } // at this point, 2^$j * $n/(2^$j) == $n $mod1 = clone $n; $mod1->rshift($j); $mod2 = new $class(); $mod2->value = [1]; $mod2->lshift($j); $part1 = $mod1->value != [1] ? parent::slidingWindow($x, $e, $mod1, $class) : new $class(); $part2 = PowerOfTwo::slidingWindow($x, $e, $mod2, $class); $y1 = $mod2->modInverse($mod1); $y2 = $mod1->modInverse($mod2); $result = $part1->multiply($mod2); $result = $result->multiply($y1); $temp = $part2->multiply($mod1); $temp = $temp->multiply($y2); $result = $result->add($temp); list(, $result) = $result->divide($n); return $result; } }<?php /** * OpenSSL Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use phpseclib\Crypt\RSA; use phpseclib\Crypt\RSA\Keys\PKCS8; use phpseclib\Math\BigInteger; /** * OpenSSL Modular Exponentiation Engine * * @package Engines * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSL { /** * Test for engine validity * * @return bool */ public static function isValidEngine() { return extension_loaded('openssl') && static::class != __CLASS__; } /** * Performs modular exponentiation. * * @param Engine $x * @param Engine $e * @param Engine $n * @return Engine */ public static function powModHelper(Engine $x, Engine $e, Engine $n) { if ($n->getLengthInBytes() < 31 || $n->getLengthInBytes() > 16384) { throw new \OutOfRangeException('Only modulo between 31 and 16384 bits are accepted'); } $key = PKCS8::savePublicKey( new BigInteger($n), new BigInteger($e) ); $rsa = RSA::load($key); //$rsa->setPublicKeyFormat('PKCS1'); $plaintext = str_pad($x->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT); // this is easily prone to failure. if the modulo is a multiple of 2 or 3 or whatever it // won't work and you'll get a "failure: error:0906D06C:PEM routines:PEM_read_bio:no start line" // error. i suppose, for even numbers, we could do what PHP\Montgomery.php does, but then what // about odd numbers divisible by 3, by 5, etc? if (!openssl_public_encrypt($plaintext, $result, "$rsa", OPENSSL_NO_PADDING)) { throw new \UnexpectedValueException(openssl_error_string()); } $class = get_class($x); return new $class($result, 256); } }<?php /** * Pure-PHP BigInteger Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use ParagonIE\ConstantTime\Hex; use phpseclib\Exception\BadConfigurationException; /** * Pure-PHP Engine. * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PHP extends Engine { /**#@+ * Array constants * * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them. * * @access protected */ /** * $result[self::VALUE] contains the value. */ const VALUE = 0; /** * $result[self::SIGN] contains the sign. */ const SIGN = 1; /**#@-*/ /** * Karatsuba Cutoff * * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication? * * @access private */ const KARATSUBA_CUTOFF = 25; /** * Can Bitwise operations be done fast? * * @see parent::bitwise_leftRotate() * @see parent::bitwise_rightRotate() * @access protected */ const FAST_BITWISE = true; /** * Engine Directory * * @see parent::setModExpEngine * @access protected */ const ENGINE_DIR = 'PHP'; /** * Default constructor * * @param mixed $x integer Base-10 number or base-$base number if $base set. * @param int $base * @see parent::__construct() * @return \phpseclib\Math\BigInteger\Engines\PHP */ public function __construct($x = 0, $base = 10) { if (!isset(static::$isValidEngine)) { static::$isValidEngine = static::isValidEngine(); } if (!static::$isValidEngine) { throw new BadConfigurationException(static::class . ' is not setup correctly on this system'); } $this->value = []; parent::__construct($x, $base); } /** * Initialize a PHP BigInteger Engine instance * * @param int $base * @see parent::__construct() */ protected function initialize($base) { switch (abs($base)) { case 16: $x = (strlen($this->value) & 1) ? '0' . $this->value : $this->value; $temp = new static(Hex::decode($x), 256); $this->value = $temp->value; break; case 10: $temp = new static(); $multiplier = new static(); $multiplier->value = [static::MAX10]; $x = $this->value; if ($x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = str_pad($x, strlen($x) + ((static::MAX10LEN - 1) * strlen($x)) % static::MAX10LEN, 0, STR_PAD_LEFT); while (strlen($x)) { $temp = $temp->multiply($multiplier); $temp = $temp->add(new static($this->int2bytes(substr($x, 0, static::MAX10LEN)), 256)); $x = substr($x, static::MAX10LEN); } $this->value = $temp->value; } } /** * Pads strings so that unpack may be used on them * * @param string $str * @return string */ protected function pad($str) { $length = strlen($str); $pad = 4 - (strlen($str) % 4); return str_pad($str, $length + $pad, "\0", STR_PAD_LEFT); } /** * Converts a BigInteger to a base-10 number. * * @return string */ public function toString() { if (!count($this->value)) { return '0'; } $temp = clone $this; $temp->is_negative = false; $divisor = new static(); $divisor->value = [static::MAX10]; $result = ''; while (count($temp->value)) { list($temp, $mod) = $temp->divide($divisor); $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', static::MAX10LEN, '0', STR_PAD_LEFT) . $result; } $result = ltrim($result, '0'); if (empty($result)) { $result = '0'; } if ($this->is_negative) { $result = '-' . $result; } return $result; } /** * Converts a BigInteger to a byte string (eg. base-256). * * @param bool $twos_compliment * @return string */ public function toBytes($twos_compliment = false) { if ($twos_compliment) { return $this->toBytesHelper(); } if (!count($this->value)) { return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; } $result = $this->bitwise_small_split(8); $result = implode('', array_map('chr', $result)); return $this->precision > 0 ? str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) : $result; } /** * Performs addition. * * @param array $x_value * @param bool $x_negative * @param array $y_value * @param bool $y_negative * @return array */ protected static function addHelper(array $x_value, $x_negative, array $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); if ($x_size == 0) { return [ self::VALUE => $y_value, self::SIGN => $y_negative ]; } elseif ($y_size == 0) { return [ self::VALUE => $x_value, self::SIGN => $x_negative ]; } // subtract, if appropriate if ($x_negative != $y_negative) { if ($x_value == $y_value) { return [ self::VALUE => [], self::SIGN => false ]; } $temp = self::subtractHelper($x_value, false, $y_value, false); $temp[self::SIGN] = self::compareHelper($x_value, false, $y_value, false) > 0 ? $x_negative : $y_negative; return $temp; } if ($x_size < $y_size) { $size = $x_size; $value = $y_value; } else { $size = $y_size; $value = $x_value; } $value[count($value)] = 0; // just in case the carry adds an extra digit $carry = 0; for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { //$sum = $x_value[$j] * static::BASE_FULL + $x_value[$i] + $y_value[$j] * static::BASE_FULL + $y_value[$i] + $carry; $sum = ($x_value[$j] + $y_value[$j]) * static::BASE_FULL + $x_value[$i] + $y_value[$i] + $carry; $carry = $sum >= static::MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $sum = $carry ? $sum - static::MAX_DIGIT2 : $sum; $temp = static::BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31); $value[$i] = (int) ($sum - static::BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) $value[$j] = $temp; } if ($j == $size) { // ie. if $y_size is odd $sum = $x_value[$i] + $y_value[$i] + $carry; $carry = $sum >= static::BASE_FULL; $value[$i] = $carry ? $sum - static::BASE_FULL : $sum; ++$i; // ie. let $i = $j since we've just done $value[$i] } if ($carry) { for (; $value[$i] == static::MAX_DIGIT; ++$i) { $value[$i] = 0; } ++$value[$i]; } return [ self::VALUE => self::trim($value), self::SIGN => $x_negative ]; } /** * Performs subtraction. * * @param array $x_value * @param bool $x_negative * @param array $y_value * @param bool $y_negative * @return array */ static function subtractHelper(array $x_value, $x_negative, array $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); if ($x_size == 0) { return [ self::VALUE => $y_value, self::SIGN => !$y_negative ]; } elseif ($y_size == 0) { return [ self::VALUE => $x_value, self::SIGN => $x_negative ]; } // add, if appropriate (ie. -$x - +$y or +$x - -$y) if ($x_negative != $y_negative) { $temp = self::addHelper($x_value, false, $y_value, false); $temp[self::SIGN] = $x_negative; return $temp; } $diff = self::compareHelper($x_value, $x_negative, $y_value, $y_negative); if (!$diff) { return [ self::VALUE => [], self::SIGN => false ]; } // switch $x and $y around, if appropriate. if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_negative = !$x_negative; $x_size = count($x_value); $y_size = count($y_value); } // at this point, $x_value should be at least as big as - if not bigger than - $y_value $carry = 0; for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { $sum = ($x_value[$j] - $y_value[$j]) * static::BASE_FULL + $x_value[$i] - $y_value[$i] - $carry; $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 $sum = $carry ? $sum + static::MAX_DIGIT2 : $sum; $temp = static::BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31); $x_value[$i] = (int) ($sum - static::BASE_FULL * $temp); $x_value[$j] = $temp; } if ($j == $y_size) { // ie. if $y_size is odd $sum = $x_value[$i] - $y_value[$i] - $carry; $carry = $sum < 0; $x_value[$i] = $carry ? $sum + static::BASE_FULL : $sum; ++$i; } if ($carry) { for (; !$x_value[$i]; ++$i) { $x_value[$i] = static::MAX_DIGIT; } --$x_value[$i]; } return [ self::VALUE => self::trim($x_value), self::SIGN => $x_negative ]; } /** * Performs multiplication. * * @param array $x_value * @param bool $x_negative * @param array $y_value * @param bool $y_negative * @return array */ protected static function multiplyHelper(array $x_value, $x_negative, array $y_value, $y_negative) { //if ( $x_value == $y_value ) { // return [ // self::VALUE => self::square($x_value), // self::SIGN => $x_sign != $y_value // ]; //} $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { // a 0 is being multiplied return [ self::VALUE => [], self::SIGN => false ]; } return [ self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ? self::trim(self::regularMultiply($x_value, $y_value)) : self::trim(self::karatsuba($x_value, $y_value)), self::SIGN => $x_negative != $y_negative ]; } /** * Performs Karatsuba multiplication on two BigIntegers * * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}. * * @param array $x_value * @param array $y_value * @return array */ private static function karatsuba(array $x_value, array $y_value) { $m = min(count($x_value) >> 1, count($y_value) >> 1); if ($m < self::KARATSUBA_CUTOFF) { return self::regularMultiply($x_value, $y_value); } $x1 = array_slice($x_value, $m); $x0 = array_slice($x_value, 0, $m); $y1 = array_slice($y_value, $m); $y0 = array_slice($y_value, 0, $m); $z2 = self::karatsuba($x1, $y1); $z0 = self::karatsuba($x0, $y0); $z1 = self::addHelper($x1, false, $x0, false); $temp = self::addHelper($y1, false, $y0, false); $z1 = self::karatsuba($z1[self::VALUE], $temp[self::VALUE]); $temp = self::addHelper($z2, false, $z0, false); $z1 = self::subtractHelper($z1, false, $temp[self::VALUE], false); $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]); $xy = self::addHelper($z2, false, $z1[self::VALUE], $z1[self::SIGN]); $xy = self::addHelper($xy[self::VALUE], $xy[self::SIGN], $z0, false); return $xy[self::VALUE]; } /** * Performs long multiplication on two BigIntegers * * Modeled after 'multiply' in MutableBigInteger.java. * * @param array $x_value * @param array $y_value * @return array */ protected static function regularMultiply(array $x_value, array $y_value) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { // a 0 is being multiplied return []; } $product_value = self::array_repeat(0, $x_length + $y_length); // the following for loop could be removed if the for loop following it // (the one with nested for loops) initially set $i to 0, but // doing so would also make the result in one set of unnecessary adds, // since on the outermost loops first pass, $product->value[$k] is going // to always be 0 $carry = 0; for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$j] = (int) ($temp - static::BASE_FULL * $carry); } $product_value[$j] = $carry; // the above for loop is what the previous comment was talking about. the // following for loop is the "one with nested for loops" for ($i = 1; $i < $y_length; ++$i) { $carry = 0; for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $product_value[$k] = (int) ($temp - static::BASE_FULL * $carry); } $product_value[$k] = $carry; } return $product_value; } /** * Divides two BigIntegers. * * Returns an array whose first element contains the quotient and whose second element contains the * "common residue". If the remainder would be positive, the "common residue" and the remainder are the * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder * and the divisor (basically, the "common residue" is the first positive modulo). * * @param \phpseclib\Math\BigInteger\engines\PHP $y * @return array * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}. */ protected function divideHelper(PHP $y) { if (count($y->value) == 1) { list($q, $r) = $this->divide_digit($this->value, $y->value[0]); $quotient = new static(); $remainder = new static(); $quotient->value = $q; $remainder->value = [$r]; $quotient->is_negative = $this->is_negative != $y->is_negative; return [$this->normalize($quotient), $this->normalize($remainder)]; } $x = clone $this; $y = clone $y; $x_sign = $x->is_negative; $y_sign = $y->is_negative; $x->is_negative = $y->is_negative = false; $diff = $x->compare($y); if (!$diff) { $temp = new static(); $temp->value = [1]; $temp->is_negative = $x_sign != $y_sign; return [$this->normalize($temp), $this->normalize(static::$zero)]; } if ($diff < 0) { // if $x is negative, "add" $y. if ($x_sign) { $x = $y->subtract($x); } return [$this->normalize(static::$zero), $this->normalize($x)]; } // normalize $x and $y as described in HAC 14.23 / 14.24 $msb = $y->value[count($y->value) - 1]; for ($shift = 0; !($msb & static::MSB); ++$shift) { $msb <<= 1; } $x->lshift($shift); $y->lshift($shift); $y_value = &$y->value; $x_max = count($x->value) - 1; $y_max = count($y->value) - 1; $quotient = new static(); $quotient_value = &$quotient->value; $quotient_value = self::array_repeat(0, $x_max - $y_max + 1); static $temp, $lhs, $rhs; if (!isset($temp)) { $temp = new static(); $lhs = new static(); $rhs = new static(); } $temp_value = &$temp->value; $rhs_value = &$rhs->value; // $temp = $y << ($x_max - $y_max-1) in base 2**26 $temp_value = array_merge(self::array_repeat(0, $x_max - $y_max), $y_value); while ($x->compare($temp) >= 0) { // calculate the "common residue" ++$quotient_value[$x_max - $y_max]; $x = $x->subtract($temp); $x_max = count($x->value) - 1; } for ($i = $x_max; $i >= $y_max + 1; --$i) { $x_value = &$x->value; $x_window = [ isset($x_value[$i]) ? $x_value[$i] : 0, isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 ]; $y_window = [ $y_value[$y_max], ($y_max > 0) ? $y_value[$y_max - 1] : 0 ]; $q_index = $i - $y_max - 1; if ($x_window[0] == $y_window[0]) { $quotient_value[$q_index] = static::MAX_DIGIT; } else { $quotient_value[$q_index] = self::safe_divide( $x_window[0] * static::BASE_FULL + $x_window[1], $y_window[0] ); } $temp_value = [$y_window[1], $y_window[0]]; $lhs->value = [$quotient_value[$q_index]]; $lhs = $lhs->multiply($temp); $rhs_value = [$x_window[2], $x_window[1], $x_window[0]]; while ($lhs->compare($rhs) > 0) { --$quotient_value[$q_index]; $lhs->value = [$quotient_value[$q_index]]; $lhs = $lhs->multiply($temp); } $adjust = self::array_repeat(0, $q_index); $temp_value = [$quotient_value[$q_index]]; $temp = $temp->multiply($y); $temp_value = &$temp->value; $temp_value = array_merge($adjust, $temp_value); $x = $x->subtract($temp); if ($x->compare(static::$zero) < 0) { $temp_value = array_merge($adjust, $y_value); $x = $x->add($temp); --$quotient_value[$q_index]; } $x_max = count($x_value) - 1; } // unnormalize the remainder $x->rshift($shift); $quotient->is_negative = $x_sign != $y_sign; // calculate the "common residue", if appropriate if ($x_sign) { $y->rshift($shift); $x = $y->subtract($x); } return [$this->normalize($quotient), $this->normalize($x)]; } /** * Divides a BigInteger by a regular integer * * abc / x = a00 / x + b0 / x + c / x * * @param array $dividend * @param int $divisor * @return array */ private static function divide_digit(array $dividend, $divisor) { $carry = 0; $result = []; for ($i = count($dividend) - 1; $i >= 0; --$i) { $temp = static::BASE_FULL * $carry + $dividend[$i]; $result[$i] = self::safe_divide($temp, $divisor); $carry = (int) ($temp - $divisor * $result[$i]); } return [$result, $carry]; } /** * Single digit division * * Even if int64 is being used the division operator will return a float64 value * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't * have the precision of int64 this is a problem so, when int64 is being used, * we'll guarantee that the dividend is divisible by first subtracting the remainder. * * @param int $x * @param int $y * @return int */ private static function safe_divide($x, $y) { if (static::BASE === 26) { return (int) ($x / $y); } // static::BASE === 31 return ($x - ($x % $y)) / $y; } /* * Convert an array / boolean to a PHP BigInteger object * * @param array $arr * @return \phpseclib\Math\BigInteger\Engines\PHP */ protected function convertToObj(array $arr) { $result = new static(); $result->value = $arr[self::VALUE]; $result->is_negative = $arr[self::SIGN]; return $this->normalize($result); } /** * Normalize * * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision * * @param PHP $result * @return PHP */ protected function normalize(PHP $result) { unset($result->reduce); $result->precision = $this->precision; $result->bitmask = $this->bitmask; $value = &$result->value; if (!count($value)) { return $result; } $value = static::trim($value); if (!empty($result->bitmask->value)) { $length = min(count($value), count($result->bitmask->value)); $value = array_slice($value, 0, $length); for ($i = 0; $i < $length; ++$i) { $value[$i] = $value[$i] & $result->bitmask->value[$i]; } } return $result; } /* * Compares two numbers. * * @param array $x_value * @param bool $x_negative * @param array $y_value * @param bool $y_negative * @return int * @see static::compare() */ protected static function compareHelper(array $x_value, $x_negative, array $y_value, $y_negative) { if ($x_negative != $y_negative) { return (!$x_negative && $y_negative) ? 1 : -1; } $result = $x_negative ? -1 : 1; if (count($x_value) != count($y_value)) { return (count($x_value) > count($y_value)) ? $result : -$result; } $size = max(count($x_value), count($y_value)); $x_value = array_pad($x_value, $size, 0); $y_value = array_pad($y_value, $size, 0); for ($i = count($x_value) - 1; $i >= 0; --$i) { if ($x_value[$i] != $y_value[$i]) { return ($x_value[$i] > $y_value[$i]) ? $result : -$result; } } return 0; } /** * Absolute value. * * @return \phpseclib\Math\BigInteger\Engines\PHP */ public function abs() { $temp = new static(); $temp->value = $this->value; return $temp; } /** * Trim * * Removes leading zeros * * @param array $value * @return PHP */ protected static function trim(array $value) { for ($i = count($value) - 1; $i >= 0; --$i) { if ($value[$i]) { break; } unset($value[$i]); } return $value; } /** * Logical Right Shift * * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\PHP */ public function bitwise_rightShift($shift) { $temp = new static(); // could just replace lshift with this, but then all lshift() calls would need to be rewritten // and I don't want to do that... $temp->value = $this->value; $temp->rshift($shift); return $this->normalize($temp); } /** * Logical Left Shift * * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\PHP */ public function bitwise_leftShift($shift) { $temp = new static(); // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten // and I don't want to do that... $temp->value = $this->value; $temp->lshift($shift); return $this->normalize($temp); } /** * Converts 32-bit integers to bytes. * * @param int $x * @return string */ private static function int2bytes($x) { return ltrim(pack('N', $x), chr(0)); } /** * Array Repeat * * @param int $input * @param int $multiplier * @return array */ protected static function array_repeat($input, $multiplier) { return $multiplier ? array_fill(0, $multiplier, $input) : []; } /** * Logical Left Shift * * Shifts BigInteger's by $shift bits. * * @param int $shift */ protected function lshift($shift) { if ($shift == 0) { return; } $num_digits = (int) ($shift / static::BASE); $shift %= static::BASE; $shift = 1 << $shift; $carry = 0; for ($i = 0; $i < count($this->value); ++$i) { $temp = $this->value[$i] * $shift + $carry; $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $this->value[$i] = (int) ($temp - $carry * static::BASE_FULL); } if ($carry) { $this->value[count($this->value)] = $carry; } while ($num_digits--) { array_unshift($this->value, 0); } } /** * Logical Right Shift * * Shifts BigInteger's by $shift bits. * * @param int $shift */ protected function rshift($shift) { if ($shift == 0) { return; } $num_digits = (int) ($shift / static::BASE); $shift %= static::BASE; $carry_shift = static::BASE - $shift; $carry_mask = (1 << $shift) - 1; if ($num_digits) { $this->value = array_slice($this->value, $num_digits); } $carry = 0; for ($i = count($this->value) - 1; $i >= 0; --$i) { $temp = $this->value[$i] >> $shift | $carry; $carry = ($this->value[$i] & $carry_mask) << $carry_shift; $this->value[$i] = $temp; } $this->value = static::trim($this->value); } /** * Performs modular exponentiation. * * @param PHP $e * @param PHP $n * @return PHP */ protected function powModInner(PHP $e, PHP $n) { try { $class = static::$modexpEngine; return $class::powModHelper($this, $e, $n, static::class); } catch (\Exception $err) { return PHP\DefaultEngine::powModHelper($this, $e, $n, static::class); } } /** * Performs squaring * * @param array $x * @return array */ protected static function square(array $x) { return count($x) < 2 * self::KARATSUBA_CUTOFF ? self::trim(self::baseSquare($x)) : self::trim(self::karatsubaSquare($x)); } /** * Performs traditional squaring on two BigIntegers * * Squaring can be done faster than multiplying a number by itself can be. See * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} / * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information. * * @param array $value * @return array */ protected static function baseSquare(array $value) { if (empty($value)) { return []; } $square_value = self::array_repeat(0, 2 * count($value)); for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { $i2 = $i << 1; $temp = $square_value[$i2] + $value[$i] * $value[$i]; $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $square_value[$i2] = (int) ($temp - static::BASE_FULL * $carry); // note how we start from $i+1 instead of 0 as we do in multiplication. for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31); $square_value[$k] = (int) ($temp - static::BASE_FULL * $carry); } // the following line can yield values larger 2**15. at this point, PHP should switch // over to floats. $square_value[$i + $max_index + 1] = $carry; } return $square_value; } /** * Performs Karatsuba "squaring" on two BigIntegers * * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}. * * @param array $value * @return array */ protected static function karatsubaSquare(array $value) { $m = count($value) >> 1; if ($m < self::KARATSUBA_CUTOFF) { return self::baseSquare($value); } $x1 = array_slice($value, $m); $x0 = array_slice($value, 0, $m); $z2 = self::karatsubaSquare($x1); $z0 = self::karatsubaSquare($x0); $z1 = self::addHelper($x1, false, $x0, false); $z1 = self::karatsubaSquare($z1[self::VALUE]); $temp = self::addHelper($z2, false, $z0, false); $z1 = self::subtractHelper($z1, false, $temp[self::VALUE], false); $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]); $xx = self::addHelper($z2, false, $z1[self::VALUE], $z1[self::SIGN]); $xx = self::addHelper($xx[self::VALUE], $xx[self::SIGN], $z0, false); return $xx[self::VALUE]; } /** * Make the current number odd * * If the current number is odd it'll be unchanged. If it's even, one will be added to it. * * @see self::randomPrime() */ protected function make_odd() { $this->value[0] |= 1; } /** * Test the number against small primes. * * @see self::isPrime() */ protected function testSmallPrimes() { if ($this->value == [1]) { return false; } if ($this->value == [2]) { return true; } if (~$this->value[0] & 1) { return false; } $value = $this->value; foreach (static::$primes as $prime) { list(, $r) = self::divide_digit($value, $prime); if (!$r) { return count($value) == 1 && $value[0] == $prime; } } return true; } /** * Scan for 1 and right shift by that amount * * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); * * @see self::isPrime() * @param PHP $r * @return int */ public static function scan1divide(PHP $r) { $r_value = &$r->value; for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { $temp = ~$r_value[$i] & static::MAX_DIGIT; for ($j = 1; ($temp >> $j) & 1; ++$j) { } if ($j <= static::BASE) { break; } } $s = static::BASE * $i + $j; $r->rshift($s); return $s; } /** * Performs exponentiation. * * @param PHP $n * @return PHP */ protected function powHelper(PHP $n) { if ($n->compare(static::$zero) == 0) { return new static(1); } // n^0 = 1 $temp = clone $this; while (!$n->equals(static::$one)) { $temp = $temp->multiply($this); $n = $n->subtract(static::$one); } return $temp; } /** * Is Odd? * * @return boolean */ public function isOdd() { return (bool) ($this->value[0] & 1); } /** * Tests if a bit is set * * @return boolean */ public function testBit($x) { $digit = floor($x / static::BASE); $bit = $x % static::BASE; if (!isset($this->value[$digit])) { return false; } return (bool) ($this->value[$digit] & (1 << $bit)); } /** * Is Negative? * * @return boolean */ public function isNegative() { return $this->is_negative; } /** * Negate * * Given $k, returns -$k * * @return BigInteger */ public function negate() { $temp = clone $this; $temp->is_negative = !$temp->is_negative; return $temp; } /** * Bitwise Split * * Splits BigInteger's into chunks of $split bits * * @param int $split * @return \phpseclib\Math\BigInteger\Engines\PHP[] */ public function bitwise_split($split) { if ($split < 1) { throw new \RuntimeException('Offset must be greater than 1'); } $width = (int) ($split / static::BASE); if (!$width) { $arr = $this->bitwise_small_split($split); return array_map(function ($digit) { $temp = new static(); $temp->value = $digit != 0 ? [$digit] : []; return $temp; }, $arr); } $vals = []; $val = $this->value; $i = $overflow = 0; $len = count($val); while ($i < $len) { $digit = []; if (!$overflow) { $digit = array_slice($val, $i, $width); $i+= $width; $overflow = $split % static::BASE; if ($overflow) { $mask = (1 << $overflow) - 1; $temp = isset($val[$i]) ? $val[$i] : 0; $digit[] = $temp & $mask; } } else { $remaining = static::BASE - $overflow; $tempsplit = $split - $remaining; $tempwidth = (int) ($tempsplit / static::BASE + 1); $digit = array_slice($val, $i, $tempwidth); $i+= $tempwidth; $tempoverflow = $tempsplit % static::BASE; if ($tempoverflow) { $tempmask = (1 << $tempoverflow) - 1; $temp = isset($val[$i]) ? $val[$i] : 0; $digit[] = $temp & $tempmask; } $newbits = 0; for ($j = count($digit) - 1; $j >= 0; $j--) { $temp = $digit[$j] & $mask; $digit[$j] = ($digit[$j] >> $overflow) | ($newbits << $remaining); $newbits = $temp; } $overflow = $tempoverflow; $mask = $tempmask; } $temp = new static(); $temp->value = static::trim($digit); $vals[] = $temp; } return array_reverse($vals); } /** * Bitwise Split where $split < static::BASE * * @param int $split * @return \phpseclib\Math\BigInteger\Engines\PHP[] */ private function bitwise_small_split($split) { $vals = []; $val = $this->value; $mask = (1 << $split) - 1; $i = $overflow = 0; $len = count($val); $val[] = 0; $remaining = static::BASE; while ($i != $len) { $digit = $val[$i] & $mask; $val[$i]>>= $split; if (!$overflow) { $remaining-= $split; $overflow = $split <= $remaining ? 0 : $split - $remaining; if (!$remaining) { $i++; $remaining = static::BASE; $overflow = 0; } } else if (++$i != $len) { $tempmask = (1 << $overflow) - 1; $digit|= ($val[$i] & $tempmask) << $remaining; $val[$i]>>= $overflow; $remaining = static::BASE - $overflow; $overflow = $split <= $remaining ? 0 : $split - $remaining; } $vals[] = $digit; } while ($vals[count($vals) - 1] == 0) { unset($vals[count($vals) - 1]); } return array_reverse($vals); } }<?php /** * BCMath Barrett Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\BCMath\Reductions; use phpseclib\Math\BigInteger\Engines\BCMath\Base; /** * PHP Barrett Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Barrett extends Base { /**#@+ * @access private */ /** * Cache constants * * $cache[self::VARIABLE] tells us whether or not the cached data is still valid. */ const VARIABLE = 0; /** * $cache[self::DATA] contains the cached data. */ const DATA = 1; /**#@-*/ /** * Barrett Modular Reduction * * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} / * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly, * so as not to require negative numbers (initially, this script didn't support negative numbers). * * Employs "folding", as described at * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." * * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that * usable on account of (1) its not using reasonable radix points as discussed in * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line * comments for details. * * @param string $n * @param string $m * @return array|string */ protected static function reduce($n, $m) { static $cache = [ self::VARIABLE => [], self::DATA => [] ]; $m_length = strlen($m); if (strlen($n) > 2 * $m_length) { return bcmod($n, $m); } // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced if ($m_length < 5) { return self::regularBarrett($n, $m); } // n = 2 * m.length if (($key = array_search($m, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); $cache[self::VARIABLE][] = $m; $lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1)); $u = bcdiv($lhs, $m, 0); $m1 = bcsub($lhs, bcmul($u, $m)); $cache[self::DATA][] = [ 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) 'm1'=> $m1 // m.length ]; } else { extract($cache[self::DATA][$key]); } $cutoff = $m_length + ($m_length >> 1); $lsd = substr($n, -$cutoff); $msd = substr($n, 0, -$cutoff); $temp = bcmul($msd, $m1); // m.length + (m.length >> 1) $n = bcadd($lsd, $temp); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers) //if ($m_length & 1) { // return self::regularBarrett($n, $m); //} // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 $temp = substr($n, 0, -$m_length + 1); // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 $temp = bcmul($temp, $u); // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) $temp = substr($temp, 0, -($m_length >> 1) - 1); // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) $temp = bcmul($temp, $m); // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). $result = bcsub($n, $temp); //if (bccomp($result, '0') < 0) { if ($result[0] == '-') { $temp = '1' . str_repeat('0', $m_length + 1); $result = bcadd($result, $temp); } while (bccomp($result, $m) >= 0) { $result = bcsub($result, $m); } return $result; } /** * (Regular) Barrett Modular Reduction * * For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this * is that this function does not fold the denominator into a smaller form. * * @param string $x * @param string $n * @return string */ private static function regularBarrett($x, $n) { static $cache = [ self::VARIABLE => [], self::DATA => [] ]; $n_length = strlen($n); if (strlen($x) > 2 * $n_length) { return bcmod($x, $n); } if (($key = array_search($n, $cache[self::VARIABLE])) === false) { $key = count($cache[self::VARIABLE]); $cache[self::VARIABLE][] = $n; $lhs = '1' . str_repeat('0', 2 * $n_length); $cache[self::DATA][] = bcdiv($lhs, $n, 0); } $temp = substr($x, 0, -$n_length + 1); $temp = bcmul($temp, $cache[self::DATA][$key]); $temp = substr($temp, 0, -$n_length - 1); $r1 = substr($x, -$n_length - 1); $r2 = substr(bcmul($temp, $n), -$n_length - 1); $result = bcsub($r1, $r2); //if (bccomp($result, '0') < 0) { if ($result[0] == '-') { $q = '1' . str_repeat('0', $n_length + 1); $result = bcadd($result, $q); } while (bccomp($result, $n) >= 0) { $result = bcsub($result, $n); } return $result; } }<?php /** * BCMath Dynamic Barrett Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\BCMath\Reductions; use phpseclib\Math\BigInteger\Engines\BCMath\Base; use phpseclib\Math\BigInteger\Engines\BCMath; /** * PHP Barrett Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class EvalBarrett extends Base { /** * Custom Reduction Function * * @see self::generateCustomReduction */ private static $custom_reduction; /** * Barrett Modular Reduction * * This calls a dynamically generated loop unrolled function that's specific to a given modulo. * Array lookups are avoided as are if statements testing for how many bits the host OS supports, etc. * * @param string $n * @param string $m * @return string */ protected static function reduce($n, $m) { $inline = self::$custom_reduction; return $inline($n); } /** * Generate Custom Reduction * * @param BCMath $m * @param string $class * @return callable|void */ protected static function generateCustomReduction(BCMath $m, $class) { if (isset($n->reduce)) { self::$custom_reduction = $n->reduce; return $n->reduce; } $m_length = strlen($m); if ($m_length < 5) { $code = 'return bcmod($x, $n);'; eval('$func = function ($n) { ' . $code . '};'); self::$custom_reduction = $func; return; } $lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1)); $u = bcdiv($lhs, $m, 0); $m1 = bcsub($lhs, bcmul($u, $m)); $cutoff = $m_length + ($m_length >> 1); $m = "'$m'"; $u = "'$u'"; $m1= "'$m1'"; $code.= ' $lsd = substr($n, -' . $cutoff . '); $msd = substr($n, 0, -' . $cutoff . '); $temp = bcmul($msd, ' . $m1 . '); $n = bcadd($lsd, $temp); $temp = substr($n, 0, ' . (-$m_length + 1) . '); $temp = bcmul($temp, ' . $u . '); $temp = substr($temp, 0, ' . (-($m_length >> 1) - 1) . '); $temp = bcmul($temp, ' . $m . '); $result = bcsub($n, $temp); if ($result[0] == \'-\') { $temp = \'1' . str_repeat('0', $m_length + 1) . '\'; $result = bcadd($result, $temp); } while (bccomp($result, ' . $m . ') >= 0) { $result = bcsub($result, ' . $m . '); } return $result;'; eval('$func = function ($n) { ' . $code . '};'); self::$custom_reduction = $func; return $func; } }<?php /** * Built-In BCMath Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\BCMath; use phpseclib\Math\BigInteger\Engines\BCMath; /** * Built-In BCMath Modular Exponentiation Engine * * @package BCMath * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class BuiltIn extends BCMath { /** * Performs modular exponentiation. * * @param BCMath $x * @param BCMath $e * @param BCMath $n * @return BCMath */ protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n) { $temp = new BCMath(); $temp->value = bcpowmod($x->value, $e->value, $n->value); return $x->normalize($temp); } }<?php /** * OpenSSL Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\BCMath; use phpseclib\Math\BigInteger\Engines\OpenSSL as Progenitor; /** * OpenSSL Modular Exponentiation Engine * * @package BCMath * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OpenSSL extends Progenitor { }<?php /** * Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\BCMath; use phpseclib\Math\BigInteger\Engines\BCMath; /** * Sliding Window Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Base extends BCMath { /**#@+ * @access private */ /** * Cache constants * * $cache[self::VARIABLE] tells us whether or not the cached data is still valid. */ const VARIABLE = 0; /** * $cache[self::DATA] contains the cached data. */ const DATA = 1; /**#@-*/ /** * Test for engine validity * * @return bool */ public static function isValidEngine() { return static::class != __CLASS__; } /** * Performs modular exponentiation. * * @param \phpseclib\Math\BigInteger\Engines\BCMath $x * @param \phpseclib\Math\BigInteger\Engines\BCMath $e * @param \phpseclib\Math\BigInteger\Engines\BCMath $n * @param string $class * @return \phpseclib\Math\BigInteger\Engines\BCMath */ protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n, $class) { if (empty($e->value)) { $temp = new $class(); $temp->value = '1'; return $x->normalize($temp); } return $x->normalize(static::slidingWindow($x, $e, $n, $class)); } /** * Modular reduction preparation * * @param string $x * @param string $n * @param string $class * @see self::slidingWindow() * @return string */ protected static function prepareReduce($x, $n, $class) { return static::reduce($x, $n); } /** * Modular multiply * * @param string $x * @param string $y * @param string $n * @param string $class * @see self::slidingWindow() * @return string */ protected static function multiplyReduce($x, $y, $n, $class) { return static::reduce(bcmul($x, $y), $n); } /** * Modular square * * @param string $x * @param string $n * @param string $class * @see self::slidingWindow() * @return string */ protected static function squareReduce($x, $n, $class) { return static::reduce(bcmul($x, $x), $n); } }<?php /** * BCMath Default Modular Exponentiation Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines\BCMath; use phpseclib\Math\BigInteger\Engines\BCMath\Reductions\Barrett; /** * PHP Default Modular Exponentiation Engine * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DefaultEngine extends Barrett { }<?php /** * Pure-PHP 32-bit BigInteger Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use ParagonIE\ConstantTime\Hex; /** * Pure-PHP 32-bit Engine. * * Uses 64-bit floats if int size is 4 bits * * @package PHP32 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PHP32 extends PHP { /**#@+ * Constants used by PHP.php */ const BASE = 26; const BASE_FULL = 0x4000000; const MAX_DIGIT = 0x3FFFFFF; const MSB = 0x2000000; /** * MAX10 in greatest MAX10LEN satisfying * MAX10 = 10**MAX10LEN <= 2**BASE. */ const MAX10 = 10000000; /** * MAX10LEN in greatest MAX10LEN satisfying * MAX10 = 10**MAX10LEN <= 2**BASE. */ const MAX10LEN = 7; const MAX_DIGIT2 = 4503599627370496; /**#@-*/ /** * Modular Exponentiation Engine * * @var string */ protected static $modexpEngine; /** * Engine Validity Flag * * @var bool */ protected static $isValidEngine; /** * Primes > 2 and < 1000 * * @var array */ protected static $primes; /** * BigInteger(0) * * @var \phpseclib\Math\BigInteger\Engines\PHP32 */ protected static $zero; /** * BigInteger(1) * * @var \phpseclib\Math\BigInteger\Engines\PHP32 */ protected static $one; /** * BigInteger(2) * * @var \phpseclib\Math\BigInteger\Engines\PHP32 */ protected static $two; /** * Initialize a PHP32 BigInteger Engine instance * * @param int $base * @see parent::initialize() */ protected function initialize($base) { if ($base != 256 && $base != -256) { return parent::initialize($base); } $val = $this->value; $this->value = []; $vals = &$this->value; $i = strlen($val); if (!$i) { return; } while (true) { $i-= 4; if ($i < 0) { if ($i == -4) { break; } $val = substr($val, 0, 4 + $i); $val = str_pad($val, 4, "\0", STR_PAD_LEFT); if ($val == "\0\0\0\0") { break; } $i = 0; } list(, $digit) = unpack('N', substr($val, $i, 4)); $step = count($vals) & 3; if ($step) { $digit>>= 2 * $step; } if ($step != 3) { $digit&= static::MAX_DIGIT; $i++; } $vals[] = $digit; } while (end($vals) === 0) { array_pop($vals); } reset($vals); } /** * Test for engine validity * * @see parent::__construct() * @return bool */ public static function isValidEngine() { return PHP_INT_SIZE >= 4; } /** * Adds two BigIntegers. * * @param PHP32 $y * @return PHP32 */ public function add(PHP32 $y) { $temp = self::addHelper($this->value, $this->is_negative, $y->value, $y->is_negative); return $this->convertToObj($temp); } /** * Subtracts two BigIntegers. * * @param PHP32 $y * @return PHP32 */ public function subtract(PHP32 $y) { $temp = self::subtractHelper($this->value, $this->is_negative, $y->value, $y->is_negative); return $this->convertToObj($temp); } /** * Multiplies two BigIntegers. * * @param PHP32 $y * @return PHP32 */ public function multiply(PHP32 $y) { $temp = self::multiplyHelper($this->value, $this->is_negative, $y->value, $y->is_negative); return $this->convertToObj($temp); } /** * Divides two BigIntegers. * * Returns an array whose first element contains the quotient and whose second element contains the * "common residue". If the remainder would be positive, the "common residue" and the remainder are the * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder * and the divisor (basically, the "common residue" is the first positive modulo). * * @param PHP32 $y * @return PHP32 */ public function divide(PHP32 $y) { return $this->divideHelper($y); } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * @param PHP32 $n * @return false|PHP32 */ public function modInverse(PHP32 $n) { return $this->modInverseHelper($n); } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * @param PHP32 $n * @return PHP32[] */ public function extendedGCD(PHP32 $n) { return $this->extendedGCDHelper($n); } /** * Calculates the greatest common divisor * * Say you have 693 and 609. The GCD is 21. * * @param PHP32 $n * @return PHP32 */ public function gcd(PHP32 $n) { return $this->extendedGCD($n)['gcd']; } /** * Logical And * * @param PHP32 $x * @return PHP32 */ public function bitwise_and(PHP32 $x) { return $this->bitwiseAndHelper($x); } /** * Logical Or * * @param PHP32 $x * @return PHP32 */ public function bitwise_or(PHP32 $x) { return $this->bitwiseOrHelper($x); } /** * Logical Exclusive Or * * @param PHP32 $x * @return PHP32 */ public function bitwise_xor(PHP32 $x) { return $this->bitwiseXorHelper($x); } /** * Compares two numbers. * * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is * demonstrated thusly: * * $x > $y: $x->compare($y) > 0 * $x < $y: $x->compare($y) < 0 * $x == $y: $x->compare($y) == 0 * * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). * * @param PHP32 $y * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. * @access public * @see self::equals() * @internal Could return $this->subtract($x), but that's not as fast as what we do do. */ public function compare(PHP32 $y) { return $this->compareHelper($this->value, $this->is_negative, $y->value, $y->is_negative); } /** * Tests the equality of two numbers. * * If you need to see if one number is greater than or less than another number, use BigInteger::compare() * * @param PHP32 $x * @return bool */ public function equals(PHP32 $x) { return $this->value === $x->value && $this->is_negative == $x->is_negative; } /** * Performs modular exponentiation. * * @param PHP32 $e * @param PHP32 $n * @return PHP32 */ public function modPow(PHP32 $e, PHP32 $n) { return $this->powModOuter($e, $n); } /** * Performs modular exponentiation. * * Alias for modPow(). * * @param PHP32 $e * @param PHP32 $n * @return PHP32 */ public function powMod(PHP32 $e, PHP32 $n) { return $this->powModOuter($e, $n); } /** * Generate a random prime number between a range * * If there's not a prime within the given range, false will be returned. * * @param PHP32 $min * @param PHP32 $max * @return false|PHP32 */ public static function randomRangePrime(PHP32 $min, PHP32 $max) { return self::randomRangePrimeOuter($min, $max); } /** * Generate a random number between a range * * Returns a random number between $min and $max where $min and $max * can be defined using one of the two methods: * * BigInteger::randomRange($min, $max) * BigInteger::randomRange($max, $min) * * @param PHP32 $min * @param PHP32 $max * @return PHP32 */ public static function randomRange(PHP32 $min, PHP32 $max) { return self::randomRangeHelper($min, $max); } /** * Performs exponentiation. * * @param PHP32 $n * @return PHP32 */ public function pow(PHP32 $n) { return $this->powHelper($n); } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param PHP32[] $nums * @return PHP32 */ public static function min(...$nums) { return self::minHelper($nums); } /** * Return the maximum BigInteger between an arbitrary number of BigIntegers. * * @param PHP32[] $nums * @return PHP32 */ public static function max(...$nums) { return self::maxHelper($nums); } /** * Tests BigInteger to see if it is between two integers, inclusive * * @param PHP32 $min * @param PHP32 $max * @return bool */ public function between(PHP32 $min, PHP32 $max) { return $this->compare($min) >= 0 && $this->compare($max) <= 0; } }<?php /** * GMP BigInteger Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use ParagonIE\ConstantTime\Hex; use phpseclib\Exception\BadConfigurationException; /** * GMP Engine. * * @package GMP * @author Jim Wigginton <terrafrost@php.net> * @access public */ class GMP extends Engine { /** * Can Bitwise operations be done fast? * * @see parent::bitwise_leftRotate() * @see parent::bitwise_rightRotate() * @access protected */ const FAST_BITWISE = true; /** * Engine Directory * * @see parent::setModExpEngine * @access protected */ const ENGINE_DIR = 'GMP'; /** * Modular Exponentiation Engine * * @var string */ protected static $modexpEngine; /** * Engine Validity Flag * * @var bool */ protected static $isValidEngine; /** * BigInteger(0) * * @var \phpseclib\Math\BigInteger\Engines\GMP */ protected static $zero; /** * BigInteger(1) * * @var \phpseclib\Math\BigInteger\Engines\GMP */ protected static $one; /** * BigInteger(2) * * @var \phpseclib\Math\BigInteger\Engines\GMP */ protected static $two; /** * Primes > 2 and < 1000 * * Unused for GMP Engine * * @var mixed */ protected static $primes; /** * Test for engine validity * * @see parent::__construct() * @return bool */ public static function isValidEngine() { return extension_loaded('gmp'); } /** * Default constructor * * @param mixed $x integer Base-10 number or base-$base number if $base set. * @param int $base * @see parent::__construct() * @return \phpseclib\Math\BigInteger\Engines\GMP */ public function __construct($x = 0, $base = 10) { if (!isset(self::$isValidEngine)) { self::$isValidEngine = self::isValidEngine(); } if (!self::$isValidEngine) { throw new BadConfigurationException('GMP is not setup correctly on this system'); } if ($x instanceof \GMP) { $this->value = $x; return; } $this->value = gmp_init(0); parent::__construct($x, $base); } /** * Initialize a GMP BigInteger Engine instance * * @param int $base * @see parent::__construct() */ protected function initialize($base) { switch (abs($base)) { case 256: $this->value = gmp_import($this->value); if ($this->is_negative) { $this->value = -$this->value; } break; case 16: $temp = $this->is_negative ? '-0x' . $this->value : '0x' . $this->value; $this->value = gmp_init($temp); break; case 10: $this->value = gmp_init(isset($this->value) ? $this->value : '0'); } } /** * Converts a BigInteger to a base-10 number. * * @return string */ public function toString() { return (string) $this->value; } /** * Converts a BigInteger to a bit string (eg. base-2). * * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're * saved as two's compliment. * * @param bool $twos_compliment * @return string */ public function toBits($twos_compliment = false) { $hex = $this->toHex($twos_compliment); $bits = gmp_strval(gmp_init($hex, 16), 2); if ($this->precision > 0) { $bits = substr($bits, -$this->precision); } if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) { return '0' . $bits; } return $bits; } /** * Converts a BigInteger to a byte string (eg. base-256). * * @param bool $twos_compliment * @return string */ function toBytes($twos_compliment = false) { if ($twos_compliment) { return $this->toBytesHelper(); } if (gmp_cmp($this->value, gmp_init(0)) == 0) { return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; } $temp = gmp_export($this->value); return $this->precision > 0 ? substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : ltrim($temp, chr(0)); } /** * Adds two BigIntegers. * * @param GMP $y * @return GMP */ public function add(GMP $y) { $temp = new self(); $temp->value = $this->value + $y->value; return $this->normalize($temp); } /** * Subtracts two BigIntegers. * * @param GMP $y * @return GMP */ public function subtract(GMP $y) { $temp = new self(); $temp->value = $this->value - $y->value; return $this->normalize($temp); } /** * Multiplies two BigIntegers. * * @param GMP $x * @return GMP */ public function multiply(GMP $x) { $temp = new self(); $temp->value = $this->value * $x->value; return $this->normalize($temp); } /** * Divides two BigIntegers. * * Returns an array whose first element contains the quotient and whose second element contains the * "common residue". If the remainder would be positive, the "common residue" and the remainder are the * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder * and the divisor (basically, the "common residue" is the first positive modulo). * * @param GMP $y * @return GMP */ public function divide(GMP $y) { $quotient = new self(); $remainder = new self(); list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); if (gmp_sign($remainder->value) < 0) { $remainder->value = $remainder->value + gmp_abs($y->value); } return [$this->normalize($quotient), $this->normalize($remainder)]; } /** * Compares two numbers. * * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is * demonstrated thusly: * * $x > $y: $x->compare($y) > 0 * $x < $y: $x->compare($y) < 0 * $x == $y: $x->compare($y) == 0 * * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). * * @param GMP $y * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. * @access public * @see self::equals() * @internal Could return $this->subtract($x), but that's not as fast as what we do do. */ public function compare(GMP $y) { $r = gmp_cmp($this->value, $y->value); if ($r < -1) { $r = -1; } if ($r > 1) { $r = 1; } return $r; } /** * Tests the equality of two numbers. * * If you need to see if one number is greater than or less than another number, use BigInteger::compare() * * @param GMP $x * @return bool */ public function equals(GMP $x) { return $this->value == $x->value; } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * * @param GMP $n * @return false|GMP */ public function modInverse(GMP $n) { $temp = new self(); $temp->value = gmp_invert($this->value, $n->value); return $temp->value === false ? false : $this->normalize($temp); } /** * Calculates the greatest common divisor and Bezout's identity. * * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which * combination is returned is dependent upon which mode is in use. See * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. * * @param \phpseclib\Math\BigInteger\Engines\GMP $n * @return \phpseclib\Math\BigInteger\Engines\GMP[] */ public function extendedGCD(GMP $n) { extract(gmp_gcdext($this->value, $n->value)); return [ 'gcd' => $this->normalize(new self($g)), 'x' => $this->normalize(new self($s)), 'y' => $this->normalize(new self($t)) ]; } /** * Calculates the greatest common divisor * * Say you have 693 and 609. The GCD is 21. * * @param GMP $n * @return GMP */ public function gcd(GMP $n) { $r = gmp_gcd($this->value, $n->value); return $this->normalize(new self($r)); } /** * Absolute value. * * @return \phpseclib\Math\BigInteger\Engines\GMP * @access public */ public function abs() { $temp = new self(); $temp->value = gmp_abs($this->value); return $temp; } /** * Logical And * * @param GMP $x * @return GMP */ public function bitwise_and(GMP $x) { $temp = new self(); $temp->value = $this->value & $x->value; return $this->normalize($temp); } /** * Logical Or * * @param GMP $x * @return GMP */ public function bitwise_or(GMP $x) { $temp = new self(); $temp->value = $this->value | $x->value; return $this->normalize($temp); } /** * Logical Exclusive Or * * @param GMP $x * @return GMP */ public function bitwise_xor(GMP $x) { $temp = new self(); $temp->value = $this->value ^ $x->value; return $this->normalize($temp); } /** * Logical Right Shift * * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\GMP */ public function bitwise_rightShift($shift) { // 0xFFFFFFFF >> 2 == -1 (on 32-bit systems) // gmp_init('0xFFFFFFFF') >> 2 == gmp_init('0x3FFFFFFF') $temp = new self(); $temp->value = $this->value >> $shift; return $this->normalize($temp); } /** * Logical Left Shift * * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\GMP */ public function bitwise_leftShift($shift) { $temp = new self(); $temp->value = $this->value << $shift; return $this->normalize($temp); } /** * Performs modular exponentiation. * * @param GMP $e * @param GMP $n * @return GMP */ public function modPow(GMP $e, GMP $n) { return $this->powModOuter($e, $n); } /** * Performs modular exponentiation. * * Alias for modPow(). * * @param GMP $e * @param GMP $n * @return GMP */ public function powMod(GMP $e, GMP $n) { return $this->powModOuter($e, $n); } /** * Performs modular exponentiation. * * @param GMP $e * @param GMP $n * @return GMP */ protected function powModInner(GMP $e, GMP $n) { $class = self::$modexpEngine; return $class::powModHelper($this, $e, $n); } /** * Normalize * * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision * * @param GMP $result * @return GMP */ protected function normalize(GMP $result) { unset($result->reduce); $result->precision = $this->precision; $result->bitmask = $this->bitmask; if ($result->bitmask !== false) { $result->value = $result->value & $result->bitmask->value; } return $result; } /** * Performs some post-processing for randomRangePrime * * @param Engine $x * @param Engine $min * @param Engine $max * @return GMP */ protected static function randomRangePrimeInner(Engine $x, Engine $min, Engine $max) { $p = gmp_nextprime($x->value); if ($p <= $max->value) { return new self($p); } if ($min->value != $x->value) { $x = new self($x->value - 1); } return self::randomRangePrime($min, $x); } /** * Generate a random prime number between a range * * If there's not a prime within the given range, false will be returned. * * @param GMP $min * @param GMP $max * @return false|GMP */ public static function randomRangePrime(GMP $min, GMP $max) { return self::randomRangePrimeOuter($min, $max); } /** * Generate a random number between a range * * Returns a random number between $min and $max where $min and $max * can be defined using one of the two methods: * * BigInteger::randomRange($min, $max) * BigInteger::randomRange($max, $min) * * @param GMP $min * @param GMP $max * @return GMP */ public static function randomRange(GMP $min, GMP $max) { return self::randomRangeHelper($min, $max); } /** * Make the current number odd * * If the current number is odd it'll be unchanged. If it's even, one will be added to it. * * @see self::randomPrime() */ protected function make_odd() { gmp_setbit($this->value, 0); } /** * Tests Primality * * @param int $t * @return bool */ protected function testPrimality($t) { return gmp_prob_prime($this->value, $t) != 0; } /** * Calculates the nth root of a biginteger. * * Returns the nth root of a positive biginteger, where n defaults to 2 * * @param int $n * @return GMP */ protected function rootInner($n) { $root = new self(); $root->value = gmp_root($this->value, $n); return $this->normalize($root); } /** * Performs exponentiation. * * @param GMP $n * @return GMP */ public function pow(GMP $n) { $temp = new self(); $temp->value = $this->value ** $n->value; return $this->normalize($temp); } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param GMP[] $nums * @return GMP */ public static function min(...$nums) { return self::minHelper($nums); } /** * Return the maximum BigInteger between an arbitrary number of BigIntegers. * * @param GMP[] $nums * @return GMP */ public static function max(...$nums) { return self::maxHelper($nums); } /** * Tests BigInteger to see if it is between two integers, inclusive * * @param GMP $min * @param GMP $max * @return bool */ public function between(GMP $min, GMP $max) { return $this->compare($min) >= 0 && $this->compare($max) <= 0; } /** * Create Recurring Modulo Function * * Sometimes it may be desirable to do repeated modulos with the same number outside of * modular exponentiation * * @return callable */ public function createRecurringModuloFunction() { $temp = $this->value; $this->reduce = function(GMP $x) use ($temp) { return new GMP($x->value % $temp); }; return $this->reduce; } /** * Scan for 1 and right shift by that amount * * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); * * @param GMP $r * @return int */ public static function scan1divide(GMP $r) { $s = gmp_scan1($r->value, 0); $r->value >>= $s; return $s; } /** * Is Odd? * * @return boolean */ public function isOdd() { return gmp_testbit($this->value, 0); } /** * Tests if a bit is set * * @return boolean */ public function testBit($x) { return gmp_testbit($this->value, $x); } /** * Is Negative? * * @return boolean */ public function isNegative() { return gmp_sign($this->value) == -1; } /** * Negate * * Given $k, returns -$k * * @return GMP */ public function negate() { $temp = clone $this; $temp->value = -$this->value; return $temp; } }<?php /** * BCMath BigInteger Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use ParagonIE\ConstantTime\Hex; use phpseclib\Exception\BadConfigurationException; /** * BCMath Engine. * * @package BCMath * @author Jim Wigginton <terrafrost@php.net> * @access public */ class BCMath extends Engine { /** * Can Bitwise operations be done fast? * * @see parent::bitwise_leftRotate() * @see parent::bitwise_rightRotate() * @access protected */ const FAST_BITWISE = false; /** * Engine Directory * * @see parent::setModExpEngine * @access protected */ const ENGINE_DIR = 'BCMath'; /** * Modular Exponentiation Engine * * @var string */ protected static $modexpEngine; /** * Engine Validity Flag * * @var bool */ protected static $isValidEngine; /** * BigInteger(0) * * @var \phpseclib\Math\BigInteger\Engines\BCMath */ protected static $zero; /** * BigInteger(1) * * @var \phpseclib\Math\BigInteger\Engines\BCMath */ protected static $one; /** * BigInteger(2) * * @var \phpseclib\Math\BigInteger\Engines\BCMath */ protected static $two; /** * Primes > 2 and < 1000 * * @var array */ protected static $primes; /** * Test for engine validity * * @see parent::__construct() * @return bool */ public static function isValidEngine() { return extension_loaded('bcmath'); } /** * Default constructor * * @param mixed $x integer Base-10 number or base-$base number if $base set. * @param int $base * @see parent::__construct() * @return \phpseclib\Math\BigInteger\Engines\BCMath */ public function __construct($x = 0, $base = 10) { if (!isset(self::$isValidEngine)) { self::$isValidEngine = self::isValidEngine(); } if (!self::$isValidEngine) { throw new BadConfigurationException('BCMath is not setup correctly on this system'); } $this->value = '0'; parent::__construct($x, $base); } /** * Initialize a BCMath BigInteger Engine instance * * @param int $base * @see parent::__construct() */ protected function initialize($base) { switch (abs($base)) { case 256: // round $len to the nearest 4 $len = (strlen($this->value) + 3) & 0xFFFFFFFC; $x = str_pad($this->value, $len, chr(0), STR_PAD_LEFT); $this->value = '0'; for ($i = 0; $i < $len; $i+= 4) { $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32 $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0); } if ($this->is_negative) { $this->value = '-' . $this->value; } break; case 16: $x = (strlen($this->value) & 1) ? '0' . $this->value : $this->value; $temp = new self(Hex::decode($x), 256); $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; $this->is_negative = false; break; case 10: // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different // results then doing it on '-1' does (modInverse does $x[0]) $this->value = $this->value === '-' ? '0' : (string) $this->value; } } /** * Converts a BigInteger to a base-10 number. * * @return string */ public function toString() { if ($this->value === '0') { return '0'; } return ltrim($this->value, '0'); } /** * Converts a BigInteger to a byte string (eg. base-256). * * @param bool $twos_compliment * @return string */ function toBytes($twos_compliment = false) { if ($twos_compliment) { return $this->toBytesHelper(); } $value = ''; $current = $this->value; if ($current[0] == '-') { $current = substr($current, 1); } while (bccomp($current, '0', 0) > 0) { $temp = bcmod($current, '16777216'); $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; $current = bcdiv($current, '16777216', 0); } return $this->precision > 0 ? substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : ltrim($value, chr(0)); } /** * Adds two BigIntegers. * * @param BCMath $y * @return BCMath */ public function add(BCMath $y) { $temp = new self(); $temp->value = bcadd($this->value, $y->value); return $this->normalize($temp); } /** * Subtracts two BigIntegers. * * @param BCMath $y * @return BCMath */ public function subtract(BCMath $y) { $temp = new self(); $temp->value = bcsub($this->value, $y->value); return $this->normalize($temp); } /** * Multiplies two BigIntegers. * * @param BCMath $x * @return BCMath */ public function multiply(BCMath $x) { $temp = new self(); $temp->value = bcmul($this->value, $x->value); return $this->normalize($temp); } /** * Divides two BigIntegers. * * Returns an array whose first element contains the quotient and whose second element contains the * "common residue". If the remainder would be positive, the "common residue" and the remainder are the * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder * and the divisor (basically, the "common residue" is the first positive modulo). * * @param BCMath $y * @return BCMath */ public function divide(BCMath $y) { $quotient = new self(); $remainder = new self(); $quotient->value = bcdiv($this->value, $y->value, 0); $remainder->value = bcmod($this->value, $y->value); if ($remainder->value[0] == '-') { $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); } return [$this->normalize($quotient), $this->normalize($remainder)]; } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * * @return false|BCMath * @param \phpseclib\Math\BigInteger\Engines\BCMath $n */ public function modInverse(BCMath $n) { return $this->modInverseHelper($n); } /** * Calculates the greatest common divisor and Bezout's identity. * * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which * combination is returned is dependent upon which mode is in use. See * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. * * @param BCMath $n * @return BCMath */ public function extendedGCD(BCMath $n) { // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is, // the basic extended euclidean algorithim is what we're using. $u = $this->value; $v = $n->value; $a = '1'; $b = '0'; $c = '0'; $d = '1'; while (bccomp($v, '0', 0) != 0) { $q = bcdiv($u, $v, 0); $temp = $u; $u = $v; $v = bcsub($temp, bcmul($v, $q, 0), 0); $temp = $a; $a = $c; $c = bcsub($temp, bcmul($a, $q, 0), 0); $temp = $b; $b = $d; $d = bcsub($temp, bcmul($b, $q, 0), 0); } return [ 'gcd' => $this->normalize(new static($u)), 'x' => $this->normalize(new static($a)), 'y' => $this->normalize(new static($b)) ]; } /** * Calculates the greatest common divisor * * Say you have 693 and 609. The GCD is 21. * * @param BCMath $n * @return BCMath */ public function gcd(BCMath $n) { extract($this->extendedGCD($n)); /** @var BCMath $gcd */ return $gcd; } /** * Absolute value. * * @return \phpseclib\Math\BigInteger\Engines\BCMath */ public function abs() { $temp = new static(); $temp->value = strlen($this->value) && $this->value[0] == '-' ? substr($this->value, 1) : $this->value; return $temp; } /** * Logical And * * @param BCMath $x * @return BCMath */ public function bitwise_and(BCMath $x) { return $this->bitwiseAndHelper($x); } /** * Logical Or * * @param BCMath $x * @return BCMath */ public function bitwise_or(BCMath $x) { return $this->bitwiseXorHelper($x); } /** * Logical Exclusive Or * * @param BCMath $x * @return BCMath */ public function bitwise_xor(BCMath $x) { return $this->bitwiseXorHelper($x); } /** * Logical Right Shift * * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\BCMath */ public function bitwise_rightShift($shift) { $temp = new static(); $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0); return $this->normalize($temp); } /** * Logical Left Shift * * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\BCMath */ public function bitwise_leftShift($shift) { $temp = new static(); $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0); return $this->normalize($temp); } /** * Compares two numbers. * * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is * demonstrated thusly: * * $x > $y: $x->compare($y) > 0 * $x < $y: $x->compare($y) < 0 * $x == $y: $x->compare($y) == 0 * * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). * * @param BCMath $y * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. * @see self::equals() * @internal Could return $this->subtract($x), but that's not as fast as what we do do. */ public function compare(BCMath $y) { return bccomp($this->value, $y->value, 0); } /** * Tests the equality of two numbers. * * If you need to see if one number is greater than or less than another number, use BigInteger::compare() * * @param BCMath $x * @return bool */ public function equals(BCMath $x) { return $this->value == $x->value; } /** * Performs modular exponentiation. * * @param BCMath $e * @param BCMath $n * @return BCMath */ public function modPow(BCMath $e, BCMath $n) { return $this->powModOuter($e, $n); } /** * Performs modular exponentiation. * * Alias for modPow(). * * @param BCMath $e * @param BCMath $n * @return BCMath */ public function powMod(BCMath $e, BCMath $n) { return $this->powModOuter($e, $n); } /** * Performs modular exponentiation. * * @param BCMath $e * @param BCMath $n * @return BCMath */ protected function powModInner(BCMath $e, BCMath $n) { try { $class = self::$modexpEngine; return $class::powModHelper($this, $e, $n, static::class); } catch (\Exception $err) { return BCMath\DefaultEngine::powModHelper($this, $e, $n, static::class); } } /** * Normalize * * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision * * @param BCMath $result * @return BCMath */ protected function normalize(BCMath $result) { unset($result->reduce); $result->precision = $this->precision; $result->bitmask = $this->bitmask; if ($result->bitmask !== false) { $result->value = bcmod($result->value, $result->bitmask->value); } return $result; } /** * Generate a random prime number between a range * * If there's not a prime within the given range, false will be returned. * * @param BCMath $min * @param BCMath $max * @return false|BCMath */ public static function randomRangePrime(BCMath $min, BCMath $max) { return self::randomRangePrimeOuter($min, $max); } /** * Generate a random number between a range * * Returns a random number between $min and $max where $min and $max * can be defined using one of the two methods: * * BigInteger::randomRange($min, $max) * BigInteger::randomRange($max, $min) * * @param BCMath $min * @param BCMath $max * @return BCMath */ public static function randomRange(BCMath $min, BCMath $max) { return self::randomRangeHelper($min, $max); } /** * Make the current number odd * * If the current number is odd it'll be unchanged. If it's even, one will be added to it. * * @see self::randomPrime() */ protected function make_odd() { if (!$this->isOdd()) { $this->value = bcadd($this->value, '1'); } } /** * Test the number against small primes. * * @see self::isPrime() */ protected function testSmallPrimes() { if ($this->value === '1') { return false; } if ($this->value === '2') { return true; } if ($this->value[strlen($this->value) - 1] % 2 == 0) { return false; } $value = $this->value; foreach (self::$primes as $prime) { $r = bcmod($this->value, $prime); if ($r == '0') { return $this->value == $prime; } } return true; } /** * Scan for 1 and right shift by that amount * * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); * * @see self::isPrime() * @param BCMath $r * @return int */ public static function scan1divide(BCMath $r) { $r_value = &$r->value; $s = 0; // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals(static::$one) check earlier while ($r_value[strlen($r_value) - 1] % 2 == 0) { $r_value = bcdiv($r_value, '2', 0); ++$s; } return $s; } /** * Performs exponentiation. * * @param BCMath $n * @return BCMath */ public function pow(BCMath $n) { $temp = new self(); $temp->value = bcpow($this->value, $n->value); return $this->normalize($temp); } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param BCMath[] $nums * @return BCMath */ public static function min(...$nums) { return self::minHelper($nums); } /** * Return the maximum BigInteger between an arbitrary number of BigIntegers. * * @param BCMath[] $nums * @return BCMath */ public static function max(...$nums) { return self::maxHelper($nums); } /** * Tests BigInteger to see if it is between two integers, inclusive * * @param BCMath $min * @param BCMath $max * @return bool */ public function between(BCMath $min, BCMath $max) { return $this->compare($min) >= 0 && $this->compare($max) <= 0; } /** * Set Bitmask * * @return Engine * @param int $bits * @see self::setPrecision() */ protected static function setBitmask($bits) { $temp = parent::setBitmask($bits); return $temp->add(static::$one); } /** * Is Odd? * * @return boolean */ public function isOdd() { return $this->value[strlen($this->value) - 1] % 2 == 1; } /** * Tests if a bit is set * * @return boolean */ public function testBit($x) { return bccomp( bcmod($this->value, bcpow('2', $x + 1, 0), 0), bcpow('2', $x, 0), 0 ) >= 0; } /** * Is Negative? * * @return boolean */ public function isNegative() { return strlen($this->value) && $this->value[0] == '-'; } /** * Negate * * Given $k, returns -$k * * @return BCMath */ public function negate() { $temp = clone $this; if (!strlen($temp->value)) { return $temp; } $temp->value = $temp->value[0] == '-' ? substr($this->value, 1) : '-' . $this->value; return $temp; } }<?php /** * Base BigInteger Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use ParagonIE\ConstantTime\Hex; use phpseclib\Exception\BadConfigurationException; use phpseclib\Crypt\Random; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; /** * Base Engine. * * @package Engine * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Engine implements \Serializable { /** * Holds the BigInteger's value * * @var mixed */ protected $value; /** * Holds the BigInteger's sign * * @var bool */ protected $is_negative; /** * Precision * * @see static::setPrecision() */ protected $precision = -1; /** * Precision Bitmask * * @see static::setPrecision() */ protected $bitmask = false; /** * Recurring Modulo Function * * @var callable */ protected $reduce; /** * Default constructor * * @param mixed $x integer Base-10 number or base-$base number if $base set. * @param int $base */ public function __construct($x, $base) { if (!isset(static::$primes)) { static::$primes = [ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 ]; static::$zero = new static(0); static::$one = new static(1); static::$two = new static(2); } // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48 // '0' is the only value like this per http://php.net/empty if (empty($x) && (abs($base) != 256 || $x !== '0')) { return; } switch ($base) { case -256: case 256: if ($base == -256 && (ord($x[0]) & 0x80)) { $this->value = ~$x; $this->is_negative = true; } else { $this->value = $x; $this->is_negative = false; } static::initialize($base); if ($this->is_negative) { $temp = $this->add(new static('-1')); $this->value = $temp->value; } break; case -16: case 16: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); $is_negative = false; if ($base < 0 && hexdec($x[0]) >= 8) { $this->is_negative = $is_negative = true; $x = Hex::encode(~Hex::decode($x)); } $this->value = $x; static::initialize($base); if ($is_negative) { $temp = $this->add(new static('-1')); $this->value = $temp->value; } break; case -10: case 10: // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals) // [^-0-9].*: find any non-numeric characters and then any characters that follow that $this->value = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x); if (!strlen($this->value) || $this->value == '-') { $this->value = '0'; } static::initialize($base); break; case -2: case 2: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = preg_replace('#^([01]*).*#', '$1', $x); $temp = new static(Strings::bits2bin($x), 128 * $base); // ie. either -16 or +16 $this->value = $temp->value; if ($temp->is_negative) { $this->is_negative = true; } break; default: // base not supported, so we'll let $this == 0 } } /** * Sets engine type. * * Throws an exception if the type is invalid * * @param string $engine */ public static function setModExpEngine($engine) { $fqengine = '\\phpseclib\\Math\\BigInteger\\Engines\\' . static::ENGINE_DIR . '\\' . $engine; if (!class_exists($fqengine) || !method_exists($fqengine, 'isValidEngine')) { throw new \InvalidArgumentException("$engine is not a valid engine"); } if (!$fqengine::isValidEngine()) { throw new BadConfigurationException("$engine is not setup correctly on this system"); } static::$modexpEngine = $fqengine; } /** * Converts a BigInteger to a byte string (eg. base-256). * * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're * saved as two's compliment. * @return string */ protected function toBytesHelper() { $comparison = $this->compare(new static()); if ($comparison == 0) { return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; } $temp = $comparison < 0 ? $this->add(new static(1)) : $this; $bytes = $temp->toBytes(); if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1 $bytes = chr(0); } if (ord($bytes[0]) & 0x80) { $bytes = chr(0) . $bytes; } return $comparison < 0 ? ~$bytes : $bytes; } /** * Converts a BigInteger to a hex string (eg. base-16). * * @param bool $twos_compliment * @return string */ public function toHex($twos_compliment = false) { return Hex::encode($this->toBytes($twos_compliment)); } /** * Converts a BigInteger to a bit string (eg. base-2). * * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're * saved as two's compliment. * * @param bool $twos_compliment * @return string */ public function toBits($twos_compliment = false) { $hex = $this->toBytes($twos_compliment); $bits = Strings::bin2bits($hex); $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) { return '0' . $result; } return $result; } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * * @param \phpseclib\Math\BigInteger\Engines\Engine $n * @return \phpseclib\Math\BigInteger\Engines\Engine|false * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information. */ protected function modInverseHelper(Engine $n) { // $x mod -$n == $x mod $n. $n = $n->abs(); if ($this->compare(static::$zero) < 0) { $temp = $this->abs(); $temp = $temp->modInverse($n); return $this->normalize($n->subtract($temp)); } extract($this->extendedGCD($n)); /** * @var BigInteger $gcd * @var BigInteger $x */ if (!$gcd->equals(static::$one)) { return false; } $x = $x->compare(static::$zero) < 0 ? $x->add($n) : $x; return $this->compare(static::$zero) < 0 ? $this->normalize($n->subtract($x)) : $this->normalize($x); } /** * Serialize * * Will be called, automatically, when serialize() is called on a BigInteger object. * * @return string */ public function serialize() { $val = ['hex' => $this->toHex(true)]; if ($this->precision > 0) { $val['precision'] = $this->precision; } return serialize($val); } /** * Serialize * * Will be called, automatically, when unserialize() is called on a BigInteger object. * * @param string $serialized */ public function unserialize($serialized) { $r = unserialize($serialized); $temp = new static($r['hex'], -16); $this->value = $temp->value; $this->is_negative = $temp->is_negative; if (isset($r['precision'])) { // recalculate $this->bitmask $this->setPrecision($r['precision']); } } /** * Converts a BigInteger to a base-10 number. * * @return string */ public function __toString() { return $this->toString(); } /** * __debugInfo() magic method * * Will be called, automatically, when print_r() or var_dump() are called */ public function __debugInfo() { return [ 'value' => '0x' . $this->toHex(true), 'engine' => basename(static::class) ]; } /** * Set Precision * * Some bitwise operations give different results depending on the precision being used. Examples include left * shift, not, and rotates. * * @param int $bits */ public function setPrecision($bits) { if ($bits < 1) { $this->precision = -1; $this->bitmask = false; return; } $this->precision = $bits; $this->bitmask = static::setBitmask($bits); $temp = $this->normalize($this); $this->value = $temp->value; } /** * Get Precision * * Returns the precision if it exists, -1 if it doesn't * * @return int */ public function getPrecision() { return $this->precision; } /** * Set Bitmask * @return Engine * @param int $bits * @see self::setPrecision() */ protected static function setBitmask($bits) { return new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); } /** * Logical Not * * @return Engine|string */ public function bitwise_not() { // calculuate "not" without regard to $this->precision // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0) $temp = $this->toBytes(); if ($temp == '') { return $this->normalize(static::$zero); } $pre_msb = decbin(ord($temp[0])); $temp = ~$temp; $msb = decbin(ord($temp[0])); if (strlen($msb) == 8) { $msb = substr($msb, strpos($msb, '0')); } $temp[0] = chr(bindec($msb)); // see if we need to add extra leading 1's $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; $new_bits = $this->precision - $current_bits; if ($new_bits <= 0) { return $this->normalize(new static($temp, 256)); } // generate as many leading 1's as we need to. $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); self::base256_lshift($leading_ones, $current_bits); $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT); return $this->normalize(new static($leading_ones | $temp, 256)); } /** * Logical Left Shift * * Shifts binary strings $shift bits, essentially multiplying by 2**$shift. * * @param $x String * @param $shift Integer * @return string */ protected static function base256_lshift(&$x, $shift) { if ($shift == 0) { return; } $num_bytes = $shift >> 3; // eg. floor($shift/8) $shift &= 7; // eg. $shift % 8 $carry = 0; for ($i = strlen($x) - 1; $i >= 0; --$i) { $temp = ord($x[$i]) << $shift | $carry; $x[$i] = chr($temp); $carry = $temp >> 8; } $carry = ($carry != 0) ? chr($carry) : ''; $x = $carry . $x . str_repeat(chr(0), $num_bytes); } /** * Logical Left Rotate * * Instead of the top x bits being dropped they're appended to the shifted bit string. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\Engine */ public function bitwise_leftRotate($shift) { $bits = $this->toBytes(); if ($this->precision > 0) { $precision = $this->precision; if (static::FAST_BITWISE) { $mask = $this->bitmask->toBytes(); } else { $mask = $this->bitmask->subtract(new static(1)); $mask = $mask->toBytes(); } } else { $temp = ord($bits[0]); for ($i = 0; $temp >> $i; ++$i) { } $precision = 8 * strlen($bits) - 8 + $i; $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); } if ($shift < 0) { $shift+= $precision; } $shift%= $precision; if (!$shift) { return clone $this; } $left = $this->bitwise_leftShift($shift); $left = $left->bitwise_and(new static($mask, 256)); $right = $this->bitwise_rightShift($precision - $shift); $result = static::FAST_BITWISE ? $left->bitwise_or($right) : $left->add($right); return $this->normalize($result); } /** * Logical Right Rotate * * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. * * @param int $shift * @return \phpseclib\Math\BigInteger\Engines\Engine */ public function bitwise_rightRotate($shift) { return $this->bitwise_leftRotate(-$shift); } /** * Returns the smallest and largest n-bit number * * @param int $bits * @return \phpseclib\Math\BigInteger\Engines\Engine[] */ public static function minMaxBits($bits) { $bytes = $bits >> 3; $min = str_repeat(chr(0), $bytes); $max = str_repeat(chr(0xFF), $bytes); $msb = $bits & 7; if ($msb) { $min = chr(1 << ($msb - 1)) . $min; $max = chr((1 << $msb) - 1) . $max; } else { $min[0] = chr(0x80); } return [ 'min' => new static($min, 256), 'max' => new static($max, 256) ]; } /** * Return the size of a BigInteger in bits * * @return int */ public function getLength() { return strlen($this->toBits()); } /** * Return the size of a BigInteger in bytes * * @return int */ public function getLengthInBytes() { return strlen($this->toBytes()); } /** * Performs some pre-processing for powMod * * @param Engine $e * @param Engine $n * @return bool|Engine */ protected function powModOuter(Engine $e, Engine $n) { $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); if ($e->compare(new static()) < 0) { $e = $e->abs(); $temp = $this->modInverse($n); if ($temp === false) { return false; } return $this->normalize($temp->powModInner($e, $n)); } return $this->powModInner($e, $n); } /** * Sliding Window k-ary Modular Exponentiation * * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} / * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims, * however, this function performs a modular reduction after every multiplication and squaring operation. * As such, this function has the same preconditions that the reductions being used do. * * @param \phpseclib\Math\BigInteger\Engines\Engine $x * @param \phpseclib\Math\BigInteger\Engines\Engine $e * @param \phpseclib\Math\BigInteger\Engines\Engine $n * @param string $class * @return \phpseclib\Math\BigInteger\Engines\Engine */ protected static function slidingWindow(Engine $x, Engine $e, Engine $n, $class) { static $window_ranges = [7, 25, 81, 241, 673, 1793]; // from BigInteger.java's oddModPow function //static $window_ranges = [0, 7, 36, 140, 450, 1303, 3529]; // from MPM 7.3.1 $e_bits = $e->toBits(); $e_length = strlen($e_bits); // calculate the appropriate window size. // $window_size == 3 if $window_ranges is between 25 and 81, for example. for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) { } $n_value = $n->value; if (method_exists(static::class, 'generateCustomReduction')) { static::generateCustomReduction($n, $class); } // precompute $this^0 through $this^$window_size $powers = []; $powers[1] = static::prepareReduce($x->value, $n_value, $class); $powers[2] = static::squareReduce($powers[1], $n_value, $class); // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end // in a 1. ie. it's supposed to be odd. $temp = 1 << ($window_size - 1); for ($i = 1; $i < $temp; ++$i) { $i2 = $i << 1; $powers[$i2 + 1] = static::multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $class); } $result = new $class(1); $result = static::prepareReduce($result->value, $n_value, $class); for ($i = 0; $i < $e_length;) { if (!$e_bits[$i]) { $result = static::squareReduce($result, $n_value, $class); ++$i; } else { for ($j = $window_size - 1; $j > 0; --$j) { if (!empty($e_bits[$i + $j])) { break; } } // eg. the length of substr($e_bits, $i, $j + 1) for ($k = 0; $k <= $j; ++$k) { $result = static::squareReduce($result, $n_value, $class); } $result = static::multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $class); $i += $j + 1; } } $temp = new $class(); $temp->value = static::reduce($result, $n_value, $class); return $temp; } /** * Generates a random number of a certain size * * Bit length is equal to $size * * @param int $size * @return \phpseclib\Math\BigInteger\Engines\Engine */ public static function random($size) { extract(static::minMaxBits($size)); /** * @var BigInteger $min * @var BigInteger $max */ return static::randomRange($min, $max); } /** * Generates a random prime number of a certain size * * Bit length is equal to $size * * @param int $size * @return \phpseclib\Math\BigInteger\Engines\Engine */ public static function randomPrime($size) { extract(static::minMaxBits($size)); /** * @var BigInteger $min * @var BigInteger $max */ return static::randomRangePrime($min, $max); } /** * Performs some pre-processing for randomRangePrime * * @param Engine $min * @param Engine $max * @return bool|Engine */ protected static function randomRangePrimeOuter(Engine $min, Engine $max) { $compare = $max->compare($min); if (!$compare) { return $min->isPrime() ? $min : false; } elseif ($compare < 0) { // if $min is bigger then $max, swap $min and $max $temp = $max; $max = $min; $min = $temp; } $x = static::randomRange($min, $max); return static::randomRangePrimeInner($x, $min, $max); } /** * Generate a random number between a range * * Returns a random number between $min and $max where $min and $max * can be defined using one of the two methods: * * BigInteger::randomRange($min, $max) * BigInteger::randomRange($max, $min) * * @param Engine $min * @param Engine $max * @return Engine */ protected static function randomRangeHelper(Engine $min, Engine $max) { $compare = $max->compare($min); if (!$compare) { return $min; } elseif ($compare < 0) { // if $min is bigger then $max, swap $min and $max $temp = $max; $max = $min; $min = $temp; } if (!isset(static::$one)) { static::$one = new static(1); } $max = $max->subtract($min->subtract(static::$one)); $size = strlen(ltrim($max->toBytes(), chr(0))); /* doing $random % $max doesn't work because some numbers will be more likely to occur than others. eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145 would produce 5 whereas the only value of random that could produce 139 would be 139. ie. not all numbers would be equally likely. some would be more likely than others. creating a whole new random number until you find one that is within the range doesn't work because, for sufficiently small ranges, the likelihood that you'd get a number within that range would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability would be pretty high that $random would be greater than $max. phpseclib works around this using the technique described here: http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string */ $random_max = new static(chr(1) . str_repeat("\0", $size), 256); $random = new static(Random::string($size), 256); list($max_multiple) = $random_max->divide($max); $max_multiple = $max_multiple->multiply($max); while ($random->compare($max_multiple) >= 0) { $random = $random->subtract($max_multiple); $random_max = $random_max->subtract($max_multiple); $random = $random->bitwise_leftShift(8); $random = $random->add(new static(Random::string(1), 256)); $random_max = $random_max->bitwise_leftShift(8); list($max_multiple) = $random_max->divide($max); $max_multiple = $max_multiple->multiply($max); } list(, $random) = $random->divide($max); return $random->add($min); } /** * Performs some post-processing for randomRangePrime * * @param Engine $x * @param Engine $min * @param Engine $max * @return bool|Engine */ protected static function randomRangePrimeInner(Engine $x, Engine $min, Engine $max) { if (!isset(static::$two)) { static::$two = new static('2'); } $x->make_odd(); if ($x->compare($max) > 0) { // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range if ($min->equals($max)) { return false; } $x = clone $min; $x->make_odd(); } $initial_x = clone $x; while (true) { if ($x->isPrime()) { return $x; } $x = $x->add(static::$two); if ($x->compare($max) > 0) { $x = clone $min; if ($x->equals(static::$two)) { return $x; } $x->make_odd(); } if ($x->equals($initial_x)) { return false; } } } /** * Sets the $t parameter for primality testing * * @return int */ protected function setupIsPrime() { $length = $this->getLengthInBytes(); // see HAC 4.49 "Note (controlling the error probability)" // @codingStandardsIgnoreStart if ($length >= 163) { $t = 2; } // floor(1300 / 8) else if ($length >= 106) { $t = 3; } // floor( 850 / 8) else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8) else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8) else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8) else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8) else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8) else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8) else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8) else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8) else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8) else { $t = 27; } // @codingStandardsIgnoreEnd return $t; } /** * Tests Primality * * Uses the {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24} for more info. * * @param int $t * @return bool */ protected function testPrimality($t) { if (!$this->testSmallPrimes()) { return false; } $n = clone $this; $n_1 = $n->subtract(static::$one); $n_2 = $n->subtract(static::$two); $r = clone $n_1; $s = static::scan1divide($r); for ($i = 0; $i < $t; ++$i) { $a = static::randomRange(static::$two, $n_2); $y = $a->modPow($r, $n); if (!$y->equals(static::$one) && !$y->equals($n_1)) { for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { $y = $y->modPow(static::$two, $n); if ($y->equals(static::$one)) { return false; } } if (!$y->equals($n_1)) { return false; } } } return true; } /** * Checks a numer to see if it's prime * * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the * $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads * on a website instead of just one. * * @param int|bool $t * @return bool */ public function isPrime($t = false) { if (!$t) { $t = $this->setupIsPrime(); } return $this->testPrimality($t); } /** * Performs a few preliminary checks on root * * @param int $n * @return \phpseclib\Math\BigInteger\Engines\Engine */ protected function rootHelper($n) { if ($n < 1) { return clone static::$zero; } // we want positive exponents if ($this->compare(static::$one) < 0) { return clone static::$zero; } // we want positive numbers if ($this->compare(static::$two) < 0) { return clone static::$one; } // n-th root of 1 or 2 is 1 return $this->rootInner($n); } /** * Calculates the nth root of a biginteger. * * Returns the nth root of a positive biginteger, where n defaults to 2 * * @param int $n * @return \phpseclib\Math\BigInteger\Engines\Engine * @internal This function is based off of {@link http://mathforum.org/library/drmath/view/52605.html this page} and {@link http://stackoverflow.com/questions/11242920/calculating-nth-root-with-bcmath-in-php this stackoverflow question}. */ protected function rootInner($n) { $n = new static($n); // g is our guess number $g = static::$two; // while (g^n < num) g=g*2 while ($g->pow($n)->compare($this) < 0) { $g = $g->multiply(static::$two); } // if (g^n==num) num is a power of 2, we're lucky, end of job // == 0 bccomp(bcpow($g, $n), $n->value)==0 if ($g->pow($n)->equals($this) > 0) { $root = $g; return $this->normalize($root); } // if we're here num wasn't a power of 2 :( $og = $g; // og means original guess and here is our upper bound $g = $g->divide(static::$two)[0]; // g is set to be our lower bound $step = $og->subtract($g)->divide(static::$two)[0]; // step is the half of upper bound - lower bound $g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval // while step>1 while ($step->compare(static::$one) == 1) { $guess = $g->pow($n); $step = $step->divide(static::$two)[0]; $comp = $guess->compare($this); // compare our guess with real number switch ($comp) { case -1: // if guess is lower we add the new step $g = $g->add($step); break; case 1: // if guess is higher we sub the new step $g = $g->subtract($step); break; case 0: // if guess is exactly the num we're done, we return the value $root = $g; break 2; } } if ($comp == 1) { $g = $g->subtract($step); } // whatever happened, g is the closest guess we can make so return it $root = $g; return $this->normalize($root); } /** * Calculates the nth root of a biginteger. * * @param int $n * @return Engine */ public function root($n = 2) { return $this->rootHelper($n); } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param array $nums * @return Engine */ protected static function minHelper(array $nums) { if (count($nums) == 1) { return $nums[0]; } $min = $nums[0]; for ($i = 1; $i < count($nums); $i++) { $min = $min->compare($nums[$i]) > 0 ? $nums[$i] : $min; } return $min; } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param array $nums * @return Engine */ protected static function maxHelper(array $nums) { if (count($nums) == 1) { return $nums[0]; } $max = $nums[0]; for ($i = 1; $i < count($nums); $i++) { $max = $max->compare($nums[$i]) < 0 ? $nums[$i] : $max; } return $max; } /** * Create Recurring Modulo Function * * Sometimes it may be desirable to do repeated modulos with the same number outside of * modular exponentiation * * @return callable */ public function createRecurringModuloFunction() { $class = static::class; $fqengine = !method_exists(static::$modexpEngine, 'reduce') ? '\\phpseclib\\Math\\BigInteger\\Engines\\' . static::ENGINE_DIR . '\\DefaultEngine' : static::$modexpEngine; if (method_exists($fqengine, 'generateCustomReduction')) { $func = $fqengine::generateCustomReduction($this, static::class); $this->reduce = eval('return function(' . static::class . ' $x) use ($func, $class) { $r = new $class(); $r->value = $func($x->value); return $r; };'); return clone $this->reduce; } $n = $this->value; $this->reduce = eval('return function(' . static::class . ' $x) use ($n, $fqengine, $class) { $r = new $class(); $r->value = $fqengine::reduce($x->value, $n, $class); return $r; };'); return clone $this->reduce; } /** * Calculates the greatest common divisor and Bezout's identity. * * @param Engine $n * @return Engine */ protected function extendedGCDHelper(Engine $n, Engine $stop = null) { $u = clone $this; $v = clone $n; $one = new static(1); $zero = new static(); $a = clone $one; $b = clone $zero; $c = clone $zero; $d = clone $one; while (!$v->equals($zero)) { list($q) = $u->divide($v); $temp = $u; $u = $v; $v = $temp->subtract($v->multiply($q)); $temp = $a; $a = $c; $c = $temp->subtract($a->multiply($q)); $temp = $b; $b = $d; $d = $temp->subtract($b->multiply($q)); } return [ 'gcd'=> $u, 'x' => $a, 'y' => $b ]; } /** * Bitwise Split * * Splits BigInteger's into chunks of $split bits * * @param int $split * @return \phpseclib\Math\BigInteger\Engine[] */ public function bitwise_split($split) { if ($split < 1) { throw new \RuntimeException('Offset must be greater than 1'); } $mask = static::$one->bitwise_leftShift($split)->subtract(static::$one); $num = clone $this; $vals = []; while (!$num->equals(static::$zero)) { $vals[] = $num->bitwise_and($mask); $num = $num->bitwise_rightShift($split); } return array_reverse($vals); } /** * Logical And * * @param Engine $x * @return Engine */ protected function bitwiseAndHelper(Engine $x) { $left = $this->toBytes(true); $right = $x->toBytes(true); $length = max(strlen($left), strlen($right)); $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); return $this->normalize(new static($left & $right, -256)); } /** * Logical Or * * @param Engine $x * @return Engine */ protected function bitwiseOrHelper(Engine $x) { $left = $this->toBytes(true); $right = $x->toBytes(true); $length = max(strlen($left), strlen($right)); $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); return $this->normalize(new static($left | $right, -256)); } /** * Logical Exclusive Or * * @param Engine $x * @return Engine */ protected function bitwiseXorHelper(Engine $x) { $left = $this->toBytes(true); $right = $x->toBytes(true); $length = max(strlen($left), strlen($right)); $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); return $this->normalize(new static($left ^ $right, -256)); } } <?php /** * Pure-PHP 64-bit BigInteger Engine * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://pear.php.net/package/Math_BigInteger */ namespace phpseclib\Math\BigInteger\Engines; use ParagonIE\ConstantTime\Hex; /** * Pure-PHP 64-bit Engine. * * Uses 64-bit integers if int size is 8 bits * * @package PHP * @author Jim Wigginton <terrafrost@php.net> * @access public */ class PHP64 extends PHP { /**#@+ * Constants used by PHP.php */ const BASE = 31; const BASE_FULL = 0x80000000; const MAX_DIGIT = 0x7FFFFFFF; const MSB = 0x40000000; /** * MAX10 in greatest MAX10LEN satisfying * MAX10 = 10**MAX10LEN <= 2**BASE. */ const MAX10 = 1000000000; /** * MAX10LEN in greatest MAX10LEN satisfying * MAX10 = 10**MAX10LEN <= 2**BASE. */ const MAX10LEN = 9; const MAX_DIGIT2 = 4611686018427387904; /**#@-*/ /** * Modular Exponentiation Engine * * @var string */ protected static $modexpEngine; /** * Engine Validity Flag * * @var bool */ protected static $isValidEngine; /** * Primes > 2 and < 1000 * * @var array */ protected static $primes; /** * BigInteger(0) * * @var \phpseclib\Math\BigInteger\Engines\PHP64 */ protected static $zero; /** * BigInteger(1) * * @var \phpseclib\Math\BigInteger\Engines\PHP64 */ protected static $one; /** * BigInteger(2) * * @var \phpseclib\Math\BigInteger\Engines\PHP64 */ protected static $two; /** * Initialize a PHP64 BigInteger Engine instance * * @param int $base * @see parent::initialize() */ protected function initialize($base) { if ($base != 256 && $base != -256) { return parent::initialize($base); } $val = $this->value; $this->value = []; $vals = &$this->value; $i = strlen($val); if (!$i) { return; } while (true) { $i-= 4; if ($i < 0) { if ($i == -4) { break; } $val = substr($val, 0, 4 + $i); $val = str_pad($val, 4, "\0", STR_PAD_LEFT); if ($val == "\0\0\0\0") { break; } $i = 0; } list(, $digit) = unpack('N', substr($val, $i, 4)); $step = count($vals) & 7; if (!$step) { $digit&= static::MAX_DIGIT; $i++; } else { $shift = 8 - $step; $digit>>= $shift; $shift = 32 - $shift; $digit&= (1 << $shift) - 1; $temp = $i > 0 ? ord($val[$i - 1]) : 0; $digit|= ($temp << $shift) & 0x7F000000; } $vals[] = $digit; } while (end($vals) === 0) { array_pop($vals); } reset($vals); } /** * Test for engine validity * * @see parent::__construct() * @return bool */ public static function isValidEngine() { return PHP_INT_SIZE >= 8; } /** * Adds two BigIntegers. * * @param PHP64 $y * @return PHP64 */ public function add(PHP64 $y) { $temp = self::addHelper($this->value, $this->is_negative, $y->value, $y->is_negative); return $this->convertToObj($temp); } /** * Subtracts two BigIntegers. * * @param PHP64 $y * @return PHP64 */ public function subtract(PHP64 $y) { $temp = self::subtractHelper($this->value, $this->is_negative, $y->value, $y->is_negative); return $this->convertToObj($temp); } /** * Multiplies two BigIntegers. * * @param PHP64 $y * @return PHP64 */ public function multiply(PHP64 $y) { $temp = self::multiplyHelper($this->value, $this->is_negative, $y->value, $y->is_negative); return $this->convertToObj($temp); } /** * Divides two BigIntegers. * * Returns an array whose first element contains the quotient and whose second element contains the * "common residue". If the remainder would be positive, the "common residue" and the remainder are the * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder * and the divisor (basically, the "common residue" is the first positive modulo). * * @param PHP64 $y * @return PHP64 */ public function divide(PHP64 $y) { return $this->divideHelper($y); } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * @param PHP64 $n * @return false|PHP64 */ public function modInverse(PHP64 $n) { return $this->modInverseHelper($n); } /** * Calculates modular inverses. * * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. * @param PHP64 $n * @return PHP64[] */ public function extendedGCD(PHP64 $n) { return $this->extendedGCDHelper($n); } /** * Calculates the greatest common divisor * * Say you have 693 and 609. The GCD is 21. * * @param PHP64 $n * @return PHP64 */ public function gcd(PHP64 $n) { return $this->extendedGCD($n)['gcd']; } /** * Logical And * * @param PHP64 $x * @return PHP64 */ public function bitwise_and(PHP64 $x) { return $this->bitwiseAndHelper($x); } /** * Logical Or * * @param PHP64 $x * @return PHP64 */ public function bitwise_or(PHP64 $x) { return $this->bitwiseOrHelper($x); } /** * Logical Exclusive Or * * @param PHP64 $x * @return PHP64 */ public function bitwise_xor(PHP64 $x) { return $this->bitwiseXorHelper($x); } /** * Compares two numbers. * * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is * demonstrated thusly: * * $x > $y: $x->compare($y) > 0 * $x < $y: $x->compare($y) < 0 * $x == $y: $x->compare($y) == 0 * * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). * * @param PHP64 $y * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal. * @access public * @see self::equals() * @internal Could return $this->subtract($x), but that's not as fast as what we do do. */ public function compare(PHP64 $y) { return parent::compareHelper($this->value, $this->is_negative, $y->value, $y->is_negative); } /** * Tests the equality of two numbers. * * If you need to see if one number is greater than or less than another number, use BigInteger::compare() * * @param PHP64 $x * @return bool */ public function equals(PHP64 $x) { return $this->value === $x->value && $this->is_negative == $x->is_negative; } /** * Performs modular exponentiation. * * @param PHP64 $e * @param PHP64 $n * @return PHP64 */ public function modPow(PHP64 $e, PHP64 $n) { return $this->powModOuter($e, $n); } /** * Performs modular exponentiation. * * Alias for modPow(). * * @param PHP64 $e * @param PHP64 $n * @return PHP64 */ public function powMod(PHP64 $e, PHP64 $n) { return $this->powModOuter($e, $n); } /** * Generate a random prime number between a range * * If there's not a prime within the given range, false will be returned. * * @param PHP64 $min * @param PHP64 $max * @return false|PHP64 */ public static function randomRangePrime(PHP64 $min, PHP64 $max) { return self::randomRangePrimeOuter($min, $max); } /** * Generate a random number between a range * * Returns a random number between $min and $max where $min and $max * can be defined using one of the two methods: * * BigInteger::randomRange($min, $max) * BigInteger::randomRange($max, $min) * * @param PHP64 $min * @param PHP64 $max * @return PHP64 */ public static function randomRange(PHP64 $min, PHP64 $max) { return self::randomRangeHelper($min, $max); } /** * Performs exponentiation. * * @param PHP64 $n * @return PHP64 */ public function pow(PHP64 $n) { return $this->powHelper($n); } /** * Return the minimum BigInteger between an arbitrary number of BigIntegers. * * @param PHP64[] $nums * @return PHP64 */ public static function min(...$nums) { return self::minHelper($nums); } /** * Return the maximum BigInteger between an arbitrary number of BigIntegers. * * @param PHP64[] $nums * @return PHP64 */ public static function max(...$nums) { return self::maxHelper($nums); } /** * Tests BigInteger to see if it is between two integers, inclusive * * @param PHP64 $min * @param PHP64 $max * @return bool */ public function between(PHP64 $min, PHP64 $max) { return $this->compare($min) >= 0 && $this->compare($max) <= 0; } }<?php /** * Prime Finite Fields * * PHP version 5 and 7 * * @category Math * @package BigInteger * @author Jim Wigginton <terrafrost@php.net> * @copyright 2017 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License */ namespace phpseclib\Math\PrimeField; use phpseclib\Math\Common\FiniteField\Integer as Base; use phpseclib\Math\BigInteger; use ParagonIE\ConstantTime\Hex; /** * Prime Finite Fields * * @package Math * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Integer extends Base { /** * Holds the PrimeField's value * * @var \phpseclib\Math\BigInteger */ protected $value; /** * Keeps track of current instance * * @var int */ protected $instanceID; /** * Holds the PrimeField's modulo * * @var \phpseclib\Math\BigInteger */ protected static $modulo; /** * Holds a pre-generated function to perform modulo reductions * * @var Callable */ protected static $reduce; /** * Zero * * @var \phpseclib\Math\BigInteger */ protected static $zero; /** * Default constructor */ public function __construct($instanceID, BigInteger $num = null) { $this->instanceID = $instanceID; if (!isset($num)) { $this->value = clone static::$zero; } else { $reduce = static::$reduce[$instanceID]; $this->value = $reduce($num); } } /** * Set the modulo for a given instance */ public static function setModulo($instanceID, BigInteger $modulo) { static::$modulo[$instanceID] = $modulo; } /** * Set the modulo for a given instance */ public static function setRecurringModuloFunction($instanceID, callable $function) { static::$reduce[$instanceID] = $function; if (!isset(static::$zero)) { static::$zero = new BigInteger(); } } /** * Returns the modulo * * @return integer */ public static function getModulo($instanceID) { return static::$modulo[$instanceID]; } /** * Tests a parameter to see if it's of the right instance * * Throws an exception if the incorrect class is being utilized */ public static function checkInstance(self $x, self $y) { if ($x->instanceID != $y->instanceID) { throw new \UnexpectedValueException('The instances of the two PrimeField\Integer objects do not match'); } } /** * Tests the equality of two numbers. * * @return bool */ public function equals(self $x) { static::checkInstance($this, $x); return $this->value->equals($x->value); } /** * Compares two numbers. * * @return int */ public function compare(self $x) { static::checkInstance($this, $x); return $this->value->compare($x->value); } /** * Adds two PrimeFieldIntegers. * * @return static */ public function add(self $x) { static::checkInstance($this, $x); $temp = new static($this->instanceID); $temp->value = $this->value->add($x->value); if ($temp->value->compare(static::$modulo[$this->instanceID]) >= 0) { $temp->value = $temp->value->subtract(static::$modulo[$this->instanceID]); } return $temp; } /** * Subtracts two PrimeFieldIntegers. * * @return static */ public function subtract(self $x) { static::checkInstance($this, $x); $temp = new static($this->instanceID); $temp->value = $this->value->subtract($x->value); if ($temp->value->isNegative()) { $temp->value = $temp->value->add(static::$modulo[$this->instanceID]); } return $temp; } /** * Multiplies two PrimeFieldIntegers. * * @return static */ public function multiply(self $x) { static::checkInstance($this, $x); return new static($this->instanceID, $this->value->multiply($x->value)); } /** * Divides two PrimeFieldIntegers. * * @return static */ public function divide(self $x) { static::checkInstance($this, $x); $denominator = $x->value->modInverse(static::$modulo[$this->instanceID]); return new static($this->instanceID, $this->value->multiply($denominator)); } /** * Performs power operation on a PrimeFieldInteger. * * @return static */ public function pow(BigInteger $x) { $temp = new static($this->instanceID); $temp->value = $this->value->powMod($x, static::$modulo[$this->instanceID]); return $temp; } /** * Calculates the square root * * @link https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm * @return static|false */ public function squareRoot() { static $one, $two; if (!isset($one)) { $one = new BigInteger(1); $two = new BigInteger(2); } $reduce = static::$reduce[$this->instanceID]; $p_1 = static::$modulo[$this->instanceID]->subtract($one); $q = clone $p_1; $s = BigInteger::scan1divide($q); list($pow) = $p_1->divide($two); for ($z = $one; !$z->equals(static::$modulo[$this->instanceID]); $z = $z->add($one)) { $temp = $z->powMod($pow, static::$modulo[$this->instanceID]); if ($temp->equals($p_1)) { break; } } $m = new BigInteger($s); $c = $z->powMod($q, static::$modulo[$this->instanceID]); $t = $this->value->powMod($q, static::$modulo[$this->instanceID]); list($temp) = $q->add($one)->divide($two); $r = $this->value->powMod($temp, static::$modulo[$this->instanceID]); while (!$t->equals($one)) { $i = clone $one; while (!$t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) { $i = $i->add($one); } if ($i->compare($m) >= 0) { return false; } $b = $c->powMod($two->pow($m->subtract($i)->subtract($one)), static::$modulo[$this->instanceID]); $m = $i; $c = $reduce($b->multiply($b)); $t = $reduce($t->multiply($c)); $r = $reduce($r->multiply($b)); } return new static($this->instanceID, $r); } /** * Is Odd? * * @return boolean */ public function isOdd() { return $this->value->isOdd(); } /** * Negate * * A negative number can be written as 0-12. With modulos, 0 is the same thing as the modulo * so 0-12 is the same thing as modulo-12 * * @return object */ public function negate() { return new static($this->instanceID, static::$modulo[$this->instanceID]->subtract($this->value)); } /** * Converts an Integer to a byte string (eg. base-256). * * @return string */ public function toBytes() { $length = static::$modulo[$this->instanceID]->getLengthInBytes(); return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT); } /** * Converts an Integer to a hex string (eg. base-16). * * @return string */ public function toHex() { return Hex::encode($this->toBytes()); } /** * Converts an Integer to a bit string (eg. base-2). * * @return string */ public function toBits() { // return $this->value->toBits(); static $length; if (!isset($length)) { $length = static::$modulo[$this->instanceID]->getLength(); } return str_pad($this->value->toBits(), $length, '0', STR_PAD_LEFT); } /** * Returns the w-ary non-adjacent form (wNAF) * * @param int $w optional * @return int[] */ public function getNAF($w = 1) { $w++; $mask = new BigInteger((1 << $w) - 1); $sub = new BigInteger(1 << $w); //$sub = new BigInteger(1 << ($w - 1)); $d = $this->toBigInteger(); $d_i = []; $i = 0; while ($d->compare(static::$zero) > 0) { if ($d->isOdd()) { // start mods $d_i[$i] = $d->testBit($w - 1) ? $d->bitwise_and($mask)->subtract($sub) : //$sub->subtract($d->bitwise_and($mask)) : $d->bitwise_and($mask); // end mods $d = $d->subtract($d_i[$i]); $d_i[$i] = (int) $d_i[$i]->toString(); } else { $d_i[$i] = 0; } $shift = !$d->equals(static::$zero) && $d->bitwise_and($mask)->equals(static::$zero) ? $w : 1; // $w or $w + 1? $d = $d->bitwise_rightShift($shift); while (--$shift > 0) { $d_i[++$i] = 0; } $i++; } return $d_i; } /** * Converts an Integer to a BigInteger * * @return string */ public function toBigInteger() { return clone $this->value; } /** * __toString() magic method * * @access public */ public function __toString() { return (string) $this->value; } /** * __debugInfo() magic method * * @access public */ public function __debugInfo() { return ['value' => $this->toHex()]; } }<?php /** * Common String Functions * * PHP version 5 * * @category Common * @package Functions\Strings * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Common\Functions; use phpseclib\Math\BigInteger; use phpseclib\Math\Common\FiniteField; /** * Common String Functions * * @package Functions\Strings * @author Jim Wigginton <terrafrost@php.net> */ abstract class Strings { /** * String Shift * * Inspired by array_shift * * @param string $string * @param int $index * @access public * @return string */ public static function shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } /** * String Pop * * Inspired by array_pop * * @param string $string * @param int $index * @access public * @return string */ public static function pop(&$string, $index = 1) { $substr = substr($string, -$index); $string = substr($string, 0, -$index); return $substr; } /** * Parse SSH2-style string * * Returns either an array or a boolean if $data is malformed. * * Valid characters for $format are as follows: * * C = byte * b = boolean (true/false) * N = uint32 * s = string * i = mpint * L = name-list * * uint64 is not supported. * * @param string $format * @param $data * @return mixed */ public static function unpackSSH2($format, &$data) { $format = self::formatPack($format); $result = []; for ($i = 0; $i < strlen($format); $i++) { switch ($format[$i]) { case 'C': case 'b': if (!strlen($data)) { throw new \LengthException('At least one byte needs to be present for successful C / b decodes'); } break; case 'N': case 'i': case 's': case 'L': if (strlen($data) < 4) { throw new \LengthException('At least four byte needs to be present for successful N / i / s / L decodes'); } break; default: throw new \InvalidArgumentException('$format contains an invalid character'); } switch ($format[$i]) { case 'C': $result[] = ord(self::shift($data)); continue 2; case 'b': $result[] = ord(self::shift($data)) != 0; continue 2; case 'N': list(, $temp) = unpack('N', self::shift($data, 4)); $result[] = $temp; continue 2; } list(, $length) = unpack('N', self::shift($data, 4)); if (strlen($data) < $length) { throw new \LengthException("$length bytes needed; " . strlen($data) . ' bytes available'); } $temp = self::shift($data, $length); switch ($format[$i]) { case 'i': $result[] = new BigInteger($temp, -256); break; case 's': $result[] = $temp; break; case 'L': $result[] = explode(',', $temp); } } return $result; } /** * Create SSH2-style string * * @param $elements[] * @access public * @return mixed */ public static function packSSH2(...$elements) { $format = self::formatPack($elements[0]); array_shift($elements); if (strlen($format) != count($elements)) { throw new \InvalidArgumentException('There must be as many arguments as there are characters in the $format string'); } $result = ''; for ($i = 0; $i < strlen($format); $i++) { $element = $elements[$i]; switch ($format[$i]) { case 'C': if (!is_int($element)) { throw new \InvalidArgumentException('Bytes must be represented as an integer between 0 and 255, inclusive.'); } $result.= pack('C', $element); break; case 'b': if (!is_bool($element)) { throw new \InvalidArgumentException('A boolean parameter was expected.'); } $result.= $element ? "\1" : "\0"; break; case 'N': if (is_float($element)) { $element = (int) $element; } if (!is_int($element)) { throw new \InvalidArgumentException('An integer was expected.'); } $result.= pack('N', $element); break; case 's': if (!is_string($element)) { throw new \InvalidArgumentException('A string was expected.'); } $result.= pack('Na*', strlen($element), $element); break; case 'i': if (!$element instanceof BigInteger && !$element instanceof FiniteField\Integer) { throw new \InvalidArgumentException('A phpseclib\Math\BigInteger or phpseclib\Math\Common\FiniteField\Integer object was expected.'); } $element = $element->toBytes(true); $result.= pack('Na*', strlen($element), $element); break; case 'L': if (!is_array($element)) { throw new \InvalidArgumentException('An array was expected.'); } $element = implode(',', $element); $result.= pack('Na*', strlen($element), $element); break; default: throw new \InvalidArgumentException('$format contains an invalid character'); } } return $result; } /** * Expand a pack string * * Converts C5 to CCCCC, for example. * * @access private * @param string $format * @return string */ private static function formatPack($format) { $parts = preg_split('#(\d+)#', $format, -1, PREG_SPLIT_DELIM_CAPTURE); $format = ''; for ($i = 1; $i < count($parts); $i+=2) { $format.= substr($parts[$i - 1], 0, -1) . str_repeat(substr($parts[$i - 1], -1), $parts[$i]); } $format.= $parts[$i - 1]; return $format; } /** * Convert binary data into bits * * bin2hex / hex2bin refer to base-256 encoded data as binary, whilst * decbin / bindec refer to base-2 encoded data as binary. For the purposes * of this function, bin refers to base-256 encoded data whilst bits refers * to base-2 encoded data * * @access public * @param string $x * @return string */ public static function bits2bin($x) { /* // the pure-PHP approach is faster than the GMP approach if (function_exists('gmp_export')) { return strlen($x) ? gmp_export(gmp_init($x, 2)) : gmp_init(0); } */ if (preg_match('#[^01]#', $x)) { throw new \RuntimeException('The only valid characters are 0 and 1'); } if (!defined('PHP_INT_MIN')) { define('PHP_INT_MIN', ~PHP_INT_MAX); } $length = strlen($x); if (!$length) { return ''; } $block_size = PHP_INT_SIZE << 3; $pad = $block_size - ($length % $block_size); if ($pad != $block_size) { $x = str_repeat('0', $pad) . $x; } $parts = str_split($x, $block_size); $str = ''; foreach ($parts as $part) { $xor = $part[0] == '1' ? PHP_INT_MIN : 0; $part[0] = '0'; $str.= pack( PHP_INT_SIZE == 4 ? 'N' : 'J', $xor ^ eval('return 0b' . $part . ';') ); } return ltrim($str, "\0"); } /** * Convert bits to binary data * * @access public * @param string $x * @return string */ public static function bin2bits($x) { /* // the pure-PHP approach is slower than the GMP approach BUT // i want to the pure-PHP version to be easily unit tested as well if (function_exists('gmp_import')) { return gmp_strval(gmp_import($x), 2); } */ $len = strlen($x); $mod = $len % PHP_INT_SIZE; if ($mod) { $x = str_pad($x, $len + PHP_INT_SIZE - $mod, "\0", STR_PAD_LEFT); } $bits = ''; if (PHP_INT_SIZE == 4) { $digits = unpack('N*', $x); foreach ($digits as $digit) { $bits.= sprintf('%032b', $digit); } } else { $digits = unpack('J*', $x); foreach ($digits as $digit) { $bits.= sprintf('%064b', $digit); } } return ltrim($bits, '0'); } /** * Switch Endianness Bit Order * * @access public * @param string $x * @return string */ public static function switchEndianness($x) { $r = ''; // from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits for ($i = strlen($x) - 1; $i >= 0; $i--) { $b = ord($x[$i]); $p1 = ($b * 0x0802) & 0x22110; $p2 = ($b * 0x8020) & 0x88440; $r.= chr( (($p1 | $p2) * 0x10101) >> 16 ); } return $r; } /** * Increment the current string * * @param string $var * @return string * @access public */ public static function increment_str(&$var) { for ($i = 4; $i <= strlen($var); $i+= 4) { $temp = substr($var, -$i, 4); switch ($temp) { case "\xFF\xFF\xFF\xFF": $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4); break; case "\x7F\xFF\xFF\xFF": $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4); return $var; default: $temp = unpack('Nnum', $temp); $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4); return $var; } } $remainder = strlen($var) % 4; if ($remainder == 0) { return $var; } $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT)); $temp = substr(pack('N', $temp['num'] + 1), -$remainder); $var = substr_replace($var, $temp, 0, $remainder); return $var; } } <?php /** * Bootstrapping File for phpseclib * * composer isn't a requirement for phpseclib 2.0 but this file isn't really required * either. it's a bonus for those using composer but if you're not phpseclib will * still work * * @license http://www.opensource.org/licenses/mit-license.html MIT License */ if (extension_loaded('mbstring')) { // 2 - MB_OVERLOAD_STRING if (ini_get('mbstring.func_overload') & 2) { throw new UnexpectedValueException( 'Overloading of string functions using mbstring.func_overload ' . 'is not supported by phpseclib.' ); } } <?php /** * Pure-PHP X.509 Parser * * PHP version 5 * * Encode and decode X.509 certificates. * * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}. * * Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a * portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is * used. Problem is, if the parameter is there and it just so happens to have the default value there are two ways that that parameter can * be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the * the certificate all together unless the certificate is re-signed. * * @category File * @package X509 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File; use ParagonIE\ConstantTime\Base64; use ParagonIE\ConstantTime\Hex; use phpseclib\Crypt\Hash; use phpseclib\Crypt\Random; use phpseclib\Crypt\RSA; use phpseclib\Crypt\DSA; use phpseclib\Crypt\ECDSA; use phpseclib\Crypt\Common\PublicKey; use phpseclib\Crypt\Common\PrivateKey; use phpseclib\Exception\UnsupportedAlgorithmException; use phpseclib\File\ASN1\Element; use phpseclib\Math\BigInteger; use phpseclib\File\ASN1\Maps; use DateTime; use DateTimeZone; /** * Pure-PHP X.509 Parser * * @package X509 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class X509 { /** * Flag to only accept signatures signed by certificate authorities * * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs * * @access public */ const VALIDATE_SIGNATURE_BY_CA = 1; /**#@+ * @access public * @see \phpseclib\File\X509::getDN() */ /** * Return internal array representation */ const DN_ARRAY = 0; /** * Return string */ const DN_STRING = 1; /** * Return ASN.1 name string */ const DN_ASN1 = 2; /** * Return OpenSSL compatible array */ const DN_OPENSSL = 3; /** * Return canonical ASN.1 RDNs string */ const DN_CANON = 4; /** * Return name hash for file indexing */ const DN_HASH = 5; /**#@-*/ /**#@+ * @access public * @see \phpseclib\File\X509::saveX509() * @see \phpseclib\File\X509::saveCSR() * @see \phpseclib\File\X509::saveCRL() */ /** * Save as PEM * * ie. a base64-encoded PEM with a header and a footer */ const FORMAT_PEM = 0; /** * Save as DER */ const FORMAT_DER = 1; /** * Save as a SPKAC * * Only works on CSRs. Not currently supported. */ const FORMAT_SPKAC = 2; /** * Auto-detect the format * * Used only by the load*() functions */ const FORMAT_AUTO_DETECT = 3; /**#@-*/ /** * Attribute value disposition. * If disposition is >= 0, this is the index of the target value. */ const ATTR_ALL = -1; // All attribute values (array). const ATTR_APPEND = -2; // Add a value. const ATTR_REPLACE = -3; // Clear first, then add a value. /** * Distinguished Name * * @var array * @access private */ private $dn; /** * Public key * * @var string * @access private */ private $publicKey; /** * Private key * * @var string * @access private */ private $privateKey; /** * Object identifiers for X.509 certificates * * @var array * @access private * @link http://en.wikipedia.org/wiki/Object_identifier */ private $oids; /** * The certificate authorities * * @var array * @access private */ private $CAs; /** * The currently loaded certificate * * @var array * @access private */ private $currentCert; /** * The signature subject * * There's no guarantee \phpseclib\File\X509 is going to re-encode an X.509 cert in the same way it was originally * encoded so we take save the portion of the original cert that the signature would have made for. * * @var string * @access private */ private $signatureSubject; /** * Certificate Start Date * * @var string * @access private */ private $startDate; /** * Certificate End Date * * @var string * @access private */ private $endDate; /** * Serial Number * * @var string * @access private */ private $serialNumber; /** * Key Identifier * * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}. * * @var string * @access private */ private $currentKeyIdentifier; /** * CA Flag * * @var bool * @access private */ private $caFlag = false; /** * SPKAC Challenge * * @var string * @access private */ private $challenge; /** * OIDs loaded * * @var bool * @access private */ private static $oidsLoaded = false; /** * Recursion Limit * * @var int * @access private */ private static $recur_limit = 5; /** * URL fetch flag * * @var bool * @access private */ private static $disable_url_fetch = false; /** * Default Constructor. * * @return \phpseclib\File\X509 * @access public */ public function __construct() { // Explicitly Tagged Module, 1988 Syntax // http://tools.ietf.org/html/rfc5280#appendix-A.1 if (!self::$oidsLoaded) { // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2 ASN1::loadOIDs([ //'id-pkix' => '1.3.6.1.5.5.7', //'id-pe' => '1.3.6.1.5.5.7.1', //'id-qt' => '1.3.6.1.5.5.7.2', //'id-kp' => '1.3.6.1.5.5.7.3', //'id-ad' => '1.3.6.1.5.5.7.48', 'id-qt-cps' => '1.3.6.1.5.5.7.2.1', 'id-qt-unotice' => '1.3.6.1.5.5.7.2.2', 'id-ad-ocsp' =>'1.3.6.1.5.5.7.48.1', 'id-ad-caIssuers' => '1.3.6.1.5.5.7.48.2', 'id-ad-timeStamping' => '1.3.6.1.5.5.7.48.3', 'id-ad-caRepository' => '1.3.6.1.5.5.7.48.5', //'id-at' => '2.5.4', 'id-at-name' => '2.5.4.41', 'id-at-surname' => '2.5.4.4', 'id-at-givenName' => '2.5.4.42', 'id-at-initials' => '2.5.4.43', 'id-at-generationQualifier' => '2.5.4.44', 'id-at-commonName' => '2.5.4.3', 'id-at-localityName' => '2.5.4.7', 'id-at-stateOrProvinceName' => '2.5.4.8', 'id-at-organizationName' => '2.5.4.10', 'id-at-organizationalUnitName' => '2.5.4.11', 'id-at-title' => '2.5.4.12', 'id-at-description' => '2.5.4.13', 'id-at-dnQualifier' => '2.5.4.46', 'id-at-countryName' => '2.5.4.6', 'id-at-serialNumber' => '2.5.4.5', 'id-at-pseudonym' => '2.5.4.65', 'id-at-postalCode' => '2.5.4.17', 'id-at-streetAddress' => '2.5.4.9', 'id-at-uniqueIdentifier' => '2.5.4.45', 'id-at-role' => '2.5.4.72', 'id-at-postalAddress' => '2.5.4.16', //'id-domainComponent' => '0.9.2342.19200300.100.1.25', //'pkcs-9' => '1.2.840.113549.1.9', 'pkcs-9-at-emailAddress' => '1.2.840.113549.1.9.1', //'id-ce' => '2.5.29', 'id-ce-authorityKeyIdentifier' => '2.5.29.35', 'id-ce-subjectKeyIdentifier' => '2.5.29.14', 'id-ce-keyUsage' => '2.5.29.15', 'id-ce-privateKeyUsagePeriod' => '2.5.29.16', 'id-ce-certificatePolicies' => '2.5.29.32', //'anyPolicy' => '2.5.29.32.0', 'id-ce-policyMappings' => '2.5.29.33', 'id-ce-subjectAltName' => '2.5.29.17', 'id-ce-issuerAltName' => '2.5.29.18', 'id-ce-subjectDirectoryAttributes' => '2.5.29.9', 'id-ce-basicConstraints' => '2.5.29.19', 'id-ce-nameConstraints' => '2.5.29.30', 'id-ce-policyConstraints' => '2.5.29.36', 'id-ce-cRLDistributionPoints' => '2.5.29.31', 'id-ce-extKeyUsage' => '2.5.29.37', //'anyExtendedKeyUsage' => '2.5.29.37.0', 'id-kp-serverAuth' => '1.3.6.1.5.5.7.3.1', 'id-kp-clientAuth' => '1.3.6.1.5.5.7.3.2', 'id-kp-codeSigning' => '1.3.6.1.5.5.7.3.3', 'id-kp-emailProtection' => '1.3.6.1.5.5.7.3.4', 'id-kp-timeStamping' => '1.3.6.1.5.5.7.3.8', 'id-kp-OCSPSigning' => '1.3.6.1.5.5.7.3.9', 'id-ce-inhibitAnyPolicy' => '2.5.29.54', 'id-ce-freshestCRL' => '2.5.29.46', 'id-pe-authorityInfoAccess' => '1.3.6.1.5.5.7.1.1', 'id-pe-subjectInfoAccess' => '1.3.6.1.5.5.7.1.11', 'id-ce-cRLNumber' => '2.5.29.20', 'id-ce-issuingDistributionPoint' => '2.5.29.28', 'id-ce-deltaCRLIndicator' => '2.5.29.27', 'id-ce-cRLReasons' => '2.5.29.21', 'id-ce-certificateIssuer' => '2.5.29.29', 'id-ce-holdInstructionCode' => '2.5.29.23', //'holdInstruction' => '1.2.840.10040.2', 'id-holdinstruction-none' => '1.2.840.10040.2.1', 'id-holdinstruction-callissuer' => '1.2.840.10040.2.2', 'id-holdinstruction-reject' => '1.2.840.10040.2.3', 'id-ce-invalidityDate' => '2.5.29.24', 'rsaEncryption' => '1.2.840.113549.1.1.1', 'md2WithRSAEncryption' => '1.2.840.113549.1.1.2', 'md5WithRSAEncryption' => '1.2.840.113549.1.1.4', 'sha1WithRSAEncryption' => '1.2.840.113549.1.1.5', 'sha224WithRSAEncryption' => '1.2.840.113549.1.1.14', 'sha256WithRSAEncryption' => '1.2.840.113549.1.1.11', 'sha384WithRSAEncryption' => '1.2.840.113549.1.1.12', 'sha512WithRSAEncryption' => '1.2.840.113549.1.1.13', 'id-ecPublicKey' => '1.2.840.10045.2.1', 'ecdsa-with-SHA1' => '1.2.840.10045.4.1', // from https://tools.ietf.org/html/rfc5758#section-3.2 'ecdsa-with-SHA224' => '1.2.840.10045.4.3.1', 'ecdsa-with-SHA256' => '1.2.840.10045.4.3.2', 'ecdsa-with-SHA384' => '1.2.840.10045.4.3.3', 'ecdsa-with-SHA512' => '1.2.840.10045.4.3.4', 'id-dsa' => '1.2.840.10040.4.1', 'id-dsa-with-sha1' => '1.2.840.10040.4.3', // from https://tools.ietf.org/html/rfc5758#section-3.1 'id-dsa-with-sha224' => '2.16.840.1.101.3.4.3.1', 'id-dsa-with-sha256' => '2.16.840.1.101.3.4.3.2', // from https://tools.ietf.org/html/rfc8410: 'id-Ed25519' => '1.3.101.112', 'id-Ed448' => '1.3.101.113', //'id-sha224' => '2.16.840.1.101.3.4.2.4', //'id-sha256' => '2.16.840.1.101.3.4.2.1', //'id-sha384' => '2.16.840.1.101.3.4.2.2', //'id-sha512' => '2.16.840.1.101.3.4.2.3', //'id-GostR3411-94-with-GostR3410-94' => '1.2.643.2.2.4', //'id-GostR3411-94-with-GostR3410-2001' => '1.2.643.2.2.3', //'id-GostR3410-2001' => '1.2.643.2.2.20', //'id-GostR3410-94' => '1.2.643.2.2.19', // Netscape Object Identifiers from "Netscape Certificate Extensions" 'netscape' => '2.16.840.1.113730', 'netscape-cert-extension' => '2.16.840.1.113730.1', 'netscape-cert-type' => '2.16.840.1.113730.1.1', 'netscape-comment' => '2.16.840.1.113730.1.13', 'netscape-ca-policy-url' => '2.16.840.1.113730.1.8', // the following are X.509 extensions not supported by phpseclib 'id-pe-logotype' => '1.3.6.1.5.5.7.1.12', 'entrustVersInfo' => '1.2.840.113533.7.65.0', 'verisignPrivate' => '2.16.840.1.113733.1.6.9', // for Certificate Signing Requests // see http://tools.ietf.org/html/rfc2985 'pkcs-9-at-unstructuredName' => '1.2.840.113549.1.9.2', // PKCS #9 unstructured name 'pkcs-9-at-challengePassword' => '1.2.840.113549.1.9.7', // Challenge password for certificate revocations 'pkcs-9-at-extensionRequest' => '1.2.840.113549.1.9.14' // Certificate extension request ]); } } /** * Load X.509 certificate * * Returns an associative array describing the X.509 cert or a false if the cert failed to load * * @param string $cert * @param int $mode * @access public * @return mixed */ public function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT) { if (is_array($cert) && isset($cert['tbsCertificate'])) { unset($this->currentCert); unset($this->currentKeyIdentifier); $this->dn = $cert['tbsCertificate']['subject']; if (!isset($this->dn)) { return false; } $this->currentCert = $cert; $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; unset($this->signatureSubject); return $cert; } if ($mode != self::FORMAT_DER) { $newcert = ASN1::extractBER($cert); if ($mode == self::FORMAT_PEM && $cert == $newcert) { return false; } $cert = $newcert; } if ($cert === false) { $this->currentCert = false; return false; } $decoded = ASN1::decodeBER($cert); if (!empty($decoded)) { $x509 = ASN1::asn1map($decoded[0], Maps\Certificate::MAP); } if (!isset($x509) || $x509 === false) { $this->currentCert = false; return false; } $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); if ($this->isSubArrayValid($x509, 'tbsCertificate/extensions')) { $this->mapInExtensions($x509, 'tbsCertificate/extensions'); } $this->mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence'); $this->mapInDNs($x509, 'tbsCertificate/subject/rdnSequence'); $key = $x509['tbsCertificate']['subjectPublicKeyInfo']; $key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP); $x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($key), 64) . "-----END PUBLIC KEY-----"; $this->currentCert = $x509; $this->dn = $x509['tbsCertificate']['subject']; $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; return $x509; } /** * Save X.509 certificate * * @param array $cert * @param int $format optional * @access public * @return string */ public function saveX509($cert, $format = self::FORMAT_PEM) { if (!is_array($cert) || !isset($cert['tbsCertificate'])) { return false; } switch (true) { // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()" case !($algorithm = $this->subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')): case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']): break; default: $cert['tbsCertificate']['subjectPublicKeyInfo'] = new Element( base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])) ); } if ($algorithm == 'rsaEncryption') { $cert['signatureAlgorithm']['parameters'] = null; $cert['tbsCertificate']['signature']['parameters'] = null; } $filters = []; $type_utf8_string = ['type' => ASN1::TYPE_UTF8_STRING]; $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string; $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string; $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string; $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string; $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string; $filters['signatureAlgorithm']['parameters'] = $type_utf8_string; $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string; //$filters['policyQualifiers']['qualifier'] = $type_utf8_string; $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string; $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string; /* in the case of policyQualifiers/qualifier, the type has to be \phpseclib\File\ASN1::TYPE_IA5_STRING. \phpseclib\File\ASN1::TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random characters. */ $filters['policyQualifiers']['qualifier'] = ['type' => ASN1::TYPE_IA5_STRING]; ASN1::setFilters($filters); $this->mapOutExtensions($cert, 'tbsCertificate/extensions'); $this->mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence'); $this->mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence'); $cert = ASN1::encodeDER($cert, Maps\Certificate::MAP); switch ($format) { case self::FORMAT_DER: return $cert; // case self::FORMAT_PEM: default: return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(Base64::encode($cert), 64) . '-----END CERTIFICATE-----'; } } /** * Map extension values from octet string to extension-specific internal * format. * * @param &array $root * @param string $path * @access private */ private function mapInExtensions(&$root, $path) { $extensions = &$this->subArrayUnchecked($root, $path); if ($extensions) { for ($i = 0; $i < count($extensions); $i++) { $id = $extensions[$i]['extnId']; $value = &$extensions[$i]['extnValue']; $decoded = ASN1::decodeBER($value); /* [extnValue] contains the DER encoding of an ASN.1 value corresponding to the extension type identified by extnID */ $map = $this->getMapping($id); if (!is_bool($map)) { $mapped = ASN1::asn1map($decoded[0], $map, ['iPAddress' => [$this, 'decodeIP']]); $value = $mapped === false ? $decoded[0] : $mapped; if ($id == 'id-ce-certificatePolicies') { for ($j = 0; $j < count($value); $j++) { if (!isset($value[$j]['policyQualifiers'])) { continue; } for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) { $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId']; $map = $this->getMapping($subid); $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier']; if ($map !== false) { $decoded = ASN1::decodeBER($subvalue); $mapped = ASN1::asn1map($decoded[0], $map); $subvalue = $mapped === false ? $decoded[0] : $mapped; } } } } } } } } /** * Map extension values from extension-specific internal format to * octet string. * * @param &array Ref $root * @param string $path * @access private */ private function mapOutExtensions(&$root, $path) { $extensions = &$this->subArray($root, $path); if (is_array($extensions)) { $size = count($extensions); for ($i = 0; $i < $size; $i++) { if ($extensions[$i] instanceof Element) { continue; } $id = $extensions[$i]['extnId']; $value = &$extensions[$i]['extnValue']; switch ($id) { case 'id-ce-certificatePolicies': for ($j = 0; $j < count($value); $j++) { if (!isset($value[$j]['policyQualifiers'])) { continue; } for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) { $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId']; $map = $this->getMapping($subid); $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier']; if ($map !== false) { // by default \phpseclib\File\ASN1 will try to render qualifier as a \phpseclib\File\ASN1::TYPE_IA5_STRING since it's // actual type is \phpseclib\File\ASN1::TYPE_ANY $subvalue = new Element(ASN1::encodeDER($subvalue, $map)); } } } break; case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string if (isset($value['authorityCertSerialNumber'])) { if ($value['authorityCertSerialNumber']->toBytes() == '') { $temp = chr((ASN1::CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0"; $value['authorityCertSerialNumber'] = new Element($temp); } } } /* [extnValue] contains the DER encoding of an ASN.1 value corresponding to the extension type identified by extnID */ $map = $this->getMapping($id); if (is_bool($map)) { if (!$map) { //user_error($id . ' is not a currently supported extension'); unset($extensions[$i]); } } else { $value = ASN1::encodeDER($value, $map, ['iPAddress' => [$this, 'encodeIP']]); } } } } /** * Map attribute values from ANY type to attribute-specific internal * format. * * @param &array Ref $root * @param string $path * @access private */ private function mapInAttributes(&$root, $path) { $attributes = &$this->subArray($root, $path); if (is_array($attributes)) { for ($i = 0; $i < count($attributes); $i++) { $id = $attributes[$i]['type']; /* $value contains the DER encoding of an ASN.1 value corresponding to the attribute type identified by type */ $map = $this->getMapping($id); if (is_array($attributes[$i]['value'])) { $values = &$attributes[$i]['value']; for ($j = 0; $j < count($values); $j++) { $value = ASN1::encodeDER($values[$j], Maps\AttributeValue::MAP); $decoded = ASN1::decodeBER($value); if (!is_bool($map)) { $mapped = ASN1::asn1map($decoded[0], $map); if ($mapped !== false) { $values[$j] = $mapped; } if ($id == 'pkcs-9-at-extensionRequest' && $this->isSubArrayValid($values, $j)) { $this->mapInExtensions($values, $j); } } elseif ($map) { $values[$j] = $value; } } } } } } /** * Map attribute values from attribute-specific internal format to * ANY type. * * @param &array $root Ref * @param string $path * @access private */ private function mapOutAttributes(&$root, $path) { $attributes = &$this->subArray($root, $path); if (is_array($attributes)) { $size = count($attributes); for ($i = 0; $i < $size; $i++) { /* [value] contains the DER encoding of an ASN.1 value corresponding to the attribute type identified by type */ $id = $attributes[$i]['type']; $map = $this->getMapping($id); if ($map === false) { //user_error($id . ' is not a currently supported attribute', E_USER_NOTICE); unset($attributes[$i]); } elseif (is_array($attributes[$i]['value'])) { $values = &$attributes[$i]['value']; for ($j = 0; $j < count($values); $j++) { switch ($id) { case 'pkcs-9-at-extensionRequest': $this->mapOutExtensions($values, $j); break; } if (!is_bool($map)) { $temp = ASN1::encodeDER($values[$j], $map); $decoded = ASN1::decodeBER($temp); $values[$j] = ASN1::asn1map($decoded[0], Maps\AttributeValue::MAP); } } } } } } /** * Map DN values from ANY type to DN-specific internal * format. * * @param &array $root * @param string $path * @access private */ private function mapInDNs(&$root, $path) { $dns = &$this->subArray($root, $path); if (is_array($dns)) { for ($i = 0; $i < count($dns); $i++) { for ($j = 0; $j < count($dns[$i]); $j++) { $type = $dns[$i][$j]['type']; $value = &$dns[$i][$j]['value']; if (is_object($value) && $value instanceof Element) { $map = $this->getMapping($type); if (!is_bool($map)) { $decoded = ASN1::decodeBER($value); $value = ASN1::asn1map($decoded[0], $map); } } } } } } /** * Map DN values from DN-specific internal format to * ANY type. * * @param &array $root * @param string $path * @access private */ private function mapOutDNs(&$root, $path) { $dns = &$this->subArray($root, $path); if (is_array($dns)) { $size = count($dns); for ($i = 0; $i < $size; $i++) { for ($j = 0; $j < count($dns[$i]); $j++) { $type = $dns[$i][$j]['type']; $value = &$dns[$i][$j]['value']; if (is_object($value) && $value instanceof Element) { continue; } $map = $this->getMapping($type); if (!is_bool($map)) { $value = new Element(ASN1::encodeDER($value, $map)); } } } } } /** * Associate an extension ID to an extension mapping * * @param string $extnId * @access private * @return mixed */ private function getMapping($extnId) { if (!is_string($extnId)) { // eg. if it's a \phpseclib\File\ASN1\Element object return true; } switch ($extnId) { case 'id-ce-keyUsage': return Maps\KeyUsage::MAP; case 'id-ce-basicConstraints': return Maps\BasicConstraints::MAP; case 'id-ce-subjectKeyIdentifier': return Maps\KeyIdentifier::MAP; case 'id-ce-cRLDistributionPoints': return Maps\CRLDistributionPoints::MAP; case 'id-ce-authorityKeyIdentifier': return Maps\AuthorityKeyIdentifier::MAP; case 'id-ce-certificatePolicies': return Maps\CertificatePolicies::MAP; case 'id-ce-extKeyUsage': return Maps\ExtKeyUsageSyntax::MAP; case 'id-pe-authorityInfoAccess': return Maps\AuthorityInfoAccessSyntax::MAP; case 'id-ce-subjectAltName': return Maps\SubjectAltName::MAP; case 'id-ce-subjectDirectoryAttributes': return Maps\SubjectDirectoryAttributes::MAP; case 'id-ce-privateKeyUsagePeriod': return Maps\PrivateKeyUsagePeriod::MAP; case 'id-ce-issuerAltName': return Maps\IssuerAltName::MAP; case 'id-ce-policyMappings': return Maps\PolicyMappings::MAP; case 'id-ce-nameConstraints': return Maps\NameConstraints::MAP; case 'netscape-cert-type': return Maps\netscape_cert_type::MAP; case 'netscape-comment': return Maps\netscape_comment::MAP; case 'netscape-ca-policy-url': return Maps\netscape_ca_policy_url::MAP; // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets // back around to asn1map() and we don't want it decoded again. //case 'id-qt-cps': // return Maps\CPSuri::MAP; case 'id-qt-unotice': return Maps\UserNotice::MAP; // the following OIDs are unsupported but we don't want them to give notices when calling saveX509(). case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt case 'entrustVersInfo': // http://support.microsoft.com/kb/287547 case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION // "SET Secure Electronic Transaction Specification" // http://www.maithean.com/docs/set_bk3.pdf case '2.23.42.7.0': // id-set-hashedRootKey // "Certificate Transparency" // https://tools.ietf.org/html/rfc6962 case '1.3.6.1.4.1.11129.2.4.2': // "Qualified Certificate statements" // https://tools.ietf.org/html/rfc3739#section-3.2.6 case '1.3.6.1.5.5.7.1.3': return true; // CSR attributes case 'pkcs-9-at-unstructuredName': return Maps\PKCS9String::MAP; case 'pkcs-9-at-challengePassword': return Maps\DirectoryString::MAP; case 'pkcs-9-at-extensionRequest': return Maps\Extensions::MAP; // CRL extensions. case 'id-ce-cRLNumber': return Maps\CRLNumber::MAP; case 'id-ce-deltaCRLIndicator': return Maps\CRLNumber::MAP; case 'id-ce-issuingDistributionPoint': return Maps\IssuingDistributionPoint::MAP; case 'id-ce-freshestCRL': return Maps\CRLDistributionPoints::MAP; case 'id-ce-cRLReasons': return Maps\CRLReason::MAP; case 'id-ce-invalidityDate': return Maps\InvalidityDate::MAP; case 'id-ce-certificateIssuer': return Maps\CertificateIssuer::MAP; case 'id-ce-holdInstructionCode': return Maps\HoldInstructionCode::MAP; case 'id-at-postalAddress': return Maps\PostalAddress::MAP; } return false; } /** * Load an X.509 certificate as a certificate authority * * @param string $cert * @access public * @return bool */ public function loadCA($cert) { $olddn = $this->dn; $oldcert = $this->currentCert; $oldsigsubj = $this->signatureSubject; $oldkeyid = $this->currentKeyIdentifier; $cert = $this->loadX509($cert); if (!$cert) { $this->dn = $olddn; $this->currentCert = $oldcert; $this->signatureSubject = $oldsigsubj; $this->currentKeyIdentifier = $oldkeyid; return false; } /* From RFC5280 "PKIX Certificate and CRL Profile": If the keyUsage extension is present, then the subject public key MUST NOT be used to verify signatures on certificates or CRLs unless the corresponding keyCertSign or cRLSign bit is set. */ //$keyUsage = $this->getExtension('id-ce-keyUsage'); //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) { // return false; //} /* From RFC5280 "PKIX Certificate and CRL Profile": The cA boolean indicates whether the certified public key may be used to verify certificate signatures. If the cA boolean is not asserted, then the keyCertSign bit in the key usage extension MUST NOT be asserted. If the basic constraints extension is not present in a version 3 certificate, or the extension is present but the cA boolean is not asserted, then the certified public key MUST NOT be used to verify certificate signatures. */ //$basicConstraints = $this->getExtension('id-ce-basicConstraints'); //if (!$basicConstraints || !$basicConstraints['cA']) { // return false; //} $this->CAs[] = $cert; $this->dn = $olddn; $this->currentCert = $oldcert; $this->signatureSubject = $oldsigsubj; return true; } /** * Validate an X.509 certificate against a URL * * From RFC2818 "HTTP over TLS": * * Matching is performed using the matching rules specified by * [RFC2459]. If more than one identity of a given type is present in * the certificate (e.g., more than one dNSName name, a match in any one * of the set is considered acceptable.) Names may contain the wildcard * character * which is considered to match any single domain name * component or component fragment. E.g., *.a.com matches foo.a.com but * not bar.foo.a.com. f*.com matches foo.com but not bar.com. * * @param string $url * @access public * @return bool */ public function validateURL($url) { if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { return false; } $components = parse_url($url); if (!isset($components['host'])) { return false; } if ($names = $this->getExtension('id-ce-subjectAltName')) { foreach ($names as $name) { foreach ($name as $key => $value) { $value = str_replace(['.', '*'], ['\.', '[^.]*'], $value); switch ($key) { case 'dNSName': /* From RFC2818 "HTTP over TLS": If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead. */ if (preg_match('#^' . $value . '$#', $components['host'])) { return true; } break; case 'iPAddress': /* From RFC2818 "HTTP over TLS": In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI. */ if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) { return true; } } } } return false; } if ($value = $this->getDNProp('id-at-commonName')) { $value = str_replace(['.', '*'], ['\.', '[^.]*'], $value[0]); return preg_match('#^' . $value . '$#', $components['host']); } return false; } /** * Validate a date * * If $date isn't defined it is assumed to be the current date. * * @param \DateTime|string $date optional * @access public * @return boolean */ public function validateDate($date = null) { if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { return false; } if (!isset($date)) { $date = new DateTime(null, new DateTimeZone(@date_default_timezone_get())); } $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore']; $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime']; $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter']; $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime']; if (is_string($date)) { $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get())); } $notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get())); $notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get())); switch (true) { case $date < $notBefore: case $date > $notAfter: return false; } return true; } /** * Fetches a URL * * @param string $url * @access private * @return bool|string */ private static function fetchURL($url) { if (self::$disable_url_fetch) { return false; } $parts = parse_url($url); $data = ''; switch ($parts['scheme']) { case 'http': $fsock = @fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80); if (!$fsock) { return false; } fputs($fsock, "GET $parts[path] HTTP/1.0\r\n"); fputs($fsock, "Host: $parts[host]\r\n\r\n"); $line = fgets($fsock, 1024); if (strlen($line) < 3) { return false; } preg_match('#HTTP/1.\d (\d{3})#', $line, $temp); if ($temp[1] != '200') { return false; } // skip the rest of the headers in the http response while (!feof($fsock) && fgets($fsock, 1024) != "\r\n") { } while (!feof($fsock)) { $data.= fread($fsock, 1024); } break; //case 'ftp': //case 'ldap': //default: } return $data; } /** * Validates an intermediate cert as identified via authority info access extension * * See https://tools.ietf.org/html/rfc4325 for more info * * @param bool $caonly * @param int $count * @access private * @return bool */ private function testForIntermediate($caonly, $count) { $opts = $this->getExtension('id-pe-authorityInfoAccess'); if (!is_array($opts)) { return false; } foreach ($opts as $opt) { if ($opt['accessMethod'] == 'id-ad-caIssuers') { // accessLocation is a GeneralName. GeneralName fields support stuff like email addresses, IP addresses, LDAP, // etc, but we're only supporting URI's. URI's and LDAP are the only thing https://tools.ietf.org/html/rfc4325 // discusses if (isset($opt['accessLocation']['uniformResourceIdentifier'])) { $url = $opt['accessLocation']['uniformResourceIdentifier']; break; } } } if (!isset($url)) { return false; } $cert = static::fetchURL($url); if (!is_string($cert)) { return false; } $parent = new static(); $parent->CAs = $this->CAs; /* "Conforming applications that support HTTP or FTP for accessing certificates MUST be able to accept .cer files and SHOULD be able to accept .p7c files." -- https://tools.ietf.org/html/rfc4325 A .p7c file is 'a "certs-only" CMS message as specified in RFC 2797" These are currently unsupported */ if (!is_array($parent->loadX509($cert))) { return false; } if (!$parent->validateSignatureCountable($caonly, ++$count)) { return false; } $this->CAs[] = $parent->currentCert; //$this->loadCA($cert); return true; } /** * Validate a signature * * Works on X.509 certs, CSR's and CRL's. * Returns true if the signature is verified, false if it is not correct or null on error * * By default returns false for self-signed certs. Call validateSignature(false) to make this support * self-signed. * * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}. * * @param bool $caonly optional * @access public * @return mixed */ public function validateSignature($caonly = true) { return $this->validateSignatureCountable($caonly, 0); } /** * Validate a signature * * Performs said validation whilst keeping track of how many times validation method is called * * @param bool $caonly * @param int $count * @access private * @return mixed */ private function validateSignatureCountable($caonly, $count) { if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { return null; } if ($count == self::$recur_limit) { return false; } /* TODO: "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")." -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6 implement pathLenConstraint in the id-ce-basicConstraints extension */ switch (true) { case isset($this->currentCert['tbsCertificate']): // self-signed cert switch (true) { case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']: case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(self::DN_STRING) === $this->getDN(self::DN_STRING): $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier'); switch (true) { case !is_array($authorityKey): case !$subjectKeyID: case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: $signingCert = $this->currentCert; // working cert } } if (!empty($this->CAs)) { for ($i = 0; $i < count($this->CAs); $i++) { // even if the cert is a self-signed one we still want to see if it's a CA; // if not, we'll conditionally return an error $ca = $this->CAs[$i]; switch (true) { case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']: case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']): $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); switch (true) { case !is_array($authorityKey): case !$subjectKeyID: case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) { break 2; // serial mismatch - check other ca } $signingCert = $ca; // working cert break 3; } } } if (count($this->CAs) == $i && $caonly) { return $this->testForIntermediate($caonly, $count) && $this->validateSignature($caonly); } } elseif (!isset($signingCert) || $caonly) { return $this->testForIntermediate($caonly, $count) && $this->validateSignature($caonly); } return $this->validateSignatureHelper( $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], substr($this->currentCert['signature'], 1), $this->signatureSubject ); case isset($this->currentCert['certificationRequestInfo']): return $this->validateSignatureHelper( $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'], $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], substr($this->currentCert['signature'], 1), $this->signatureSubject ); case isset($this->currentCert['publicKeyAndChallenge']): return $this->validateSignatureHelper( $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'], $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], substr($this->currentCert['signature'], 1), $this->signatureSubject ); case isset($this->currentCert['tbsCertList']): if (!empty($this->CAs)) { for ($i = 0; $i < count($this->CAs); $i++) { $ca = $this->CAs[$i]; switch (true) { case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']: case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']): $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); switch (true) { case !is_array($authorityKey): case !$subjectKeyID: case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) { break 2; // serial mismatch - check other ca } $signingCert = $ca; // working cert break 3; } } } } if (!isset($signingCert)) { return false; } return $this->validateSignatureHelper( $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], substr($this->currentCert['signature'], 1), $this->signatureSubject ); default: return false; } } /** * Validates a signature * * Returns true if the signature is verified and false if it is not correct. * If the algorithms are unsupposed an exception is thrown. * * @param string $publicKeyAlgorithm * @param string $publicKey * @param string $signatureAlgorithm * @param string $signature * @param string $signatureSubject * @access private * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported * @return bool */ private function validateSignatureHelper($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject) { switch ($publicKeyAlgorithm) { case 'rsaEncryption': $key = RSA::load($publicKey, 'PKCS8'); switch ($signatureAlgorithm) { case 'md2WithRSAEncryption': case 'md5WithRSAEncryption': case 'sha1WithRSAEncryption': case 'sha224WithRSAEncryption': case 'sha256WithRSAEncryption': case 'sha384WithRSAEncryption': case 'sha512WithRSAEncryption': $key = $key ->withHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)) ->withPadding(RSA::SIGNATURE_PKCS1); break; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); } break; case 'id-Ed25519': case 'id-Ed448': $key = ECDSA::load($publicKey, 'PKCS8'); break; case 'id-ecPublicKey': $key = ECDSA::load($publicKey, 'PKCS8'); switch ($signatureAlgorithm) { case 'ecdsa-with-SHA1': case 'ecdsa-with-SHA224': case 'ecdsa-with-SHA256': case 'ecdsa-with-SHA384': case 'ecdsa-with-SHA512': $key = $key ->withHash(preg_replace('#^ecdsa-with-#', '', strtolower($signatureAlgorithm))); break; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); } break; case 'id-dsa': $key = DSA::load($publicKey, 'PKCS8'); switch ($signatureAlgorithm) { case 'id-dsa-with-sha1': case 'id-dsa-with-sha224': case 'id-dsa-with-sha256': $key = $key ->withHash(preg_replace('#^id-dsa-with-#', '', strtolower($signatureAlgorithm))); break; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); } break; default: throw new UnsupportedAlgorithmException('Public key algorithm unsupported'); } return $key->verify($signatureSubject, $signature); } /** * Sets the recursion limit * * When validating a signature it may be necessary to download intermediate certs from URI's. * An intermediate cert that linked to itself would result in an infinite loop so to prevent * that we set a recursion limit. A negative number means that there is no recursion limit. * * @param int $count * @access public */ static function setRecurLimit($count) { self::$recur_limit = $count; } /** * Prevents URIs from being automatically retrieved * * @access public */ static function disableURLFetch() { self::$disable_url_fetch = true; } /** * Allows URIs to be automatically retrieved * * @access public */ static function enableURLFetch() { self::$disable_url_fetch = false; } /** * Decodes an IP address * * Takes in a base64 encoded "blob" and returns a human readable IP address * * @param string $ip * @access private * @return string */ public function decodeIP($ip) { return inet_ntop($ip); } /** * Encodes an IP address * * Takes a human readable IP address into a base64-encoded "blob" * * @param string $ip * @access private * @return string */ public function encodeIP($ip) { return inet_pton($ip); } /** * "Normalizes" a Distinguished Name property * * @param string $propName * @access private * @return mixed */ private function translateDNProp($propName) { switch (strtolower($propName)) { case 'id-at-countryname': case 'countryname': case 'c': return 'id-at-countryName'; case 'id-at-organizationname': case 'organizationname': case 'o': return 'id-at-organizationName'; case 'id-at-dnqualifier': case 'dnqualifier': return 'id-at-dnQualifier'; case 'id-at-commonname': case 'commonname': case 'cn': return 'id-at-commonName'; case 'id-at-stateorprovincename': case 'stateorprovincename': case 'state': case 'province': case 'provincename': case 'st': return 'id-at-stateOrProvinceName'; case 'id-at-localityname': case 'localityname': case 'l': return 'id-at-localityName'; case 'id-emailaddress': case 'emailaddress': return 'pkcs-9-at-emailAddress'; case 'id-at-serialnumber': case 'serialnumber': return 'id-at-serialNumber'; case 'id-at-postalcode': case 'postalcode': return 'id-at-postalCode'; case 'id-at-streetaddress': case 'streetaddress': return 'id-at-streetAddress'; case 'id-at-name': case 'name': return 'id-at-name'; case 'id-at-givenname': case 'givenname': return 'id-at-givenName'; case 'id-at-surname': case 'surname': case 'sn': return 'id-at-surname'; case 'id-at-initials': case 'initials': return 'id-at-initials'; case 'id-at-generationqualifier': case 'generationqualifier': return 'id-at-generationQualifier'; case 'id-at-organizationalunitname': case 'organizationalunitname': case 'ou': return 'id-at-organizationalUnitName'; case 'id-at-pseudonym': case 'pseudonym': return 'id-at-pseudonym'; case 'id-at-title': case 'title': return 'id-at-title'; case 'id-at-description': case 'description': return 'id-at-description'; case 'id-at-role': case 'role': return 'id-at-role'; case 'id-at-uniqueidentifier': case 'uniqueidentifier': case 'x500uniqueidentifier': return 'id-at-uniqueIdentifier'; case 'postaladdress': case 'id-at-postaladdress': return 'id-at-postalAddress'; default: return false; } } /** * Set a Distinguished Name property * * @param string $propName * @param mixed $propValue * @param string $type optional * @access public * @return bool */ public function setDNProp($propName, $propValue, $type = 'utf8String') { if (empty($this->dn)) { $this->dn = ['rdnSequence' => []]; } if (($propName = $this->translateDNProp($propName)) === false) { return false; } foreach ((array) $propValue as $v) { if (!is_array($v) && isset($type)) { $v = [$type => $v]; } $this->dn['rdnSequence'][] = [ [ 'type' => $propName, 'value'=> $v ] ]; } return true; } /** * Remove Distinguished Name properties * * @param string $propName * @access public */ public function removeDNProp($propName) { if (empty($this->dn)) { return; } if (($propName = $this->translateDNProp($propName)) === false) { return; } $dn = &$this->dn['rdnSequence']; $size = count($dn); for ($i = 0; $i < $size; $i++) { if ($dn[$i][0]['type'] == $propName) { unset($dn[$i]); } } $dn = array_values($dn); // fix for https://bugs.php.net/75433 affecting PHP 7.2 if (!isset($dn[0])) { $dn = array_splice($dn, 0, 0); } } /** * Get Distinguished Name properties * * @param string $propName * @param array $dn optional * @param bool $withType optional * @return mixed * @access public */ public function getDNProp($propName, $dn = null, $withType = false) { if (!isset($dn)) { $dn = $this->dn; } if (empty($dn)) { return false; } if (($propName = $this->translateDNProp($propName)) === false) { return false; } $filters = []; $filters['value'] = ['type' => ASN1::TYPE_UTF8_STRING]; ASN1::setFilters($filters); $this->mapOutDNs($dn, 'rdnSequence'); $dn = $dn['rdnSequence']; $result = []; for ($i = 0; $i < count($dn); $i++) { if ($dn[$i][0]['type'] == $propName) { $v = $dn[$i][0]['value']; if (!$withType) { if (is_array($v)) { foreach ($v as $type => $s) { $type = array_search($type, ASN1::ANY_MAP); if ($type !== false && array_key_exists($type, ASN1::STRING_TYPE_SIZE)) { $s = ASN1::convert($s, $type); if ($s !== false) { $v = $s; break; } } } if (is_array($v)) { $v = array_pop($v); // Always strip data type. } } elseif (is_object($v) && $v instanceof Element) { $map = $this->getMapping($propName); if (!is_bool($map)) { $decoded = ASN1::decodeBER($v); $v = ASN1::asn1map($decoded[0], $map); } } } $result[] = $v; } } return $result; } /** * Set a Distinguished Name * * @param mixed $dn * @param bool $merge optional * @param string $type optional * @access public * @return bool */ public function setDN($dn, $merge = false, $type = 'utf8String') { if (!$merge) { $this->dn = null; } if (is_array($dn)) { if (isset($dn['rdnSequence'])) { $this->dn = $dn; // No merge here. return true; } // handles stuff generated by openssl_x509_parse() foreach ($dn as $prop => $value) { if (!$this->setDNProp($prop, $value, $type)) { return false; } } return true; } // handles everything else $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE); for ($i = 1; $i < count($results); $i+=2) { $prop = trim($results[$i], ', =/'); $value = $results[$i + 1]; if (!$this->setDNProp($prop, $value, $type)) { return false; } } return true; } /** * Get the Distinguished Name for a certificates subject * * @param mixed $format optional * @param array $dn optional * @access public * @return array|bool */ public function getDN($format = self::DN_ARRAY, $dn = null) { if (!isset($dn)) { $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn; } switch ((int) $format) { case self::DN_ARRAY: return $dn; case self::DN_ASN1: $filters = []; $filters['rdnSequence']['value'] = ['type' => ASN1::TYPE_UTF8_STRING]; ASN1::setFilters($filters); $this->mapOutDNs($dn, 'rdnSequence'); return ASN1::encodeDER($dn, Maps\Name::MAP); case self::DN_CANON: // No SEQUENCE around RDNs and all string values normalized as // trimmed lowercase UTF-8 with all spacing as one blank. // constructed RDNs will not be canonicalized $filters = []; $filters['value'] = ['type' => ASN1::TYPE_UTF8_STRING]; ASN1::setFilters($filters); $result = ''; $this->mapOutDNs($dn, 'rdnSequence'); foreach ($dn['rdnSequence'] as $rdn) { foreach ($rdn as $i => $attr) { $attr = &$rdn[$i]; if (is_array($attr['value'])) { foreach ($attr['value'] as $type => $v) { $type = array_search($type, ASN1::ANY_MAP, true); if ($type !== false && array_key_exists($type, ASN1::STRING_TYPE_SIZE)) { $v = ASN1::convert($v, $type); if ($v !== false) { $v = preg_replace('/\s+/', ' ', $v); $attr['value'] = strtolower(trim($v)); break; } } } } } $result .= ASN1::encodeDER($rdn, Maps\RelativeDistinguishedName::MAP); } return $result; case self::DN_HASH: $dn = $this->getDN(self::DN_CANON, $dn); $hash = new Hash('sha1'); $hash = $hash->hash($dn); extract(unpack('Vhash', $hash)); return strtolower(Hex::encode(pack('N', $hash))); } // Default is to return a string. $start = true; $output = ''; $result = []; $filters = []; $filters['rdnSequence']['value'] = ['type' => ASN1::TYPE_UTF8_STRING]; ASN1::setFilters($filters); $this->mapOutDNs($dn, 'rdnSequence'); foreach ($dn['rdnSequence'] as $field) { $prop = $field[0]['type']; $value = $field[0]['value']; $delim = ', '; switch ($prop) { case 'id-at-countryName': $desc = 'C'; break; case 'id-at-stateOrProvinceName': $desc = 'ST'; break; case 'id-at-organizationName': $desc = 'O'; break; case 'id-at-organizationalUnitName': $desc = 'OU'; break; case 'id-at-commonName': $desc = 'CN'; break; case 'id-at-localityName': $desc = 'L'; break; case 'id-at-surname': $desc = 'SN'; break; case 'id-at-uniqueIdentifier': $delim = '/'; $desc = 'x500UniqueIdentifier'; break; case 'id-at-postalAddress': $delim = '/'; $desc = 'postalAddress'; break; default: $delim = '/'; $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop); } if (!$start) { $output.= $delim; } if (is_array($value)) { foreach ($value as $type => $v) { $type = array_search($type, ASN1::ANY_MAP, true); if ($type !== false && array_key_exists($type, ASN1::STRING_TYPE_SIZE)) { $v = ASN1::convert($v, $type); if ($v !== false) { $value = $v; break; } } } if (is_array($value)) { $value = array_pop($value); // Always strip data type. } } elseif (is_object($value) && $value instanceof Element) { $callback = function($x) { return '\x' . bin2hex($x[0]); }; $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element)); } $output.= $desc . '=' . $value; $result[$desc] = isset($result[$desc]) ? array_merge((array) $result[$desc], [$value]) : $value; $start = false; } return $format == self::DN_OPENSSL ? $result : $output; } /** * Get the Distinguished Name for a certificate/crl issuer * * @param int $format optional * @access public * @return mixed */ public function getIssuerDN($format = self::DN_ARRAY) { switch (true) { case !isset($this->currentCert) || !is_array($this->currentCert): break; case isset($this->currentCert['tbsCertificate']): return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']); case isset($this->currentCert['tbsCertList']): return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']); } return false; } /** * Get the Distinguished Name for a certificate/csr subject * Alias of getDN() * * @param int $format optional * @access public * @return mixed */ public function getSubjectDN($format = self::DN_ARRAY) { switch (true) { case !empty($this->dn): return $this->getDN($format); case !isset($this->currentCert) || !is_array($this->currentCert): break; case isset($this->currentCert['tbsCertificate']): return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']); case isset($this->currentCert['certificationRequestInfo']): return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']); } return false; } /** * Get an individual Distinguished Name property for a certificate/crl issuer * * @param string $propName * @param bool $withType optional * @access public * @return mixed */ public function getIssuerDNProp($propName, $withType = false) { switch (true) { case !isset($this->currentCert) || !is_array($this->currentCert): break; case isset($this->currentCert['tbsCertificate']): return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType); case isset($this->currentCert['tbsCertList']): return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType); } return false; } /** * Get an individual Distinguished Name property for a certificate/csr subject * * @param string $propName * @param bool $withType optional * @access public * @return mixed */ public function getSubjectDNProp($propName, $withType = false) { switch (true) { case !empty($this->dn): return $this->getDNProp($propName, null, $withType); case !isset($this->currentCert) || !is_array($this->currentCert): break; case isset($this->currentCert['tbsCertificate']): return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType); case isset($this->currentCert['certificationRequestInfo']): return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType); } return false; } /** * Get the certificate chain for the current cert * * @access public * @return mixed */ public function getChain() { $chain = [$this->currentCert]; if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { return false; } if (empty($this->CAs)) { return $chain; } while (true) { $currentCert = $chain[count($chain) - 1]; for ($i = 0; $i < count($this->CAs); $i++) { $ca = $this->CAs[$i]; if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) { $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert); $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); switch (true) { case !is_array($authorityKey): case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: if ($currentCert === $ca) { break 3; } $chain[] = $ca; break 2; } } } if ($i == count($this->CAs)) { break; } } foreach ($chain as $key => $value) { $chain[$key] = new X509(); $chain[$key]->loadX509($value); } return $chain; } /** * Set public key * * Key needs to be a \phpseclib\Crypt\RSA object * * @param object $key * @access public * @return bool */ public function setPublicKey(PublicKey $key) { $this->publicKey = $key; } /** * Set private key * * Key needs to be a \phpseclib\Crypt\RSA object * * @param object $key * @access public */ public function setPrivateKey(PrivateKey $key) { $this->privateKey = $key; } /** * Set challenge * * Used for SPKAC CSR's * * @param string $challenge * @access public */ public function setChallenge($challenge) { $this->challenge = $challenge; } /** * Gets the public key * * Returns a \phpseclib\Crypt\RSA object or a false. * * @access public * @return mixed */ public function getPublicKey() { if (isset($this->publicKey)) { return $this->publicKey; } if (isset($this->currentCert) && is_array($this->currentCert)) { foreach (['tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo'] as $path) { $keyinfo = $this->subArray($this->currentCert, $path); if (!empty($keyinfo)) { break; } } } if (empty($keyinfo)) { return false; } $key = $keyinfo['subjectPublicKey']; switch ($keyinfo['algorithm']['algorithm']) { case 'rsaEncryption': return RSA::load($key, 'PKCS8'); case 'id-ecPublicKey': case 'id-Ed25519': case 'id-Ed448': return ECDSA::load($key, 'PKCS8'); case 'id-dsa': return DSA::load($key, 'PKCS8'); } return false; } /** * Load a Certificate Signing Request * * @param string $csr * @param int $mode * @return mixed * @access public */ public function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT) { if (is_array($csr) && isset($csr['certificationRequestInfo'])) { unset($this->currentCert); unset($this->currentKeyIdentifier); unset($this->signatureSubject); $this->dn = $csr['certificationRequestInfo']['subject']; if (!isset($this->dn)) { return false; } $this->currentCert = $csr; return $csr; } // see http://tools.ietf.org/html/rfc2986 if ($mode != self::FORMAT_DER) { $newcsr = ASN1::extractBER($csr); if ($mode == self::FORMAT_PEM && $csr == $newcsr) { return false; } $csr = $newcsr; } $orig = $csr; if ($csr === false) { $this->currentCert = false; return false; } $decoded = ASN1::decodeBER($csr); if (empty($decoded)) { $this->currentCert = false; return false; } $csr = ASN1::asn1map($decoded[0], Maps\CertificationRequest::MAP); if (!isset($csr) || $csr === false) { $this->currentCert = false; return false; } $this->mapInAttributes($csr, 'certificationRequestInfo/attributes'); $this->mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence'); $this->dn = $csr['certificationRequestInfo']['subject']; $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); $key = $csr['certificationRequestInfo']['subjectPKInfo']; $key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP); $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($key), 64) . "-----END PUBLIC KEY-----"; $this->publicKey = null; $this->publicKey = $this->getPublicKey(); $this->currentKeyIdentifier = null; $this->currentCert = $csr; return $csr; } /** * Save CSR request * * @param array $csr * @param int $format optional * @access public * @return string */ public function saveCSR($csr, $format = self::FORMAT_PEM) { if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) { return false; } switch (true) { case !($algorithm = $this->subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')): case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']): break; default: $csr['certificationRequestInfo']['subjectPKInfo'] = new Element( base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])) ); } $filters = []; $filters['certificationRequestInfo']['subject']['rdnSequence']['value'] = ['type' => ASN1::TYPE_UTF8_STRING]; ASN1::setFilters($filters); $this->mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence'); $this->mapOutAttributes($csr, 'certificationRequestInfo/attributes'); $csr = ASN1::encodeDER($csr, Maps\CertificationRequest::MAP); switch ($format) { case self::FORMAT_DER: return $csr; // case self::FORMAT_PEM: default: return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(Base64::encode($csr), 64) . '-----END CERTIFICATE REQUEST-----'; } } /** * Load a SPKAC CSR * * SPKAC's are produced by the HTML5 keygen element: * * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen * * @param string $spkac * @access public * @return mixed */ public function loadSPKAC($spkac) { if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) { unset($this->currentCert); unset($this->currentKeyIdentifier); unset($this->signatureSubject); $this->currentCert = $spkac; return $spkac; } // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge // OpenSSL produces SPKAC's that are preceded by the string SPKAC= $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac); $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false; if ($temp != false) { $spkac = $temp; } $orig = $spkac; if ($spkac === false) { $this->currentCert = false; return false; } $decoded = ASN1::decodeBER($spkac); if (empty($decoded)) { $this->currentCert = false; return false; } $spkac = ASN1::asn1map($decoded[0], Maps\SignedPublicKeyAndChallenge::MAP); if (!isset($spkac) || $spkac === false) { $this->currentCert = false; return false; } $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); $key = $spkac['publicKeyAndChallenge']['spki']; $key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP); $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'] = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($key), 64) . "-----END PUBLIC KEY-----"; $this->publicKey = null; $this->publicKey = $this->getPublicKey(); $this->currentKeyIdentifier = null; $this->currentCert = $spkac; return $spkac; } /** * Save a SPKAC CSR request * * @param array $spkac * @param int $format optional * @access public * @return string */ public function saveSPKAC($spkac, $format = self::FORMAT_PEM) { if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) { return false; } $algorithm = $this->subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm'); switch (true) { case !$algorithm: case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']): break; default: $spkac['publicKeyAndChallenge']['spki'] = new Element( base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])) ); } $spkac = ASN1::encodeDER($spkac, Maps\SignedPublicKeyAndChallenge::MAP); switch ($format) { case self::FORMAT_DER: return $spkac; // case self::FORMAT_PEM: default: // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much // no other SPKAC decoders phpseclib will use that same format return 'SPKAC=' . Base64::encode($spkac); } } /** * Load a Certificate Revocation List * * @param string $crl * @param int $mode * @return mixed * @access public */ public function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT) { if (is_array($crl) && isset($crl['tbsCertList'])) { $this->currentCert = $crl; unset($this->signatureSubject); return $crl; } if ($mode != self::FORMAT_DER) { $newcrl = ASN1::extractBER($crl); if ($mode == self::FORMAT_PEM && $crl == $newcrl) { return false; } $crl = $newcrl; } $orig = $crl; if ($crl === false) { $this->currentCert = false; return false; } $decoded = ASN1::decodeBER($crl); if (empty($decoded)) { $this->currentCert = false; return false; } $crl = ASN1::asn1map($decoded[0], Maps\CertificateList::MAP); if (!isset($crl) || $crl === false) { $this->currentCert = false; return false; } $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); $this->mapInDNs($crl, 'tbsCertList/issuer/rdnSequence'); if ($this->isSubArrayValid($crl, 'tbsCertList/crlExtensions')) { $this->mapInExtensions($crl, 'tbsCertList/crlExtensions'); } if ($this->isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) { $rclist_ref = &$this->subArrayUnchecked($crl, 'tbsCertList/revokedCertificates'); if ($rclist_ref) { $rclist = $crl['tbsCertList']['revokedCertificates']; foreach ($rclist as $i => $extension) { if ($this->isSubArrayValid($rclist, "$i/crlEntryExtensions")) { $this->mapInExtensions($rclist_ref, "$i/crlEntryExtensions"); } } } } $this->currentKeyIdentifier = null; $this->currentCert = $crl; return $crl; } /** * Save Certificate Revocation List. * * @param array $crl * @param int $format optional * @access public * @return string */ public function saveCRL($crl, $format = self::FORMAT_PEM) { if (!is_array($crl) || !isset($crl['tbsCertList'])) { return false; } $filters = []; $filters['tbsCertList']['issuer']['rdnSequence']['value'] = ['type' => ASN1::TYPE_UTF8_STRING]; $filters['tbsCertList']['signature']['parameters'] = ['type' => ASN1::TYPE_UTF8_STRING]; $filters['signatureAlgorithm']['parameters'] = ['type' => ASN1::TYPE_UTF8_STRING]; if (empty($crl['tbsCertList']['signature']['parameters'])) { $filters['tbsCertList']['signature']['parameters'] = ['type' => ASN1::TYPE_NULL]; } if (empty($crl['signatureAlgorithm']['parameters'])) { $filters['signatureAlgorithm']['parameters'] = ['type' => ASN1::TYPE_NULL]; } ASN1::setFilters($filters); $this->mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence'); $this->mapOutExtensions($crl, 'tbsCertList/crlExtensions'); $rclist = &$this->subArray($crl, 'tbsCertList/revokedCertificates'); if (is_array($rclist)) { foreach ($rclist as $i => $extension) { $this->mapOutExtensions($rclist, "$i/crlEntryExtensions"); } } $crl = ASN1::encodeDER($crl, Maps\CertificateList::MAP); switch ($format) { case self::FORMAT_DER: return $crl; // case self::FORMAT_PEM: default: return "-----BEGIN X509 CRL-----\r\n" . chunk_split(Base64::encode($crl), 64) . '-----END X509 CRL-----'; } } /** * Helper function to build a time field according to RFC 3280 section * - 4.1.2.5 Validity * - 5.1.2.4 This Update * - 5.1.2.5 Next Update * - 5.1.2.6 Revoked Certificates * by choosing utcTime iff year of date given is before 2050 and generalTime else. * * @param string $date in format date('D, d M Y H:i:s O') * @access private * @return array|Element */ private function timeField($date) { if ($date instanceof Element) { return $date; } $dateObj = new DateTime($date, new DateTimeZone('GMT')); $year = $dateObj->format('Y'); // the same way ASN1.php parses this if ($year < 2050) { return ['utcTime' => $date]; } else { return ['generalTime' => $date]; } } /** * Sign an X.509 certificate * * $issuer's private key needs to be loaded. * $subject can be either an existing X.509 cert (if you want to resign it), * a CSR or something with the DN and public key explicitly set. * * @param \phpseclib\File\X509 $issuer * @param \phpseclib\File\X509 $subject * @param string $signatureAlgorithm optional * @access public * @return mixed */ public function sign($issuer, $subject, $signatureAlgorithm = 'sha256WithRSAEncryption') { if (!is_object($issuer->privateKey) || empty($issuer->dn)) { return false; } if (isset($subject->publicKey) && !($subjectPublicKey = $subject->formatSubjectPublicKey())) { return false; } $currentCert = isset($this->currentCert) ? $this->currentCert : null; $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) { $this->currentCert = $subject->currentCert; $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm; $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; if (!empty($this->startDate)) { $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->timeField($this->startDate); } if (!empty($this->endDate)) { $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->timeField($this->endDate); } if (!empty($this->serialNumber)) { $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber; } if (!empty($subject->dn)) { $this->currentCert['tbsCertificate']['subject'] = $subject->dn; } if (!empty($subject->publicKey)) { $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey; } $this->removeExtension('id-ce-authorityKeyIdentifier'); if (isset($subject->domains)) { $this->removeExtension('id-ce-subjectAltName'); } } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) { return false; } else { if (!isset($subject->publicKey)) { return false; } $startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get())); $startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O'); $endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get())); $endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O'); /* "The serial number MUST be a positive integer" "Conforming CAs MUST NOT use serialNumber values longer than 20 octets." -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2 for the integer to be positive the leading bit needs to be 0 hence the application of a bitmap */ $serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new BigInteger(Random::string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256); $this->currentCert = [ 'tbsCertificate' => [ 'version' => 'v3', 'serialNumber' => $serialNumber, // $this->setSerialNumber() 'signature' => ['algorithm' => $signatureAlgorithm], 'issuer' => false, // this is going to be overwritten later 'validity' => [ 'notBefore' => $this->timeField($startDate), // $this->setStartDate() 'notAfter' => $this->timeField($endDate) // $this->setEndDate() ], 'subject' => $subject->dn, 'subjectPublicKeyInfo' => $subjectPublicKey ], 'signatureAlgorithm' => ['algorithm' => $signatureAlgorithm], 'signature' => false // this is going to be overwritten later ]; // Copy extensions from CSR. $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0); if (!empty($csrexts)) { $this->currentCert['tbsCertificate']['extensions'] = $csrexts; } } $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn; if (isset($issuer->currentKeyIdentifier)) { $this->setExtension('id-ce-authorityKeyIdentifier', [ //'authorityCertIssuer' => array( // array( // 'directoryName' => $issuer->dn // ) //), 'keyIdentifier' => $issuer->currentKeyIdentifier ]); //$extensions = &$this->currentCert['tbsCertificate']['extensions']; //if (isset($issuer->serialNumber)) { // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; //} //unset($extensions); } if (isset($subject->currentKeyIdentifier)) { $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier); } $altName = []; if (isset($subject->domains) && count($subject->domains)) { $altName = array_map(['\phpseclib\File\X509', 'dnsName'], $subject->domains); } if (isset($subject->ipAddresses) && count($subject->ipAddresses)) { // should an IP address appear as the CN if no domain name is specified? idk //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1); $ipAddresses = []; foreach ($subject->ipAddresses as $ipAddress) { $encoded = $subject->ipAddress($ipAddress); if ($encoded !== false) { $ipAddresses[] = $encoded; } } if (count($ipAddresses)) { $altName = array_merge($altName, $ipAddresses); } } if (!empty($altName)) { $this->setExtension('id-ce-subjectAltName', $altName); } if ($this->caFlag) { $keyUsage = $this->getExtension('id-ce-keyUsage'); if (!$keyUsage) { $keyUsage = []; } $this->setExtension( 'id-ce-keyUsage', array_values(array_unique(array_merge($keyUsage, ['cRLSign', 'keyCertSign']))) ); $basicConstraints = $this->getExtension('id-ce-basicConstraints'); if (!$basicConstraints) { $basicConstraints = []; } $this->setExtension( 'id-ce-basicConstraints', array_unique(array_merge(['cA' => true], $basicConstraints)), true ); if (!isset($subject->currentKeyIdentifier)) { $this->setExtension('id-ce-subjectKeyIdentifier', $this->computeKeyIdentifier($this->currentCert), false, false); } } // resync $this->signatureSubject // save $tbsCertificate in case there are any \phpseclib\File\ASN1\Element objects in it $tbsCertificate = $this->currentCert['tbsCertificate']; $this->loadX509($this->saveX509($this->currentCert)); $result = $this->signHelper($issuer->privateKey, $signatureAlgorithm); $result['tbsCertificate'] = $tbsCertificate; $this->currentCert = $currentCert; $this->signatureSubject = $signatureSubject; return $result; } /** * Sign a CSR * * @access public * @param string $signatureAlgorithm * @return mixed */ public function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption') { if (!is_object($this->privateKey) || empty($this->dn)) { return false; } $origPublicKey = $this->publicKey; $this->publicKey = $this->privateKey->getPublicKey(); $publicKey = $this->formatSubjectPublicKey(); $this->publicKey = $origPublicKey; $currentCert = isset($this->currentCert) ? $this->currentCert : null; $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) { $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; if (!empty($this->dn)) { $this->currentCert['certificationRequestInfo']['subject'] = $this->dn; } $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey; } else { $this->currentCert = [ 'certificationRequestInfo' => [ 'version' => 'v1', 'subject' => $this->dn, 'subjectPKInfo' => $publicKey ], 'signatureAlgorithm' => ['algorithm' => $signatureAlgorithm], 'signature' => false // this is going to be overwritten later ]; } // resync $this->signatureSubject // save $certificationRequestInfo in case there are any \phpseclib\File\ASN1\Element objects in it $certificationRequestInfo = $this->currentCert['certificationRequestInfo']; $this->loadCSR($this->saveCSR($this->currentCert)); $result = $this->signHelper($this->privateKey, $signatureAlgorithm); $result['certificationRequestInfo'] = $certificationRequestInfo; $this->currentCert = $currentCert; $this->signatureSubject = $signatureSubject; return $result; } /** * Sign a SPKAC * * @access public * @param string $signatureAlgorithm * @return mixed */ public function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption') { if (!is_object($this->privateKey)) { return false; } $origPublicKey = $this->publicKey; $this->publicKey = $this->privateKey->getPublicKey(); $publicKey = $this->formatSubjectPublicKey(); $this->publicKey = $origPublicKey; $currentCert = isset($this->currentCert) ? $this->currentCert : null; $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; // re-signing a SPKAC seems silly but since everything else supports re-signing why not? if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) { $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey; if (!empty($this->challenge)) { // the bitwise AND ensures that the output is a valid IA5String $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge)); } } else { $this->currentCert = [ 'publicKeyAndChallenge' => [ 'spki' => $publicKey, // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>, // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified." // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way // we could alternatively do this instead if we ignored the specs: // Random::string(8) & str_repeat("\x7F", 8) 'challenge' => !empty($this->challenge) ? $this->challenge : '' ], 'signatureAlgorithm' => ['algorithm' => $signatureAlgorithm], 'signature' => false // this is going to be overwritten later ]; } // resync $this->signatureSubject // save $publicKeyAndChallenge in case there are any \phpseclib\File\ASN1\Element objects in it $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge']; $this->loadSPKAC($this->saveSPKAC($this->currentCert)); $result = $this->signHelper($this->privateKey, $signatureAlgorithm); $result['publicKeyAndChallenge'] = $publicKeyAndChallenge; $this->currentCert = $currentCert; $this->signatureSubject = $signatureSubject; return $result; } /** * Sign a CRL * * $issuer's private key needs to be loaded. * * @param \phpseclib\File\X509 $issuer * @param \phpseclib\File\X509 $crl * @param string $signatureAlgorithm optional * @access public * @return mixed */ public function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption') { if (!is_object($issuer->privateKey) || empty($issuer->dn)) { return false; } $currentCert = isset($this->currentCert) ? $this->currentCert : null; $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; $thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get())); $thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O'); if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) { $this->currentCert = $crl->currentCert; $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm; $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; } else { $this->currentCert = [ 'tbsCertList' => [ 'version' => 'v2', 'signature' => ['algorithm' => $signatureAlgorithm], 'issuer' => false, // this is going to be overwritten later 'thisUpdate' => $this->timeField($thisUpdate) // $this->setStartDate() ], 'signatureAlgorithm' => ['algorithm' => $signatureAlgorithm], 'signature' => false // this is going to be overwritten later ]; } $tbsCertList = &$this->currentCert['tbsCertList']; $tbsCertList['issuer'] = $issuer->dn; $tbsCertList['thisUpdate'] = $this->timeField($thisUpdate); if (!empty($this->endDate)) { $tbsCertList['nextUpdate'] = $this->timeField($this->endDate); // $this->setEndDate() } else { unset($tbsCertList['nextUpdate']); } if (!empty($this->serialNumber)) { $crlNumber = $this->serialNumber; } else { $crlNumber = $this->getExtension('id-ce-cRLNumber'); // "The CRL number is a non-critical CRL extension that conveys a // monotonically increasing sequence number for a given CRL scope and // CRL issuer. This extension allows users to easily determine when a // particular CRL supersedes another CRL." // -- https://tools.ietf.org/html/rfc5280#section-5.2.3 $crlNumber = $crlNumber !== false ? $crlNumber->add(new BigInteger(1)) : null; } $this->removeExtension('id-ce-authorityKeyIdentifier'); $this->removeExtension('id-ce-issuerAltName'); // Be sure version >= v2 if some extension found. $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0; if (!$version) { if (!empty($tbsCertList['crlExtensions'])) { $version = 1; // v2. } elseif (!empty($tbsCertList['revokedCertificates'])) { foreach ($tbsCertList['revokedCertificates'] as $cert) { if (!empty($cert['crlEntryExtensions'])) { $version = 1; // v2. } } } if ($version) { $tbsCertList['version'] = $version; } } // Store additional extensions. if (!empty($tbsCertList['version'])) { // At least v2. if (!empty($crlNumber)) { $this->setExtension('id-ce-cRLNumber', $crlNumber); } if (isset($issuer->currentKeyIdentifier)) { $this->setExtension('id-ce-authorityKeyIdentifier', [ //'authorityCertIssuer' => array( // ] // 'directoryName' => $issuer->dn // ] //), 'keyIdentifier' => $issuer->currentKeyIdentifier ]); //$extensions = &$tbsCertList['crlExtensions']; //if (isset($issuer->serialNumber)) { // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; //} //unset($extensions); } $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert); if ($issuerAltName !== false) { $this->setExtension('id-ce-issuerAltName', $issuerAltName); } } if (empty($tbsCertList['revokedCertificates'])) { unset($tbsCertList['revokedCertificates']); } unset($tbsCertList); // resync $this->signatureSubject // save $tbsCertList in case there are any \phpseclib\File\ASN1\Element objects in it $tbsCertList = $this->currentCert['tbsCertList']; $this->loadCRL($this->saveCRL($this->currentCert)); $result = $this->signHelper($issuer->privateKey, $signatureAlgorithm); $result['tbsCertList'] = $tbsCertList; $this->currentCert = $currentCert; $this->signatureSubject = $signatureSubject; return $result; } /** * X.509 certificate signing helper function. * * @param object $key * @param string $signatureAlgorithm * @access public * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported * @return mixed */ private function signHelper(PrivateKey $key, $signatureAlgorithm) { if ($key instanceof RSA) { switch ($signatureAlgorithm) { case 'md2WithRSAEncryption': case 'md5WithRSAEncryption': case 'sha1WithRSAEncryption': case 'sha224WithRSAEncryption': case 'sha256WithRSAEncryption': case 'sha384WithRSAEncryption': case 'sha512WithRSAEncryption': $key = $key ->withHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)) ->withPadding(RSA::SIGNATURE_PKCS1); $this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject); return $this->currentCert; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); } } if ($key instanceof DSA) { switch ($signatureAlgorithm) { case 'id-dsa-with-sha1': case 'id-dsa-with-sha224': case 'id-dsa-with-sha256': $key = $key ->withHash(preg_replace('#^id-dsa-with-#', '', strtolower($signatureAlgorithm))); $this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject); return $this->currentCert; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); } } if ($key instanceof ECDSA) { switch ($signatureAlgorithm) { case 'id-Ed25519': if ($key->getCurve() !== 'Ed25519') { throw new UnsupportedAlgorithmException('Loaded ECDSA does not use the Ed25519 key and yet that is the signature algorithm that has been chosen'); } $this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject); return $this->currentCert; case 'id-Ed448': if ($key->getCurve() !== 'Ed448') { throw new UnsupportedAlgorithmException('Loaded ECDSA does not use the Ed448 key and yet that is the signature algorithm that has been chosen'); } $this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject); return $this->currentCert; case 'ecdsa-with-SHA1': case 'ecdsa-with-SHA224': case 'ecdsa-with-SHA256': case 'ecdsa-with-SHA384': case 'ecdsa-with-SHA512': $key = $key ->withHash(preg_replace('#^ecdsa-with-#', '', strtolower($signatureAlgorithm))); $this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject); return $this->currentCert; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); } } throw new UnsupportedAlgorithmException('Unsupported public key algorithm'); } /** * Set certificate start date * * @param string $date * @access public */ public function setStartDate($date) { if (!is_object($date) || !is_a($date, 'DateTime')) { $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get())); } $this->startDate = $date->format('D, d M Y H:i:s O'); } /** * Set certificate end date * * @param string $date * @access public */ public function setEndDate($date) { /* To indicate that a certificate has no well-defined expiration date, the notAfter SHOULD be assigned the GeneralizedTime value of 99991231235959Z. -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5 */ if (strtolower($date) == 'lifetime') { $temp = '99991231235959Z'; $temp = chr(ASN1::TYPE_GENERALIZED_TIME) . ASN1::encodeLength(strlen($temp)) . $temp; $this->endDate = new Element($temp); } else { if (!is_object($date) || !is_a($date, 'DateTime')) { $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get())); } $this->endDate = $date->format('D, d M Y H:i:s O'); } } /** * Set Serial Number * * @param string $serial * @param $base integer Optional * @access public */ public function setSerialNumber($serial, $base = -256) { $this->serialNumber = new BigInteger($serial, $base); } /** * Turns the certificate into a certificate authority * * @access public */ public function makeCA() { $this->caFlag = true; } /** * Check for validity of subarray * * This is intended for use in conjunction with _subArrayUnchecked(), * implementing the checks included in _subArray() but without copying * a potentially large array by passing its reference by-value to is_array(). * * @param array $root * @param string $path * @return boolean * @access private */ private function isSubArrayValid($root, $path) { if (!is_array($root)) { return false; } foreach (explode('/', $path) as $i) { if (!is_array($root)) { return false; } if (!isset($root[$i])) { return true; } $root = $root[$i]; } return true; } /** * Get a reference to a subarray * * This variant of _subArray() does no is_array() checking, * so $root should be checked with _isSubArrayValid() first. * * This is here for performance reasons: * Passing a reference (i.e. $root) by-value (i.e. to is_array()) * creates a copy. If $root is an especially large array, this is expensive. * * @param array $root * @param string $path absolute path with / as component separator * @param bool $create optional * @access private * @return array|false */ private function &subArrayUnchecked(&$root, $path, $create = false) { $false = false; foreach (explode('/', $path) as $i) { if (!isset($root[$i])) { if (!$create) { return $false; } $root[$i] = []; } $root = &$root[$i]; } return $root; } /** * Get a reference to a subarray * * @param array $root * @param string $path absolute path with / as component separator * @param bool $create optional * @access private * @return array|false */ private function &subArray(&$root, $path, $create = false) { $false = false; if (!is_array($root)) { return $false; } foreach (explode('/', $path) as $i) { if (!is_array($root)) { return $false; } if (!isset($root[$i])) { if (!$create) { return $false; } $root[$i] = []; } $root = &$root[$i]; } return $root; } /** * Get a reference to an extension subarray * * @param array $root * @param string $path optional absolute path with / as component separator * @param bool $create optional * @access private * @return array|false */ private function &extensions(&$root, $path = null, $create = false) { if (!isset($root)) { $root = $this->currentCert; } switch (true) { case !empty($path): case !is_array($root): break; case isset($root['tbsCertificate']): $path = 'tbsCertificate/extensions'; break; case isset($root['tbsCertList']): $path = 'tbsCertList/crlExtensions'; break; case isset($root['certificationRequestInfo']): $pth = 'certificationRequestInfo/attributes'; $attributes = &$this->subArray($root, $pth, $create); if (is_array($attributes)) { foreach ($attributes as $key => $value) { if ($value['type'] == 'pkcs-9-at-extensionRequest') { $path = "$pth/$key/value/0"; break 2; } } if ($create) { $key = count($attributes); $attributes[] = ['type' => 'pkcs-9-at-extensionRequest', 'value' => []]; $path = "$pth/$key/value/0"; } } break; } $extensions = &$this->subArray($root, $path, $create); if (!is_array($extensions)) { $false = false; return $false; } return $extensions; } /** * Remove an Extension * * @param string $id * @param string $path optional * @access private * @return bool */ private function removeExtensionHelper($id, $path = null) { $extensions = &$this->extensions($this->currentCert, $path); if (!is_array($extensions)) { return false; } $result = false; foreach ($extensions as $key => $value) { if ($value['extnId'] == $id) { unset($extensions[$key]); $result = true; } } $extensions = array_values($extensions); // fix for https://bugs.php.net/75433 affecting PHP 7.2 if (!isset($extensions[0])) { $extensions = array_splice($extensions, 0, 0); } return $result; } /** * Get an Extension * * Returns the extension if it exists and false if not * * @param string $id * @param array $cert optional * @param string $path optional * @access private * @return mixed */ private function getExtensionHelper($id, $cert = null, $path = null) { $extensions = $this->extensions($cert, $path); if (!is_array($extensions)) { return false; } foreach ($extensions as $key => $value) { if ($value['extnId'] == $id) { return $value['extnValue']; } } return false; } /** * Returns a list of all extensions in use * * @param array $cert optional * @param string $path optional * @access private * @return array */ private function getExtensionsHelper($cert = null, $path = null) { $exts = $this->extensions($cert, $path); $extensions = []; if (is_array($exts)) { foreach ($exts as $extension) { $extensions[] = $extension['extnId']; } } return $extensions; } /** * Set an Extension * * @param string $id * @param mixed $value * @param bool $critical optional * @param bool $replace optional * @param string $path optional * @access private * @return bool */ private function setExtensionHelper($id, $value, $critical = false, $replace = true, $path = null) { $extensions = &$this->extensions($this->currentCert, $path, true); if (!is_array($extensions)) { return false; } $newext = ['extnId' => $id, 'critical' => $critical, 'extnValue' => $value]; foreach ($extensions as $key => $value) { if ($value['extnId'] == $id) { if (!$replace) { return false; } $extensions[$key] = $newext; return true; } } $extensions[] = $newext; return true; } /** * Remove a certificate, CSR or CRL Extension * * @param string $id * @access public * @return bool */ public function removeExtension($id) { return $this->removeExtensionHelper($id); } /** * Get a certificate, CSR or CRL Extension * * Returns the extension if it exists and false if not * * @param string $id * @param array $cert optional * @param string $path * @access public * @return mixed */ public function getExtension($id, $cert = null, $path=null) { return $this->getExtensionHelper($id, $cert, $path); } /** * Returns a list of all extensions in use in certificate, CSR or CRL * * @param array $cert optional * @param string $path optional * @access public * @return array */ public function getExtensions($cert = null, $path = null) { return $this->getExtensionsHelper($cert, $path); } /** * Set a certificate, CSR or CRL Extension * * @param string $id * @param mixed $value * @param bool $critical optional * @param bool $replace optional * @access public * @return bool */ public function setExtension($id, $value, $critical = false, $replace = true) { return $this->setExtensionHelper($id, $value, $critical, $replace); } /** * Remove a CSR attribute. * * @param string $id * @param int $disposition optional * @access public * @return bool */ public function removeAttribute($id, $disposition = self::ATTR_ALL) { $attributes = &$this->subArray($this->currentCert, 'certificationRequestInfo/attributes'); if (!is_array($attributes)) { return false; } $result = false; foreach ($attributes as $key => $attribute) { if ($attribute['type'] == $id) { $n = count($attribute['value']); switch (true) { case $disposition == self::ATTR_APPEND: case $disposition == self::ATTR_REPLACE: return false; case $disposition >= $n: $disposition -= $n; break; case $disposition == self::ATTR_ALL: case $n == 1: unset($attributes[$key]); $result = true; break; default: unset($attributes[$key]['value'][$disposition]); $attributes[$key]['value'] = array_values($attributes[$key]['value']); $result = true; break; } if ($result && $disposition != self::ATTR_ALL) { break; } } } $attributes = array_values($attributes); return $result; } /** * Get a CSR attribute * * Returns the attribute if it exists and false if not * * @param string $id * @param int $disposition optional * @param array $csr optional * @access public * @return mixed */ public function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null) { if (empty($csr)) { $csr = $this->currentCert; } $attributes = $this->subArray($csr, 'certificationRequestInfo/attributes'); if (!is_array($attributes)) { return false; } foreach ($attributes as $key => $attribute) { if ($attribute['type'] == $id) { $n = count($attribute['value']); switch (true) { case $disposition == self::ATTR_APPEND: case $disposition == self::ATTR_REPLACE: return false; case $disposition == self::ATTR_ALL: return $attribute['value']; case $disposition >= $n: $disposition -= $n; break; default: return $attribute['value'][$disposition]; } } } return false; } /** * Returns a list of all CSR attributes in use * * @param array $csr optional * @access public * @return array */ public function getAttributes($csr = null) { if (empty($csr)) { $csr = $this->currentCert; } $attributes = $this->subArray($csr, 'certificationRequestInfo/attributes'); $attrs = []; if (is_array($attributes)) { foreach ($attributes as $attribute) { $attrs[] = $attribute['type']; } } return $attrs; } /** * Set a CSR attribute * * @param string $id * @param mixed $value * @param int $disposition optional * @access public * @return bool */ public function setAttribute($id, $value, $disposition = self::ATTR_ALL) { $attributes = &$this->subArray($this->currentCert, 'certificationRequestInfo/attributes', true); if (!is_array($attributes)) { return false; } switch ($disposition) { case self::ATTR_REPLACE: $disposition = self::ATTR_APPEND; case self::ATTR_ALL: $this->removeAttribute($id); break; } foreach ($attributes as $key => $attribute) { if ($attribute['type'] == $id) { $n = count($attribute['value']); switch (true) { case $disposition == self::ATTR_APPEND: $last = $key; break; case $disposition >= $n: $disposition -= $n; break; default: $attributes[$key]['value'][$disposition] = $value; return true; } } } switch (true) { case $disposition >= 0: return false; case isset($last): $attributes[$last]['value'][] = $value; break; default: $attributes[] = ['type' => $id, 'value' => $disposition == self::ATTR_ALL ? $value: [$value]]; break; } return true; } /** * Sets the subject key identifier * * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions. * * @param string $value * @access public */ public function setKeyIdentifier($value) { if (empty($value)) { unset($this->currentKeyIdentifier); } else { $this->currentKeyIdentifier = $value; } } /** * Compute a public key identifier. * * Although key identifiers may be set to any unique value, this function * computes key identifiers from public key according to the two * recommended methods (4.2.1.2 RFC 3280). * Highly polymorphic: try to accept all possible forms of key: * - Key object * - \phpseclib\File\X509 object with public or private key defined * - Certificate or CSR array * - \phpseclib\File\ASN1\Element object * - PEM or DER string * * @param mixed $key optional * @param int $method optional * @access public * @return string binary key identifier */ public function computeKeyIdentifier($key = null, $method = 1) { if (is_null($key)) { $key = $this; } switch (true) { case is_string($key): break; case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']): return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method); case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']): return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method); case !is_object($key): return false; case $key instanceof Element: // Assume the element is a bitstring-packed key. $decoded = ASN1::decodeBER($key->element); if (empty($decoded)) { return false; } $raw = ASN1::asn1map($decoded[0], ['type' => ASN1::TYPE_BIT_STRING]); if (empty($raw)) { return false; } // If the key is private, compute identifier from its corresponding public key. $key = new RSA(); if (!$key->load($raw)) { return false; // Not an unencrypted RSA key. } if ($key->getPrivateKey() !== false) { // If private. return $this->computeKeyIdentifier($key, $method); } $key = $raw; // Is a public key. break; case $key instanceof X509: if (isset($key->publicKey)) { return $this->computeKeyIdentifier($key->publicKey, $method); } if (isset($key->privateKey)) { return $this->computeKeyIdentifier($key->privateKey, $method); } if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) { return $this->computeKeyIdentifier($key->currentCert, $method); } return false; default: // Should be a key object (i.e.: \phpseclib\Crypt\RSA). $key = $key->getPublicKey(); break; } // If in PEM format, convert to binary. $key = ASN1::extractBER($key); // Now we have the key string: compute its sha-1 sum. $hash = new Hash('sha1'); $hash = $hash->hash($key); if ($method == 2) { $hash = substr($hash, -8); $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40); } return $hash; } /** * Format a public key as appropriate * * @access private * @return array|bool */ private function formatSubjectPublicKey() { $publicKey = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey)); $decoded = ASN1::decodeBER($publicKey); $mapped = ASN1::asn1map($decoded[0], Maps\SubjectPublicKeyInfo::MAP); $mapped['subjectPublicKey'] = (string) $this->publicKey; return $mapped; } /** * Set the domain name's which the cert is to be valid for * * @param $domains[] * @access public * @return array */ public function setDomain(...$domains) { $this->domains = $domains; $this->removeDNProp('id-at-commonName'); $this->setDNProp('id-at-commonName', $this->domains[0]); } /** * Set the IP Addresses's which the cert is to be valid for * * @access public * @param $ipAddresses[] optional */ public function setIPAddress(...$ipAddresses) { $this->ipAddresses = $ipAddresses; /* if (!isset($this->domains)) { $this->removeDNProp('id-at-commonName'); $this->setDNProp('id-at-commonName', $this->ipAddresses[0]); } */ } /** * Helper function to build domain array * * @access private * @param string $domain * @return array */ private function dnsName($domain) { return ['dNSName' => $domain]; } /** * Helper function to build IP Address array * * (IPv6 is not currently supported) * * @access private * @param string $address * @return array */ private function iPAddress($address) { return ['iPAddress' => $address]; } /** * Get the index of a revoked certificate. * * @param array $rclist * @param string $serial * @param bool $create optional * @access private * @return int|false */ private function revokedCertificate(&$rclist, $serial, $create = false) { $serial = new BigInteger($serial); foreach ($rclist as $i => $rc) { if (!($serial->compare($rc['userCertificate']))) { return $i; } } if (!$create) { return false; } $i = count($rclist); $revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get())); $rclist[] = ['userCertificate' => $serial, 'revocationDate' => $this->timeField($revocationDate->format('D, d M Y H:i:s O'))]; return $i; } /** * Revoke a certificate. * * @param string $serial * @param string $date optional * @access public * @return bool */ public function revoke($serial, $date = null) { if (isset($this->currentCert['tbsCertList'])) { if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { if ($this->revokedCertificate($rclist, $serial) === false) { // If not yet revoked if (($i = $this->revokedCertificate($rclist, $serial, true)) !== false) { if (!empty($date)) { $rclist[$i]['revocationDate'] = $this->timeField($date); } return true; } } } } return false; } /** * Unrevoke a certificate. * * @param string $serial * @access public * @return bool */ public function unrevoke($serial) { if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { if (($i = $this->revokedCertificate($rclist, $serial)) !== false) { unset($rclist[$i]); $rclist = array_values($rclist); return true; } } return false; } /** * Get a revoked certificate. * * @param string $serial * @access public * @return mixed */ public function getRevoked($serial) { if (is_array($rclist = $this->subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { if (($i = $this->revokedCertificate($rclist, $serial)) !== false) { return $rclist[$i]; } } return false; } /** * List revoked certificates * * @param array $crl optional * @access public * @return array|bool */ public function listRevoked($crl = null) { if (!isset($crl)) { $crl = $this->currentCert; } if (!isset($crl['tbsCertList'])) { return false; } $result = []; if (is_array($rclist = $this->subArray($crl, 'tbsCertList/revokedCertificates'))) { foreach ($rclist as $rc) { $result[] = $rc['userCertificate']->toString(); } } return $result; } /** * Remove a Revoked Certificate Extension * * @param string $serial * @param string $id * @access public * @return bool */ public function removeRevokedCertificateExtension($serial, $id) { if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { if (($i = $this->revokedCertificate($rclist, $serial)) !== false) { return $this->removeExtensionHelper($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); } } return false; } /** * Get a Revoked Certificate Extension * * Returns the extension if it exists and false if not * * @param string $serial * @param string $id * @param array $crl optional * @access public * @return mixed */ public function getRevokedCertificateExtension($serial, $id, $crl = null) { if (!isset($crl)) { $crl = $this->currentCert; } if (is_array($rclist = $this->subArray($crl, 'tbsCertList/revokedCertificates'))) { if (($i = $this->revokedCertificate($rclist, $serial)) !== false) { return $this->getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); } } return false; } /** * Returns a list of all extensions in use for a given revoked certificate * * @param string $serial * @param array $crl optional * @access public * @return array|bool */ public function getRevokedCertificateExtensions($serial, $crl = null) { if (!isset($crl)) { $crl = $this->currentCert; } if (is_array($rclist = $this->subArray($crl, 'tbsCertList/revokedCertificates'))) { if (($i = $this->revokedCertificate($rclist, $serial)) !== false) { return $this->getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); } } return false; } /** * Set a Revoked Certificate Extension * * @param string $serial * @param string $id * @param mixed $value * @param bool $critical optional * @param bool $replace optional * @access public * @return bool */ public function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true) { if (isset($this->currentCert['tbsCertList'])) { if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { if (($i = $this->revokedCertificate($rclist, $serial, true)) !== false) { return $this->setExtensionHelper($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); } } } return false; } } <?php /** * Pure-PHP ANSI Decoder * * PHP version 5 * * If you call read() in \phpseclib\Net\SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back. * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what * color to display them in, etc. \phpseclib\File\ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator. * * @category File * @package ANSI * @author Jim Wigginton <terrafrost@php.net> * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File; /** * Pure-PHP ANSI Decoder * * @package ANSI * @author Jim Wigginton <terrafrost@php.net> * @access public */ class ANSI { /** * Max Width * * @var int * @access private */ private $max_x; /** * Max Height * * @var int * @access private */ private $max_y; /** * Max History * * @var int * @access private */ private $max_history; /** * History * * @var array * @access private */ private $history; /** * History Attributes * * @var array * @access private */ private $history_attrs; /** * Current Column * * @var int * @access private */ private $x; /** * Current Row * * @var int * @access private */ private $y; /** * Old Column * * @var int * @access private */ private $old_x; /** * Old Row * * @var int * @access private */ private $old_y; /** * An empty attribute cell * * @var object * @access private */ private $base_attr_cell; /** * The current attribute cell * * @var object * @access private */ private $attr_cell; /** * An empty attribute row * * @var array * @access private */ private $attr_row; /** * The current screen text * * @var array * @access private */ private $screen; /** * The current screen attributes * * @var array * @access private */ private $attrs; /** * Current ANSI code * * @var string * @access private */ private $ansi; /** * Tokenization * * @var array * @access private */ private $tokenization; /** * Default Constructor. * * @return \phpseclib\File\ANSI * @access public */ public function __construct() { $attr_cell = new \stdClass(); $attr_cell->bold = false; $attr_cell->underline = false; $attr_cell->blink = false; $attr_cell->background = 'black'; $attr_cell->foreground = 'white'; $attr_cell->reverse = false; $this->base_attr_cell = clone $attr_cell; $this->attr_cell = clone $attr_cell; $this->setHistory(200); $this->setDimensions(80, 24); } /** * Set terminal width and height * * Resets the screen as well * * @param int $x * @param int $y * @access public */ public function setDimensions($x, $y) { $this->max_x = $x - 1; $this->max_y = $y - 1; $this->x = $this->y = 0; $this->history = $this->history_attrs = []; $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell); $this->screen = array_fill(0, $this->max_y + 1, ''); $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row); $this->ansi = ''; } /** * Set the number of lines that should be logged past the terminal height * * @param int $history * @access public */ public function setHistory($history) { $this->max_history = $history; } /** * Load a string * * @param string $source * @access public */ public function loadString($source) { $this->setDimensions($this->max_x + 1, $this->max_y + 1); $this->appendString($source); } /** * Appdend a string * * @param string $source * @access public */ public function appendString($source) { $this->tokenization = ['']; for ($i = 0; $i < strlen($source); $i++) { if (strlen($this->ansi)) { $this->ansi.= $source[$i]; $chr = ord($source[$i]); // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements // single character CSI's not currently supported switch (true) { case $this->ansi == "\x1B=": $this->ansi = ''; continue 2; case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['): case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126: break; default: continue 2; } $this->tokenization[] = $this->ansi; $this->tokenization[] = ''; // http://ascii-table.com/ansi-escape-sequences-vt-100.php switch ($this->ansi) { case "\x1B[H": // Move cursor to upper left corner $this->old_x = $this->x; $this->old_y = $this->y; $this->x = $this->y = 0; break; case "\x1B[J": // Clear screen from cursor down $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y)); $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, '')); $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y)); $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row)); if (count($this->history) == $this->max_history) { array_shift($this->history); array_shift($this->history_attrs); } case "\x1B[K": // Clear screen from cursor right $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell)); break; case "\x1B[2K": // Clear entire line $this->screen[$this->y] = str_repeat(' ', $this->x); $this->attrs[$this->y] = $this->attr_row; break; case "\x1B[?1h": // set cursor key to application case "\x1B[?25h": // show the cursor case "\x1B(B": // set united states g0 character set break; case "\x1BE": // Move to next line $this->newLine(); $this->x = 0; break; default: switch (true) { case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines $this->old_y = $this->y; $this->y+= $match[1]; break; case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h $this->old_x = $this->x; $this->old_y = $this->y; $this->x = $match[2] - 1; $this->y = $match[1] - 1; break; case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines $this->old_x = $this->x; $this->x+= $match[1]; break; case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines $this->old_x = $this->x; $this->x-= $match[1]; if ($this->x < 0) { $this->x = 0; } break; case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window break; case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes $attr_cell = &$this->attr_cell; $mods = explode(';', $match[1]); foreach ($mods as $mod) { switch ($mod) { case 0: // Turn off character attributes $attr_cell = clone $this->base_attr_cell; break; case 1: // Turn bold mode on $attr_cell->bold = true; break; case 4: // Turn underline mode on $attr_cell->underline = true; break; case 5: // Turn blinking mode on $attr_cell->blink = true; break; case 7: // Turn reverse video on $attr_cell->reverse = !$attr_cell->reverse; $temp = $attr_cell->background; $attr_cell->background = $attr_cell->foreground; $attr_cell->foreground = $temp; break; default: // set colors //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground; $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' }; //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background; $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' }; switch ($mod) { // @codingStandardsIgnoreStart case 30: $front = 'black'; break; case 31: $front = 'red'; break; case 32: $front = 'green'; break; case 33: $front = 'yellow'; break; case 34: $front = 'blue'; break; case 35: $front = 'magenta'; break; case 36: $front = 'cyan'; break; case 37: $front = 'white'; break; case 40: $back = 'black'; break; case 41: $back = 'red'; break; case 42: $back = 'green'; break; case 43: $back = 'yellow'; break; case 44: $back = 'blue'; break; case 45: $back = 'magenta'; break; case 46: $back = 'cyan'; break; case 47: $back = 'white'; break; // @codingStandardsIgnoreEnd default: //user_error('Unsupported attribute: ' . $mod); $this->ansi = ''; break 2; } } } break; default: //user_error("{$this->ansi} is unsupported\r\n"); } } $this->ansi = ''; continue; } $this->tokenization[count($this->tokenization) - 1].= $source[$i]; switch ($source[$i]) { case "\r": $this->x = 0; break; case "\n": $this->newLine(); break; case "\x08": // backspace if ($this->x) { $this->x--; $this->attrs[$this->y][$this->x] = clone $this->base_attr_cell; $this->screen[$this->y] = substr_replace( $this->screen[$this->y], $source[$i], $this->x, 1 ); } break; case "\x0F": // shift break; case "\x1B": // start ANSI escape code $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1); //if (!strlen($this->tokenization[count($this->tokenization) - 1])) { // array_pop($this->tokenization); //} $this->ansi.= "\x1B"; break; default: $this->attrs[$this->y][$this->x] = clone $this->attr_cell; if ($this->x > strlen($this->screen[$this->y])) { $this->screen[$this->y] = str_repeat(' ', $this->x); } $this->screen[$this->y] = substr_replace( $this->screen[$this->y], $source[$i], $this->x, 1 ); if ($this->x > $this->max_x) { $this->x = 0; $this->newLine(); } else { $this->x++; } } } } /** * Add a new line * * Also update the $this->screen and $this->history buffers * * @access private */ private function newLine() { //if ($this->y < $this->max_y) { // $this->y++; //} while ($this->y >= $this->max_y) { $this->history = array_merge($this->history, [array_shift($this->screen)]); $this->screen[] = ''; $this->history_attrs = array_merge($this->history_attrs, [array_shift($this->attrs)]); $this->attrs[] = $this->attr_row; if (count($this->history) >= $this->max_history) { array_shift($this->history); array_shift($this->history_attrs); } $this->y--; } $this->y++; } /** * Returns the current coordinate without preformating * * @access private * @param \stdClass $last_attr * @param \stdClass $cur_attr * @param string $char * @return string */ private function processCoordinate($last_attr, $cur_attr, $char) { $output = ''; if ($last_attr != $cur_attr) { $close = $open = ''; if ($last_attr->foreground != $cur_attr->foreground) { if ($cur_attr->foreground != 'white') { $open.= '<span style="color: ' . $cur_attr->foreground . '">'; } if ($last_attr->foreground != 'white') { $close = '</span>' . $close; } } if ($last_attr->background != $cur_attr->background) { if ($cur_attr->background != 'black') { $open.= '<span style="background: ' . $cur_attr->background . '">'; } if ($last_attr->background != 'black') { $close = '</span>' . $close; } } if ($last_attr->bold != $cur_attr->bold) { if ($cur_attr->bold) { $open.= '<b>'; } else { $close = '</b>' . $close; } } if ($last_attr->underline != $cur_attr->underline) { if ($cur_attr->underline) { $open.= '<u>'; } else { $close = '</u>' . $close; } } if ($last_attr->blink != $cur_attr->blink) { if ($cur_attr->blink) { $open.= '<blink>'; } else { $close = '</blink>' . $close; } } $output.= $close . $open; } $output.= htmlspecialchars($char); return $output; } /** * Returns the current screen without preformating * * @access private * @return string */ private function getScreenHelper() { $output = ''; $last_attr = $this->base_attr_cell; for ($i = 0; $i <= $this->max_y; $i++) { for ($j = 0; $j <= $this->max_x; $j++) { $cur_attr = $this->attrs[$i][$j]; $output.= $this->processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : ''); $last_attr = $this->attrs[$i][$j]; } $output.= "\r\n"; } $output = substr($output, 0, -2); // close any remaining open tags $output.= $this->processCoordinate($last_attr, $this->base_attr_cell, ''); return rtrim($output); } /** * Returns the current screen * * @access public * @return string */ public function getScreen() { return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->getScreenHelper() . '</pre>'; } /** * Returns the current screen and the x previous lines * * @access public * @return string */ public function getHistory() { $scrollback = ''; $last_attr = $this->base_attr_cell; for ($i = 0; $i < count($this->history); $i++) { for ($j = 0; $j <= $this->max_x + 1; $j++) { $cur_attr = $this->history_attrs[$i][$j]; $scrollback.= $this->processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : ''); $last_attr = $this->history_attrs[$i][$j]; } $scrollback.= "\r\n"; } $base_attr_cell = $this->base_attr_cell; $this->base_attr_cell = $last_attr; $scrollback.= $this->getScreen(); $this->base_attr_cell = $base_attr_cell; return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>'; } } <?php /** * ASN.1 Raw Element * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1; /** * ASN.1 Raw Element * * An ASN.1 ANY mapping will return an ASN1\Element object. Use of this object * will also bypass the normal encoding rules in ASN1::encodeDER() * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Element { /** * Raw element value * * @var string * @access private */ public $element; /** * Constructor * * @param string $encoded * @return \phpseclib\File\ASN1\Element * @access public */ public function __construct($encoded) { $this->element = $encoded; } } <?php /** * OrganizationName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * OrganizationName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OrganizationName { const MAP = ['type' => ASN1::TYPE_PRINTABLE_STRING]; } <?php /** * PrivateDomainName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PrivateDomainName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PrivateDomainName { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'numeric' => ['type' => ASN1::TYPE_NUMERIC_STRING], 'printable' => ['type' => ASN1::TYPE_PRINTABLE_STRING] ] ]; } <?php /** * PBKDF2params * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PBKDF2params * * from https://tools.ietf.org/html/rfc2898#appendix-A.3 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PBKDF2params { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ // technically, this is a CHOICE in RFC2898 but the other "choice" is, currently, more of a placeholder // in the RFC 'salt'=> ['type' => ASN1::TYPE_OCTET_STRING], 'iterationCount'=> ['type' => ASN1::TYPE_INTEGER], 'keyLength' => [ 'type' => ASN1::TYPE_INTEGER, 'optional' => true ], 'prf' => AlgorithmIdentifier::MAP + ['optional' => true] ] ]; } <?php /** * GeneralName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * GeneralName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class GeneralName { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'otherName' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + AnotherName::MAP, 'rfc822Name' => [ 'type' => ASN1::TYPE_IA5_STRING, 'constant' => 1, 'optional' => true, 'implicit' => true ], 'dNSName' => [ 'type' => ASN1::TYPE_IA5_STRING, 'constant' => 2, 'optional' => true, 'implicit' => true ], 'x400Address' => [ 'constant' => 3, 'optional' => true, 'implicit' => true ] + ORAddress::MAP, 'directoryName' => [ 'constant' => 4, 'optional' => true, 'explicit' => true ] + Name::MAP, 'ediPartyName' => [ 'constant' => 5, 'optional' => true, 'implicit' => true ] + EDIPartyName::MAP, 'uniformResourceIdentifier' => [ 'type' => ASN1::TYPE_IA5_STRING, 'constant' => 6, 'optional' => true, 'implicit' => true ], 'iPAddress' => [ 'type' => ASN1::TYPE_OCTET_STRING, 'constant' => 7, 'optional' => true, 'implicit' => true ], 'registeredID' => [ 'type' => ASN1::TYPE_OBJECT_IDENTIFIER, 'constant' => 8, 'optional' => true, 'implicit' => true ] ] ]; } <?php /** * PBES2params * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PBES2params * * from https://tools.ietf.org/html/rfc2898#appendix-A.3 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PBES2params { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'keyDerivationFunc'=> AlgorithmIdentifier::MAP, 'encryptionScheme' => AlgorithmIdentifier::MAP ] ]; } <?php /** * RSAPrivateKey * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RSAPrivateKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RSAPrivateKey { // version must be multi if otherPrimeInfos present const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => ['two-prime', 'multi'] ], 'modulus' => ['type' => ASN1::TYPE_INTEGER], // n 'publicExponent' => ['type' => ASN1::TYPE_INTEGER], // e 'privateExponent' => ['type' => ASN1::TYPE_INTEGER], // d 'prime1' => ['type' => ASN1::TYPE_INTEGER], // p 'prime2' => ['type' => ASN1::TYPE_INTEGER], // q 'exponent1' => ['type' => ASN1::TYPE_INTEGER], // d mod (p-1) 'exponent2' => ['type' => ASN1::TYPE_INTEGER], // d mod (q-1) 'coefficient' => ['type' => ASN1::TYPE_INTEGER], // (inverse of q) mod p 'otherPrimeInfos' => OtherPrimeInfos::MAP + ['optional' => true] ] ]; } <?php /** * EDIPartyName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * EDIPartyName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class EDIPartyName { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'nameAssigner' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + DirectoryString::MAP, // partyName is technically required but \phpseclib\File\ASN1 doesn't currently support non-optional constants and // setting it to optional gets the job done in any event. 'partyName' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + DirectoryString::MAP ] ]; } <?php /** * SubjectDirectoryAttributes * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * SubjectDirectoryAttributes * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SubjectDirectoryAttributes { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => Attribute::MAP ]; } <?php /** * EcdsaSigValue * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * EcdsaSigValue * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class EcdsaSigValue { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'r' => ['type' => ASN1::TYPE_INTEGER], 's' => ['type' => ASN1::TYPE_INTEGER] ] ]; } <?php /** * UserNotice * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * UserNotice * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class UserNotice { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'noticeRef' => [ 'optional' => true, 'implicit' => true ] + NoticeReference::MAP, 'explicitText' => [ 'optional' => true, 'implicit' => true ] + DisplayText::MAP ] ]; } <?php /** * ECPoint * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ECPoint * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ECPoint { const MAP = ['type' => ASN1::TYPE_OCTET_STRING]; } <?php /** * PostalAddress * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PostalAddress * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PostalAddress { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'optional' => true, 'min' => 1, 'max' => -1, 'children' => DirectoryString::MAP ]; } <?php /** * ECParameters * * From: https://tools.ietf.org/html/rfc5915 * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ECParameters * * ECParameters ::= CHOICE { * namedCurve OBJECT IDENTIFIER * -- implicitCurve NULL * -- specifiedCurve SpecifiedECDomain * } * -- implicitCurve and specifiedCurve MUST NOT be used in PKIX. * -- Details for SpecifiedECDomain can be found in [X9.62]. * -- Any future additions to this CHOICE should be coordinated * -- with ANSI X9. * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ECParameters { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'namedCurve' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'implicitCurve' => ['type' => ASN1::TYPE_NULL], 'specifiedCurve' => SpecifiedECDomain::MAP ] ]; } <?php /** * NetworkAddress * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * NetworkAddress * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class NetworkAddress { const MAP = ['type' => ASN1::TYPE_NUMERIC_STRING]; } <?php /** * AlgorithmIdentifier * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AlgorithmIdentifier * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AlgorithmIdentifier { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'algorithm' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'parameters' => [ 'type' => ASN1::TYPE_ANY, 'optional' => true ] ] ]; } <?php /** * PolicyQualifierInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PolicyQualifierInfo * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PolicyQualifierInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'policyQualifierId' => PolicyQualifierId::MAP, 'qualifier' => ['type' => ASN1::TYPE_ANY] ] ]; } <?php /** * PublicKeyAndChallenge * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PublicKeyAndChallenge * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PublicKeyAndChallenge { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'spki' => SubjectPublicKeyInfo::MAP, 'challenge' => ['type' => ASN1::TYPE_IA5_STRING] ] ]; } <?php /** * PrivateKeyUsagePeriod * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PrivateKeyUsagePeriod * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PrivateKeyUsagePeriod { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'notBefore' => [ 'constant' => 0, 'optional' => true, 'implicit' => true, 'type' => ASN1::TYPE_GENERALIZED_TIME], 'notAfter' => [ 'constant' => 1, 'optional' => true, 'implicit' => true, 'type' => ASN1::TYPE_GENERALIZED_TIME] ] ]; } <?php /** * Name * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Name * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Name { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'rdnSequence' => RDNSequence::MAP ] ]; } <?php /** * NameConstraints * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * NameConstraints * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class NameConstraints { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'permittedSubtrees' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + GeneralSubtrees::MAP, 'excludedSubtrees' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + GeneralSubtrees::MAP ] ]; } <?php /** * Prime_p * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Prime_p * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Prime_p { const MAP = ['type' => ASN1::TYPE_INTEGER]; }<?php /** * DistributionPointName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DistributionPointName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DistributionPointName { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'fullName' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + GeneralNames::MAP, 'nameRelativeToCRLIssuer' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + RelativeDistinguishedName::MAP ] ]; } <?php /** * MaskGenAglorithm * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * MaskGenAglorithm * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class MaskGenAlgorithm { const MAP = AlgorithmIdentifier::MAP; }<?php /** * CertPolicyId * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertPolicyId * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertPolicyId { const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]; } <?php /** * FieldID * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * FieldID * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class FieldID { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'fieldType' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'parameters' => [ 'type' => ASN1::TYPE_ANY, 'optional' => true ] ] ]; }<?php /** * netscape_ca_policy_url * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * netscape_ca_policy_url * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class netscape_ca_policy_url { const MAP = ['type' => ASN1::TYPE_IA5_STRING]; } <?php /** * DssSigValue * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DssSigValue * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DssSigValue { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'r' => ['type' => ASN1::TYPE_INTEGER], 's' => ['type' => ASN1::TYPE_INTEGER] ] ]; } <?php /** * Time * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Time * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Time { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'utcTime' => ['type' => ASN1::TYPE_UTC_TIME], 'generalTime' => ['type' => ASN1::TYPE_GENERALIZED_TIME] ] ]; } <?php /** * netscape_cert_type * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * netscape_cert_type * * mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html> * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class netscape_cert_type { const MAP = [ 'type' => ASN1::TYPE_BIT_STRING, 'mapping' => [ 'SSLClient', 'SSLServer', 'Email', 'ObjectSigning', 'Reserved', 'SSLCA', 'EmailCA', 'ObjectSigningCA' ] ]; } <?php /** * Characteristic_two * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Characteristic_two * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Characteristic_two { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'm' => ['type' => ASN1::TYPE_INTEGER], // field size 2**m 'basis' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'parameters' => [ 'type' => ASN1::TYPE_ANY, 'optional' => true ] ] ]; }<?php /** * FieldElement * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * FieldElement * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class FieldElement { const MAP = ['type' => ASN1::TYPE_OCTET_STRING]; } <?php /** * SpecifiedECDomain * * From: http://www.secg.org/sec1-v2.pdf#page=109 * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * SpecifiedECDomain * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SpecifiedECDomain { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => [1 => 'ecdpVer1', 'ecdpVer2', 'ecdpVer3'] ], 'fieldID' => FieldID::MAP, 'curve' => Curve::MAP, 'base' => ECPoint::MAP, 'order' => ['type' => ASN1::TYPE_INTEGER], 'cofactor' => [ 'type' => ASN1::TYPE_INTEGER, 'optional' => true ], 'hash' => ['optional' => true] + HashAlgorithm::MAP ] ]; } <?php /** * PrivateKeyInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PrivateKeyInfo * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PrivateKeyInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => ['v1'] ], 'privateKeyAlgorithm'=> AlgorithmIdentifier::MAP, 'privateKey' => PrivateKey::MAP, 'attributes' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + Attributes::MAP ] ]; } <?php /** * PublicKeyInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PublicKeyInfo * * this format is not formally defined anywhere but is none-the-less the form you * get when you do "openssl rsa -in private.pem -outform PEM -pubout" * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PublicKeyInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'publicKeyAlgorithm'=> AlgorithmIdentifier::MAP, 'publicKey' => ['type' => ASN1::TYPE_BIT_STRING] ] ]; } <?php /** * Extensions * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Extensions * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Extensions { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, // technically, it's MAX, but we'll assume anything < 0 is MAX 'max' => -1, // if 'children' isn't an array then 'min' and 'max' must be defined 'children' => Extension::MAP ]; } <?php /** * Trinomial * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Trinomial * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Trinomial { const MAP = ['type' => ASN1::TYPE_INTEGER]; }<?php /** * AnotherName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AnotherName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AnotherName { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'type-id' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'value' => [ 'type' => ASN1::TYPE_ANY, 'constant' => 0, 'optional' => true, 'explicit' => true ] ] ]; } <?php /** * AttributeValue * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AttributeValue * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AttributeValue { const MAP = ['type' => ASN1::TYPE_ANY]; } <?php /** * DistributionPoint * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DistributionPoint * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DistributionPoint { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'distributionPoint' => [ 'constant' => 0, 'optional' => true, 'explicit' => true ] + DistributionPointName::MAP, 'reasons' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + ReasonFlags::MAP, 'cRLIssuer' => [ 'constant' => 2, 'optional' => true, 'implicit' => true ] + GeneralNames::MAP ] ]; } <?php /** * Attributes * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Attributes * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Attributes { const MAP = [ 'type' => ASN1::TYPE_SET, 'min' => 1, 'max' => -1, 'children' => Attribute::MAP ]; } <?php /** * NoticeReference * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * NoticeReference * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class NoticeReference { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'organization' => DisplayText::MAP, 'noticeNumbers' => [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => 200, 'children' => ['type' => ASN1::TYPE_INTEGER] ] ] ]; } <?php /** * TBSCertificate * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * TBSCertificate * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class TBSCertificate { // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm']) const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ // technically, default implies optional, but we'll define it as being optional, none-the-less, just to // reenforce that fact 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'constant' => 0, 'optional' => true, 'explicit' => true, 'mapping' => ['v1', 'v2', 'v3'], 'default' => 'v1' ], 'serialNumber' => CertificateSerialNumber::MAP, 'signature' => AlgorithmIdentifier::MAP, 'issuer' => Name::MAP, 'validity' => Validity::MAP, 'subject' => Name::MAP, 'subjectPublicKeyInfo' => SubjectPublicKeyInfo::MAP, // implicit means that the T in the TLV structure is to be rewritten, regardless of the type 'issuerUniqueID' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + UniqueIdentifier::MAP, 'subjectUniqueID' => [ 'constant' => 2, 'optional' => true, 'implicit' => true ] + UniqueIdentifier::MAP, // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if // it's not IMPLICIT, it's EXPLICIT 'extensions' => [ 'constant' => 3, 'optional' => true, 'explicit' => true ] + Extensions::MAP ] ]; } <?php /** * RevokedCertificate * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RevokedCertificate * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RevokedCertificate { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'userCertificate' => CertificateSerialNumber::MAP, 'revocationDate' => Time::MAP, 'crlEntryExtensions' => [ 'optional' => true ] + Extensions::MAP ] ]; } <?php /** * BuiltInDomainDefinedAttributes * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * BuiltInDomainDefinedAttributes * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class BuiltInDomainDefinedAttributes { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => 4, // ub-domain-defined-attributes 'children' => BuiltInDomainDefinedAttribute::MAP ]; } <?php /** * PrivateKey * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PrivateKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PrivateKey { const MAP = ['type' => ASN1::TYPE_OCTET_STRING]; } <?php /** * DisplayText * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DisplayText * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DisplayText { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'ia5String' => ['type' => ASN1::TYPE_IA5_STRING], 'visibleString' => ['type' => ASN1::TYPE_VISIBLE_STRING], 'bmpString' => ['type' => ASN1::TYPE_BMP_STRING], 'utf8String' => ['type' => ASN1::TYPE_UTF8_STRING] ] ]; } <?php /** * RelativeDistinguishedName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RelativeDistinguishedName * * In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare, * but they can be useful at times when either there is no unique attribute in the entry or you * want to ensure that the entry's DN contains some useful identifying information. * * - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RelativeDistinguishedName { const MAP = [ 'type' => ASN1::TYPE_SET, 'min' => 1, 'max' => -1, 'children' => AttributeTypeAndValue::MAP ]; } <?php /** * CRLDistributionPoints * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CRLDistributionPoints * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CRLDistributionPoints { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => DistributionPoint::MAP ]; } <?php /** * AuthorityKeyIdentifier * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AuthorityKeyIdentifier * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AuthorityKeyIdentifier { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'keyIdentifier' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + KeyIdentifier::MAP, 'authorityCertIssuer' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + GeneralNames::MAP, 'authorityCertSerialNumber' => [ 'constant' => 2, 'optional' => true, 'implicit' => true ] + CertificateSerialNumber::MAP ] ]; } <?php /** * CRLReason * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CRLReason * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CRLReason { const MAP = [ 'type' => ASN1::TYPE_ENUMERATED, 'mapping' => [ 'unspecified', 'keyCompromise', 'cACompromise', 'affiliationChanged', 'superseded', 'cessationOfOperation', 'certificateHold', // Value 7 is not used. 8 => 'removeFromCRL', 'privilegeWithdrawn', 'aACompromise' ] ]; } <?php /** * DigestInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DigestInfo * * from https://tools.ietf.org/html/rfc2898#appendix-A.3 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DigestInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'digestAlgorithm' => AlgorithmIdentifier::MAP, 'digest' => ['type' => ASN1::TYPE_OCTET_STRING] ] ]; } <?php /** * CertificatePolicies * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertificatePolicies * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertificatePolicies { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => PolicyInformation::MAP ]; } <?php /** * PolicyInformation * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PolicyInformation * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PolicyInformation { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'policyIdentifier' => CertPolicyId::MAP, 'policyQualifiers' => [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 0, 'max' => -1, 'optional' => true, 'children' => PolicyQualifierInfo::MAP ] ] ]; } <?php /** * BuiltInStandardAttributes * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * BuiltInStandardAttributes * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class BuiltInStandardAttributes { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'country-name' => ['optional' => true] + CountryName::MAP, 'administration-domain-name' => ['optional' => true] + AdministrationDomainName::MAP, 'network-address' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + NetworkAddress::MAP, 'terminal-identifier' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + TerminalIdentifier::MAP, 'private-domain-name' => [ 'constant' => 2, 'optional' => true, 'explicit' => true ] + PrivateDomainName::MAP, 'organization-name' => [ 'constant' => 3, 'optional' => true, 'implicit' => true ] + OrganizationName::MAP, 'numeric-user-identifier' => [ 'constant' => 4, 'optional' => true, 'implicit' => true ] + NumericUserIdentifier::MAP, 'personal-name' => [ 'constant' => 5, 'optional' => true, 'implicit' => true ] + PersonalName::MAP, 'organizational-unit-names' => [ 'constant' => 6, 'optional' => true, 'implicit' => true ] + OrganizationalUnitNames::MAP ] ]; } <?php /** * SignedPublicKeyAndChallenge * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * SignedPublicKeyAndChallenge * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SignedPublicKeyAndChallenge { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'publicKeyAndChallenge' => PublicKeyAndChallenge::MAP, 'signatureAlgorithm' => AlgorithmIdentifier::MAP, 'signature' => ['type' => ASN1::TYPE_BIT_STRING] ] ]; } <?php /** * EncryptedPrivateKeyInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * EncryptedPrivateKeyInfo * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class EncryptedPrivateKeyInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'encryptionAlgorithm' => AlgorithmIdentifier::MAP, 'encryptedData' => EncryptedData::MAP ] ]; } <?php /** * CRLNumber * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CRLNumber * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CRLNumber { const MAP = ['type' => ASN1::TYPE_INTEGER]; } <?php /** * Curve * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Curve * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Curve { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'a' => FieldElement::MAP, 'b' => FieldElement::MAP, 'seed' => [ 'type' => ASN1::TYPE_BIT_STRING, 'optional' => true ] ] ]; } <?php /** * RSASSA_PSS_params * * As defined in https://tools.ietf.org/html/rfc4055#section-3.1 * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RSASSA_PSS_params * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RSASSA_PSS_params { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'hashAlgorithm' => [ 'constant' => 0, 'optional' => true, 'explicit' => true, //'default' => 'sha1Identifier' ] + HashAlgorithm::MAP, 'maskGenAlgorithm' => [ 'constant' => 1, 'optional' => true, 'explicit' => true, //'default' => 'mgf1SHA1Identifier' ] + MaskGenAlgorithm::MAP, 'saltLength' => [ 'type' => ASN1::TYPE_INTEGER, 'constant' => 2, 'optional' => true, 'explicit' => true, 'default' => 20 ], 'trailerField' => [ 'type' => ASN1::TYPE_INTEGER, 'constant' => 3, 'optional' => true, 'explicit' => true, 'default' => 1 ] ] ]; } <?php /** * NumericUserIdentifier * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * NumericUserIdentifier * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class NumericUserIdentifier { const MAP = ['type' => ASN1::TYPE_NUMERIC_STRING]; } <?php /** * ExtensionAttributes * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ExtensionAttributes * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ExtensionAttributes { const MAP = [ 'type' => ASN1::TYPE_SET, 'min' => 1, 'max' => 256, // ub-extension-attributes 'children' => ExtensionAttribute::MAP ]; } <?php /** * PKCS9String * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PKCS9String * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PKCS9String { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'ia5String' => ['type' => ASN1::TYPE_IA5_STRING], 'directoryString' => DirectoryString::MAP ] ]; } <?php /** * PolicyMappings * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PolicyMappings * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PolicyMappings { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'issuerDomainPolicy' => CertPolicyId::MAP, 'subjectDomainPolicy' => CertPolicyId::MAP ] ] ]; } <?php /** * CertificateList * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertificateList * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertificateList { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'tbsCertList' => TBSCertList::MAP, 'signatureAlgorithm' => AlgorithmIdentifier::MAP, 'signature' => ['type' => ASN1::TYPE_BIT_STRING] ] ]; } <?php /** * CertificationRequest * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertificationRequest * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertificationRequest { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'certificationRequestInfo' => CertificationRequestInfo::MAP, 'signatureAlgorithm' => AlgorithmIdentifier::MAP, 'signature' => ['type' => ASN1::TYPE_BIT_STRING] ] ]; } <?php /** * KeyUsage * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * KeyUsage * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class KeyUsage { const MAP = [ 'type' => ASN1::TYPE_BIT_STRING, 'mapping' => [ 'digitalSignature', 'nonRepudiation', 'keyEncipherment', 'dataEncipherment', 'keyAgreement', 'keyCertSign', 'cRLSign', 'encipherOnly', 'decipherOnly' ] ]; } <?php /** * ECPrivateKey * * From: https://tools.ietf.org/html/rfc5915 * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ECPrivateKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ECPrivateKey { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => [1 => 'ecPrivkeyVer1'] ], 'privateKey' => ['type' => ASN1::TYPE_OCTET_STRING], 'parameters' => [ 'constant' => 0, 'optional' => true, 'explicit' => true ] + ECParameters::MAP, 'publicKey' => [ 'type' => ASN1::TYPE_BIT_STRING, 'constant' => 1, 'optional' => true, 'explicit' => true ] ] ]; } <?php /** * ExtensionAttribute * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ExtensionAttribute * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ExtensionAttribute { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'extension-attribute-type' => [ 'type' => ASN1::TYPE_PRINTABLE_STRING, 'constant' => 0, 'optional' => true, 'implicit' => true ], 'extension-attribute-value' => [ 'type' => ASN1::TYPE_ANY, 'constant' => 1, 'optional' => true, 'explicit' => true ] ] ]; } <?php /** * ExtKeyUsageSyntax * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ExtKeyUsageSyntax * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ExtKeyUsageSyntax { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => KeyPurposeId::MAP ]; } <?php /** * CertificateSerialNumber * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertificateSerialNumber * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertificateSerialNumber { const MAP = ['type' => ASN1::TYPE_INTEGER]; } <?php /** * DirectoryString * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DirectoryString * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DirectoryString { const MAP = [ 'type' => ASN1::TYPE_CHOICE, 'children' => [ 'teletexString' => ['type' => ASN1::TYPE_TELETEX_STRING], 'printableString' => ['type' => ASN1::TYPE_PRINTABLE_STRING], 'universalString' => ['type' => ASN1::TYPE_UNIVERSAL_STRING], 'utf8String' => ['type' => ASN1::TYPE_UTF8_STRING], 'bmpString' => ['type' => ASN1::TYPE_BMP_STRING] ] ]; } <?php /** * Certificate * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Certificate * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Certificate { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'tbsCertificate' => TBSCertificate::MAP, 'signatureAlgorithm' => AlgorithmIdentifier::MAP, 'signature' => ['type' => ASN1::TYPE_BIT_STRING] ] ]; } <?php /** * EncryptedData * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * EncryptedData * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class EncryptedData { const MAP = ['type' => ASN1::TYPE_OCTET_STRING]; } <?php /** * HoldInstructionCode * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * HoldInstructionCode * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class HoldInstructionCode { const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]; } <?php /** * OtherPrimeInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * OtherPrimeInfo * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OtherPrimeInfo { // version must be multi if otherPrimeInfos present const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'prime' => ['type' => ASN1::TYPE_INTEGER], // ri 'exponent' => ['type' => ASN1::TYPE_INTEGER], // di 'coefficient' => ['type' => ASN1::TYPE_INTEGER] // ti ] ]; } <?php /** * RSAPublicKey * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RSAPublicKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RSAPublicKey { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'modulus' => ['type' => ASN1::TYPE_INTEGER], 'publicExponent' => ['type' => ASN1::TYPE_INTEGER] ] ]; } <?php /** * PBEParameter * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PBEParameter * * from https://tools.ietf.org/html/rfc2898#appendix-A.3 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PBEParameter { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'salt' => ['type' => ASN1::TYPE_OCTET_STRING], 'iterationCount' => ['type' => ASN1::TYPE_INTEGER] ] ]; } <?php /** * TBSCertList * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * TBSCertList * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class TBSCertList { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => ['v1', 'v2', 'v3'], 'optional' => true, 'default' => 'v2' ], 'signature' => AlgorithmIdentifier::MAP, 'issuer' => Name::MAP, 'thisUpdate' => Time::MAP, 'nextUpdate' => [ 'optional' => true ] + Time::MAP, 'revokedCertificates' => [ 'type' => ASN1::TYPE_SEQUENCE, 'optional' => true, 'min' => 0, 'max' => -1, 'children' => RevokedCertificate::MAP ], 'crlExtensions' => [ 'constant' => 0, 'optional' => true, 'explicit' => true ] + Extensions::MAP ] ]; } <?php /** * BaseDistance * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * BaseDistance * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class BaseDistance { const MAP = ['type' => ASN1::TYPE_INTEGER]; } <?php /** * Pentanomial * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Pentanomial * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Pentanomial { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'k1' => ['type' => ASN1::TYPE_INTEGER], // k1 > 0 'k2' => ['type' => ASN1::TYPE_INTEGER], // k2 > k1 'k3' => ['type' => ASN1::TYPE_INTEGER], // k3 > h2 ] ]; }<?php /** * GeneralSubtrees * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * GeneralSubtrees * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class GeneralSubtrees { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => GeneralSubtree::MAP ]; } <?php /** * DSAParams * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DSAParams * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DSAParams { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'p' => ['type' => ASN1::TYPE_INTEGER], 'q' => ['type' => ASN1::TYPE_INTEGER], 'g' => ['type' => ASN1::TYPE_INTEGER] ] ]; } <?php /** * OtherPrimeInfos * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * OtherPrimeInfos * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OtherPrimeInfos { // version must be multi if otherPrimeInfos present const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => OtherPrimeInfo::MAP ]; } <?php /** * ReasonFlags * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ReasonFlags * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ReasonFlags { const MAP = [ 'type' => ASN1::TYPE_BIT_STRING, 'mapping' => [ 'unused', 'keyCompromise', 'cACompromise', 'affiliationChanged', 'superseded', 'cessationOfOperation', 'certificateHold', 'privilegeWithdrawn', 'aACompromise' ] ]; } <?php /** * Validity * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Validity * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Validity { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'notBefore' => Time::MAP, 'notAfter' => Time::MAP ] ]; } <?php /** * AuthorityInfoAccessSyntax * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AuthorityInfoAccessSyntax * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AuthorityInfoAccessSyntax { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => AccessDescription::MAP ]; } <?php /** * AccessDescription * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AccessDescription * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AccessDescription { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'accessMethod' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'accessLocation' => GeneralName::MAP ] ]; } <?php /** * DSAPublicKey * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DSAPublicKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DSAPublicKey { const MAP = ['type' => ASN1::TYPE_INTEGER]; } <?php /** * OrganizationalUnitNames * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * OrganizationalUnitNames * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OrganizationalUnitNames { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => 4, // ub-organizational-units 'children' => ['type' => ASN1::TYPE_PRINTABLE_STRING] ]; } <?php /** * AdministrationDomainName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AdministrationDomainName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AdministrationDomainName { const MAP = [ 'type' => ASN1::TYPE_CHOICE, // if class isn't present it's assumed to be \phpseclib\File\ASN1::CLASS_UNIVERSAL or // (if constant is present) \phpseclib\File\ASN1::CLASS_CONTEXT_SPECIFIC 'class' => ASN1::CLASS_APPLICATION, 'cast' => 2, 'children' => [ 'numeric' => ['type' => ASN1::TYPE_NUMERIC_STRING], 'printable' => ['type' => ASN1::TYPE_PRINTABLE_STRING] ] ]; } <?php /** * ORAddress * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * ORAddress * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ORAddress { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'built-in-standard-attributes' => BuiltInStandardAttributes::MAP, 'built-in-domain-defined-attributes' => ['optional' => true] + BuiltInDomainDefinedAttributes::MAP, 'extension-attributes' => ['optional' => true] + ExtensionAttributes::MAP ] ]; } <?php /** * BuiltInDomainDefinedAttribute * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * BuiltInDomainDefinedAttribute * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class BuiltInDomainDefinedAttribute { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'type' => ['type' => ASN1::TYPE_PRINTABLE_STRING], 'value' => ['type' => ASN1::TYPE_PRINTABLE_STRING] ] ]; } <?php /** * PolicyQualifierId * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PolicyQualifierId * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PolicyQualifierId { const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]; } <?php /** * Extension * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Extension * * A certificate using system MUST reject the certificate if it encounters * a critical extension it does not recognize; however, a non-critical * extension may be ignored if it is not recognized. * * http://tools.ietf.org/html/rfc5280#section-4.2 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Extension { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'extnId' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'critical' => [ 'type' => ASN1::TYPE_BOOLEAN, 'optional' => true, 'default' => false ], 'extnValue' => ['type' => ASN1::TYPE_OCTET_STRING] ] ]; } <?php /** * BasicConstraints * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * BasicConstraints * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class BasicConstraints { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'cA' => [ 'type' => ASN1::TYPE_BOOLEAN, 'optional' => true, 'default' => false ], 'pathLenConstraint' => [ 'type' => ASN1::TYPE_INTEGER, 'optional' => true ] ] ]; } <?php /** * SubjectAltName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * SubjectAltName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SubjectAltName { const MAP = GeneralNames::MAP; } <?php /** * AttributeTypeAndValue * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AttributeTypeAndValue * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AttributeTypeAndValue { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'type' => AttributeType::MAP, 'value'=> AttributeValue::MAP ] ]; } <?php /** * CertificateIssuer * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertificateIssuer * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertificateIssuer { const MAP = GeneralNames::MAP; } <?php /** * HashAglorithm * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * HashAglorithm * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class HashAlgorithm { const MAP = AlgorithmIdentifier::MAP; }<?php /** * AttributeType * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * AttributeType * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class AttributeType { const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]; } <?php /** * GeneralSubtree * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * GeneralSubtree * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class GeneralSubtree { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'base' => GeneralName::MAP, 'minimum' => [ 'constant' => 0, 'optional' => true, 'implicit' => true, 'default' => '0' ] + BaseDistance::MAP, 'maximum' => [ 'constant' => 1, 'optional' => true, 'implicit' => true, ] + BaseDistance::MAP ] ]; } <?php /** * InvalidityDate * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * InvalidityDate * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class InvalidityDate { const MAP = ['type' => ASN1::TYPE_GENERALIZED_TIME]; } <?php /** * TerminalIdentifier * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * TerminalIdentifier * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class TerminalIdentifier { const MAP = ['type' => ASN1::TYPE_PRINTABLE_STRING]; } <?php /** * RC2CBCParameter * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RC2CBCParameter * * from https://tools.ietf.org/html/rfc2898#appendix-A.3 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RC2CBCParameter { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'rc2ParametersVersion'=> [ 'type' => ASN1::TYPE_INTEGER, 'optional' => true ], 'iv'=> ['type' => ASN1::TYPE_OCTET_STRING] ] ]; } <?php /** * KeyPurposeId * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * KeyPurposeId * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class KeyPurposeId { const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]; } <?php /** * IssuingDistributionPoint * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * IssuingDistributionPoint * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class IssuingDistributionPoint { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'distributionPoint' => [ 'constant' => 0, 'optional' => true, 'explicit' => true ] + DistributionPointName::MAP, 'onlyContainsUserCerts' => [ 'type' => ASN1::TYPE_BOOLEAN, 'constant' => 1, 'optional' => true, 'default' => false, 'implicit' => true ], 'onlyContainsCACerts' => [ 'type' => ASN1::TYPE_BOOLEAN, 'constant' => 2, 'optional' => true, 'default' => false, 'implicit' => true ], 'onlySomeReasons' => [ 'constant' => 3, 'optional' => true, 'implicit' => true ] + ReasonFlags::MAP, 'indirectCRL' => [ 'type' => ASN1::TYPE_BOOLEAN, 'constant' => 4, 'optional' => true, 'default' => false, 'implicit' => true ], 'onlyContainsAttributeCerts' =>[ 'type' => ASN1::TYPE_BOOLEAN, 'constant' => 5, 'optional' => true, 'default' => false, 'implicit' => true ] ] ]; } <?php /** * CertificationRequestInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CertificationRequestInfo * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CertificationRequestInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => ['v1'] ], 'subject' => Name::MAP, 'subjectPKInfo' => SubjectPublicKeyInfo::MAP, 'attributes' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + Attributes::MAP, ] ]; } <?php /** * GeneralNames * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * GeneralNames * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class GeneralNames { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'min' => 1, 'max' => -1, 'children' => GeneralName::MAP ]; } <?php /** * PublicKey * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PublicKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PublicKey { const MAP = ['type' => ASN1::TYPE_BIT_STRING]; } <?php /** * PersonalName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PersonalName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PersonalName { const MAP = [ 'type' => ASN1::TYPE_SET, 'children' => [ 'surname' => [ 'type' => ASN1::TYPE_PRINTABLE_STRING, 'constant' => 0, 'optional' => true, 'implicit' => true ], 'given-name' => [ 'type' => ASN1::TYPE_PRINTABLE_STRING, 'constant' => 1, 'optional' => true, 'implicit' => true ], 'initials' => [ 'type' => ASN1::TYPE_PRINTABLE_STRING, 'constant' => 2, 'optional' => true, 'implicit' => true ], 'generation-qualifier' => [ 'type' => ASN1::TYPE_PRINTABLE_STRING, 'constant' => 3, 'optional' => true, 'implicit' => true ] ] ]; } <?php /** * RDNSequence * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * RDNSequence * * In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare, * but they can be useful at times when either there is no unique attribute in the entry or you * want to ensure that the entry's DN contains some useful identifying information. * * - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class RDNSequence { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, // RDNSequence does not define a min or a max, which means it doesn't have one 'min' => 0, 'max' => -1, 'children' => RelativeDistinguishedName::MAP ]; } <?php /** * OneAsymmetricKey * * See https://tools.ietf.org/html/rfc5958 * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * OneAsymmetricKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class OneAsymmetricKey { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => [ 'type' => ASN1::TYPE_INTEGER, 'mapping' => ['v1', 'v2'] ], 'privateKeyAlgorithm'=> AlgorithmIdentifier::MAP, 'privateKey' => PrivateKey::MAP, 'attributes' => [ 'constant' => 0, 'optional' => true, 'implicit' => true ] + Attributes::MAP, 'publicKey' => [ 'constant' => 1, 'optional' => true, 'implicit' => true ] + PublicKey::MAP ] ]; } <?php /** * SubjectPublicKeyInfo * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * SubjectPublicKeyInfo * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class SubjectPublicKeyInfo { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'algorithm' => AlgorithmIdentifier::MAP, 'subjectPublicKey' => ['type' => ASN1::TYPE_BIT_STRING] ] ]; } <?php /** * netscape_comment * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * netscape_comment * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class netscape_comment { const MAP = ['type' => ASN1::TYPE_IA5_STRING]; } <?php /** * CPSuri * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CPSuri * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CPSuri { const MAP = ['type' => ASN1::TYPE_IA5_STRING]; } <?php /** * UniqueIdentifier * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * UniqueIdentifier * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class UniqueIdentifier { const MAP = ['type' => ASN1::TYPE_BIT_STRING]; } <?php /** * KeyIdentifier * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * KeyIdentifier * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class KeyIdentifier { const MAP = ['type' => ASN1::TYPE_OCTET_STRING]; } <?php /** * IssuerAltName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * IssuerAltName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class IssuerAltName { const MAP = GeneralNames::MAP; } <?php /** * CountryName * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * CountryName * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class CountryName { const MAP = [ 'type' => ASN1::TYPE_CHOICE, // if class isn't present it's assumed to be \phpseclib\File\ASN1::CLASS_UNIVERSAL or // (if constant is present) \phpseclib\File\ASN1::CLASS_CONTEXT_SPECIFIC 'class' => ASN1::CLASS_APPLICATION, 'cast' => 1, 'children' => [ 'x121-dcc-code' => ['type' => ASN1::TYPE_NUMERIC_STRING], 'iso-3166-alpha2-code' => ['type' => ASN1::TYPE_PRINTABLE_STRING] ] ]; } <?php /** * Attribute * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * Attribute * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class Attribute { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'type' => AttributeType::MAP, 'value'=> [ 'type' => ASN1::TYPE_SET, 'min' => 1, 'max' => -1, 'children' => AttributeValue::MAP ] ] ]; } <?php /** * DSAPrivateKey * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * DSAPrivateKey * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class DSAPrivateKey { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'version' => ['type' => ASN1::TYPE_INTEGER], 'p' => ['type' => ASN1::TYPE_INTEGER], 'q' => ['type' => ASN1::TYPE_INTEGER], 'g' => ['type' => ASN1::TYPE_INTEGER], 'y' => ['type' => ASN1::TYPE_INTEGER], 'x' => ['type' => ASN1::TYPE_INTEGER] ] ]; }<?php /** * PBMAC1params * * PHP version 5 * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2016 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File\ASN1\Maps; use phpseclib\File\ASN1; /** * PBMAC1params * * from https://tools.ietf.org/html/rfc2898#appendix-A.3 * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class PBMAC1params { const MAP = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'keyDerivationFunc'=> AlgorithmIdentifier::MAP, 'messageAuthScheme'=> AlgorithmIdentifier::MAP ] ]; } <?php /** * Pure-PHP ASN.1 Parser * * PHP version 5 * * ASN.1 provides the semantics for data encoded using various schemes. The most commonly * utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded * DER blobs. * * \phpseclib\File\ASN1 decodes and encodes DER formatted messages and places them in a semantic context. * * Uses the 1988 ASN.1 syntax. * * @category File * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2012 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\File; use ParagonIE\ConstantTime\Base64; use phpseclib\File\ASN1\Element; use phpseclib\Math\BigInteger; use phpseclib\Common\Functions\Strings; use DateTime; use DateTimeZone; /** * Pure-PHP ASN.1 Parser * * @package ASN1 * @author Jim Wigginton <terrafrost@php.net> * @access public */ abstract class ASN1 { /**#@+ * Tag Classes * * @access private * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12 */ const CLASS_UNIVERSAL = 0; const CLASS_APPLICATION = 1; const CLASS_CONTEXT_SPECIFIC = 2; const CLASS_PRIVATE = 3; /**#@-*/ /**#@+ * Tag Classes * * @access private * @link http://www.obj-sys.com/asn1tutorial/node124.html */ const TYPE_BOOLEAN = 1; const TYPE_INTEGER = 2; const TYPE_BIT_STRING = 3; const TYPE_OCTET_STRING = 4; const TYPE_NULL = 5; const TYPE_OBJECT_IDENTIFIER = 6; //const TYPE_OBJECT_DESCRIPTOR = 7; //const TYPE_INSTANCE_OF = 8; // EXTERNAL const TYPE_REAL = 9; const TYPE_ENUMERATED = 10; //const TYPE_EMBEDDED = 11; const TYPE_UTF8_STRING = 12; //const TYPE_RELATIVE_OID = 13; const TYPE_SEQUENCE = 16; // SEQUENCE OF const TYPE_SET = 17; // SET OF /**#@-*/ /**#@+ * More Tag Classes * * @access private * @link http://www.obj-sys.com/asn1tutorial/node10.html */ const TYPE_NUMERIC_STRING = 18; const TYPE_PRINTABLE_STRING = 19; const TYPE_TELETEX_STRING = 20; // T61String const TYPE_VIDEOTEX_STRING = 21; const TYPE_IA5_STRING = 22; const TYPE_UTC_TIME = 23; const TYPE_GENERALIZED_TIME = 24; const TYPE_GRAPHIC_STRING = 25; const TYPE_VISIBLE_STRING = 26; // ISO646String const TYPE_GENERAL_STRING = 27; const TYPE_UNIVERSAL_STRING = 28; //const TYPE_CHARACTER_STRING = 29; const TYPE_BMP_STRING = 30; /**#@-*/ /**#@+ * Tag Aliases * * These tags are kinda place holders for other tags. * * @access private */ const TYPE_CHOICE = -1; const TYPE_ANY = -2; /**#@-*/ /** * ASN.1 object identifiers * * @var array * @access private * @link http://en.wikipedia.org/wiki/Object_identifier */ private static $oids = []; /** * ASN.1 object identifier reverse mapping * * @var array * @access private */ private static $reverseOIDs = []; /** * Default date format * * @var string * @access private * @link http://php.net/class.datetime */ private static $format = 'D, d M Y H:i:s O'; /** * Filters * * If the mapping type is self::TYPE_ANY what do we actually encode it as? * * @var array * @access private * @see self::encode_der() */ private static $filters; /** * Current Location of most recent ASN.1 encode process * * Useful for debug purposes * * @var array * @access private * @see self::encode_der() */ private static $location; /** * DER Encoded String * * In case we need to create ASN1\Element object's.. * * @var string * @access private * @see self::decodeDER() */ private static $encoded; /** * Type mapping table for the ANY type. * * Structured or unknown types are mapped to a \phpseclib\File\ASN1\Element. * Unambiguous types get the direct mapping (int/real/bool). * Others are mapped as a choice, with an extra indexing level. * * @var array * @access public */ const ANY_MAP = [ self::TYPE_BOOLEAN => true, self::TYPE_INTEGER => true, self::TYPE_BIT_STRING => 'bitString', self::TYPE_OCTET_STRING => 'octetString', self::TYPE_NULL => 'null', self::TYPE_OBJECT_IDENTIFIER => 'objectIdentifier', self::TYPE_REAL => true, self::TYPE_ENUMERATED => 'enumerated', self::TYPE_UTF8_STRING => 'utf8String', self::TYPE_NUMERIC_STRING => 'numericString', self::TYPE_PRINTABLE_STRING => 'printableString', self::TYPE_TELETEX_STRING => 'teletexString', self::TYPE_VIDEOTEX_STRING => 'videotexString', self::TYPE_IA5_STRING => 'ia5String', self::TYPE_UTC_TIME => 'utcTime', self::TYPE_GENERALIZED_TIME => 'generalTime', self::TYPE_GRAPHIC_STRING => 'graphicString', self::TYPE_VISIBLE_STRING => 'visibleString', self::TYPE_GENERAL_STRING => 'generalString', self::TYPE_UNIVERSAL_STRING => 'universalString', //self::TYPE_CHARACTER_STRING => 'characterString', self::TYPE_BMP_STRING => 'bmpString' ]; /** * String type to character size mapping table. * * Non-convertable types are absent from this table. * size == 0 indicates variable length encoding. * * @var array * @access public */ const STRING_TYPE_SIZE = [ self::TYPE_UTF8_STRING => 0, self::TYPE_BMP_STRING => 2, self::TYPE_UNIVERSAL_STRING => 4, self::TYPE_PRINTABLE_STRING => 1, self::TYPE_TELETEX_STRING => 1, self::TYPE_IA5_STRING => 1, self::TYPE_VISIBLE_STRING => 1, ]; /** * Parse BER-encoding * * Serves a similar purpose to openssl's asn1parse * * @param string $encoded * @return array * @access public */ public static function decodeBER($encoded) { if ($encoded instanceof Element) { $encoded = $encoded->element; } self::$encoded = $encoded; $decoded = [self::decode_ber($encoded)]; // encapsulate in an array for BC with the old decodeBER return $decoded; } /** * Parse BER-encoding (Helper function) * * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode. * $encoded is passed by reference for the recursive calls done for self::TYPE_BIT_STRING and * self::TYPE_OCTET_STRING. In those cases, the indefinite length is used. * * @param string $encoded * @param int $start * @param int $encoded_pos * @return array|bool * @access private */ private static function decode_ber($encoded, $start = 0, $encoded_pos = 0) { $current = ['start' => $start]; $type = ord($encoded[$encoded_pos++]); $start++; $constructed = ($type >> 5) & 1; $tag = $type & 0x1F; if ($tag == 0x1F) { $tag = 0; // process septets (since the eighth bit is ignored, it's not an octet) do { $temp = ord($encoded[$encoded_pos++]); $loop = $temp >> 7; $tag <<= 7; $tag |= $temp & 0x7F; $start++; } while ($loop); } // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 $length = ord($encoded[$encoded_pos++]); $start++; if ($length == 0x80) { // indefinite length // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all // immediately available." -- paragraph 8.1.3.2.c $length = strlen($encoded) - $encoded_pos; } elseif ($length & 0x80) { // definite length, long form // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only // support it up to four. $length&= 0x7F; $temp = substr($encoded, $encoded_pos, $length); $encoded_pos += $length; // tags of indefinte length don't really have a header length; this length includes the tag $current+= ['headerlength' => $length + 2]; $start+= $length; extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); /** @var integer $length */ } else { $current+= ['headerlength' => 2]; } if ($length > (strlen($encoded) - $encoded_pos)) { return false; } $content = substr($encoded, $encoded_pos, $length); $content_pos = 0; // at this point $length can be overwritten. it's only accurate for definite length things as is /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1 built-in types. It defines an application-independent data type that must be distinguishable from all other data types. The other three classes are user defined. The APPLICATION class distinguishes data types that have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this data type; the term CONTEXT-SPECIFIC does not appear. -- http://www.obj-sys.com/asn1tutorial/node12.html */ $class = ($type >> 6) & 3; switch ($class) { case self::CLASS_APPLICATION: case self::CLASS_PRIVATE: case self::CLASS_CONTEXT_SPECIFIC: if (!$constructed) { return [ 'type' => $class, 'constant' => $tag, 'content' => $content, 'length' => $length + $start - $current['start'] ] + $current; } $newcontent = []; $remainingLength = $length; while ($remainingLength > 0) { $temp = self::decode_ber($content, $start, $content_pos); if ($temp === false) { break; } $length = $temp['length']; // end-of-content octets - see paragraph 8.1.5 if (substr($content, $content_pos + $length, 2) == "\0\0") { $length+= 2; $start+= $length; $newcontent[] = $temp; break; } $start+= $length; $remainingLength-= $length; $newcontent[] = $temp; $content_pos += $length; } return [ 'type' => $class, 'constant' => $tag, // the array encapsulation is for BC with the old format 'content' => $newcontent, // the only time when $content['headerlength'] isn't defined is when the length is indefinite. // the absence of $content['headerlength'] is how we know if something is indefinite or not. // technically, it could be defined to be 2 and then another indicator could be used but whatever. 'length' => $start - $current['start'] ] + $current; } $current+= ['type' => $tag]; // decode UNIVERSAL tags switch ($tag) { case self::TYPE_BOOLEAN: // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 //if (strlen($content) != 1) { // return false; //} $current['content'] = (bool) ord($content[$content_pos]); break; case self::TYPE_INTEGER: case self::TYPE_ENUMERATED: $current['content'] = new BigInteger(substr($content, $content_pos), -256); break; case self::TYPE_REAL: // not currently supported return false; case self::TYPE_BIT_STRING: // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit, // the number of unused bits in the final subsequent octet. The number shall be in the range zero to // seven. if (!$constructed) { $current['content'] = substr($content, $content_pos); } else { $temp = self::decode_ber($content, $start, $content_pos); if ($temp === false) { return false; } $length-= (strlen($content) - $content_pos); $last = count($temp) - 1; for ($i = 0; $i < $last; $i++) { // all subtags should be bit strings //if ($temp[$i]['type'] != self::TYPE_BIT_STRING) { // return false; //} $current['content'].= substr($temp[$i]['content'], 1); } // all subtags should be bit strings //if ($temp[$last]['type'] != self::TYPE_BIT_STRING) { // return false; //} $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1); } break; case self::TYPE_OCTET_STRING: if (!$constructed) { $current['content'] = substr($content, $content_pos); } else { $current['content'] = ''; $length = 0; while (substr($content, $content_pos, 2) != "\0\0") { $temp = self::decode_ber($content, $length + $start, $content_pos); if ($temp === false) { return false; } $content_pos += $temp['length']; // all subtags should be octet strings //if ($temp['type'] != self::TYPE_OCTET_STRING) { // return false; //} $current['content'].= $temp['content']; $length+= $temp['length']; } if (substr($content, $content_pos, 2) == "\0\0") { $length+= 2; // +2 for the EOC } } break; case self::TYPE_NULL: // "The contents octets shall not contain any octets." -- paragraph 8.8.2 //if (strlen($content)) { // return false; //} break; case self::TYPE_SEQUENCE: case self::TYPE_SET: $offset = 0; $current['content'] = []; $content_len = strlen($content); while ($content_pos < $content_len) { // if indefinite length construction was used and we have an end-of-content string next // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2 if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") { $length = $offset + 2; // +2 for the EOC break 2; } $temp = self::decode_ber($content, $start + $offset, $content_pos); if ($temp === false) { return false; } $content_pos += $temp['length']; $current['content'][] = $temp; $offset+= $temp['length']; } break; case self::TYPE_OBJECT_IDENTIFIER: $current['content'] = self::decodeOID(substr($content, $content_pos)); break; /* Each character string type shall be encoded as if it had been declared: [UNIVERSAL x] IMPLICIT OCTET STRING -- X.690-0207.pdf#page=23 (paragraph 8.21.3) Per that, we're not going to do any validation. If there are any illegal characters in the string, we don't really care */ case self::TYPE_NUMERIC_STRING: // 0,1,2,3,4,5,6,7,8,9, and space case self::TYPE_PRINTABLE_STRING: // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma, // hyphen, full stop, solidus, colon, equal sign, question mark case self::TYPE_TELETEX_STRING: // The Teletex character set in CCITT's T61, space, and delete // see http://en.wikipedia.org/wiki/Teletex#Character_sets case self::TYPE_VIDEOTEX_STRING: // The Videotex character set in CCITT's T.100 and T.101, space, and delete case self::TYPE_VISIBLE_STRING: // Printing character sets of international ASCII, and space case self::TYPE_IA5_STRING: // International Alphabet 5 (International ASCII) case self::TYPE_GRAPHIC_STRING: // All registered G sets, and space case self::TYPE_GENERAL_STRING: // All registered C and G sets, space and delete case self::TYPE_UTF8_STRING: // ???? case self::TYPE_BMP_STRING: $current['content'] = substr($content, $content_pos); break; case self::TYPE_UTC_TIME: case self::TYPE_GENERALIZED_TIME: $current['content'] = self::decodeTime(substr($content, $content_pos), $tag); default: } $start+= $length; // ie. length is the length of the full TLV encoding - it's not just the length of the value return $current + ['length' => $start - $current['start']]; } /** * ASN.1 Map * * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format. * * "Special" mappings may be applied on a per tag-name basis via $special. * * @param array $decoded * @param array $mapping * @param array $special * @return array|bool|Element * @access public */ public static function asn1map($decoded, $mapping, $special = []) { if (isset($mapping['explicit']) && is_array($decoded['content'])) { $decoded = $decoded['content'][0]; } switch (true) { case $mapping['type'] == self::TYPE_ANY: $intype = $decoded['type']; // !isset(self::ANY_MAP[$intype]) produces a fatal error on PHP 5.6 if (isset($decoded['constant']) || !array_key_exists($intype, self::ANY_MAP) || (ord(self::$encoded[$decoded['start']]) & 0x20)) { return new Element(substr(self::$encoded, $decoded['start'], $decoded['length'])); } $inmap = self::ANY_MAP[$intype]; if (is_string($inmap)) { return [$inmap => self::asn1map($decoded, ['type' => $intype] + $mapping, $special)]; } break; case $mapping['type'] == self::TYPE_CHOICE: foreach ($mapping['children'] as $key => $option) { switch (true) { case isset($option['constant']) && $option['constant'] == $decoded['constant']: case !isset($option['constant']) && $option['type'] == $decoded['type']: $value = self::asn1map($decoded, $option, $special); break; case !isset($option['constant']) && $option['type'] == self::TYPE_CHOICE: $v = self::asn1map($decoded, $option, $special); if (isset($v)) { $value = $v; } } if (isset($value)) { if (isset($special[$key])) { $value = call_user_func($special[$key], $value); } return [$key => $value]; } } return null; case isset($mapping['implicit']): case isset($mapping['explicit']): case $decoded['type'] == $mapping['type']: break; default: // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings, // let it through switch (true) { case $decoded['type'] < 18: // self::TYPE_NUMERIC_STRING == 18 case $decoded['type'] > 30: // self::TYPE_BMP_STRING == 30 case $mapping['type'] < 18: case $mapping['type'] > 30: return null; } } if (isset($mapping['implicit'])) { $decoded['type'] = $mapping['type']; } switch ($decoded['type']) { case self::TYPE_SEQUENCE: $map = []; // ignore the min and max if (isset($mapping['min']) && isset($mapping['max'])) { $child = $mapping['children']; foreach ($decoded['content'] as $content) { if (($map[] = self::asn1map($content, $child, $special)) === null) { return null; } } return $map; } $n = count($decoded['content']); $i = 0; foreach ($mapping['children'] as $key => $child) { $maymatch = $i < $n; // Match only existing input. if ($maymatch) { $temp = $decoded['content'][$i]; if ($child['type'] != self::TYPE_CHOICE) { // Get the mapping and input class & constant. $childClass = $tempClass = self::CLASS_UNIVERSAL; $constant = null; if (isset($temp['constant'])) { $tempClass = $temp['type']; } if (isset($child['class'])) { $childClass = $child['class']; $constant = $child['cast']; } elseif (isset($child['constant'])) { $childClass = self::CLASS_CONTEXT_SPECIFIC; $constant = $child['constant']; } if (isset($constant) && isset($temp['constant'])) { // Can only match if constants and class match. $maymatch = $constant == $temp['constant'] && $childClass == $tempClass; } else { // Can only match if no constant expected and type matches or is generic. $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false; } } } if ($maymatch) { // Attempt submapping. $candidate = self::asn1map($temp, $child, $special); $maymatch = $candidate !== null; } if ($maymatch) { // Got the match: use it. if (isset($special[$key])) { $candidate = call_user_func($special[$key], $candidate); } $map[$key] = $candidate; $i++; } elseif (isset($child['default'])) { switch ($child['type']) { case ASN1::TYPE_INTEGER: $map[$key] = new BigInteger($child['default']); break; //case self::TYPE_OBJECT_IDENTIFIER: // if (!isset(self::$reverseOIDs[$name])) { // return null; // } //case ASN1::TYPE_BOOLEAN: default: $map[$key] = $child['default']; } } elseif (!isset($child['optional'])) { return null; // Syntax error. } } // Fail mapping if all input items have not been consumed. return $i < $n ? null: $map; // the main diff between sets and sequences is the encapsulation of the foreach in another for loop case self::TYPE_SET: $map = []; // ignore the min and max if (isset($mapping['min']) && isset($mapping['max'])) { $child = $mapping['children']; foreach ($decoded['content'] as $content) { if (($map[] = self::asn1map($content, $child, $special)) === null) { return null; } } return $map; } for ($i = 0; $i < count($decoded['content']); $i++) { $temp = $decoded['content'][$i]; $tempClass = self::CLASS_UNIVERSAL; if (isset($temp['constant'])) { $tempClass = $temp['type']; } foreach ($mapping['children'] as $key => $child) { if (isset($map[$key])) { continue; } $maymatch = true; if ($child['type'] != self::TYPE_CHOICE) { $childClass = self::CLASS_UNIVERSAL; $constant = null; if (isset($child['class'])) { $childClass = $child['class']; $constant = $child['cast']; } elseif (isset($child['constant'])) { $childClass = self::CLASS_CONTEXT_SPECIFIC; $constant = $child['constant']; } if (isset($constant) && isset($temp['constant'])) { // Can only match if constants and class match. $maymatch = $constant == $temp['constant'] && $childClass == $tempClass; } else { // Can only match if no constant expected and type matches or is generic. $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false; } } if ($maymatch) { // Attempt submapping. $candidate = self::asn1map($temp, $child, $special); $maymatch = $candidate !== null; } if (!$maymatch) { break; } // Got the match: use it. if (isset($special[$key])) { $candidate = call_user_func($special[$key], $candidate); } $map[$key] = $candidate; break; } } foreach ($mapping['children'] as $key => $child) { if (!isset($map[$key])) { if (isset($child['default'])) { $map[$key] = $child['default']; } elseif (!isset($child['optional'])) { return null; } } } return $map; case self::TYPE_OBJECT_IDENTIFIER: return isset(self::$oids[$decoded['content']]) ? self::$oids[$decoded['content']] : $decoded['content']; case self::TYPE_UTC_TIME: case self::TYPE_GENERALIZED_TIME: if (isset($mapping['implicit'])) { $decoded['content'] = self::decodeTime($decoded['content'], $decoded['type']); } return $decoded['content'] ? $decoded['content']->format(self::$format) : false; case self::TYPE_BIT_STRING: if (isset($mapping['mapping'])) { $offset = ord($decoded['content'][0]); $size = (strlen($decoded['content']) - 1) * 8 - $offset; /* From X.680-0207.pdf#page=46 (21.7): "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove) arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should therefore ensure that different semantics are not associated with such values which differ only in the number of trailing 0 bits." */ $bits = count($mapping['mapping']) == $size ? [] : array_fill(0, count($mapping['mapping']) - $size, false); for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) { $current = ord($decoded['content'][$i]); for ($j = $offset; $j < 8; $j++) { $bits[] = (bool) ($current & (1 << $j)); } $offset = 0; } $values = []; $map = array_reverse($mapping['mapping']); foreach ($map as $i => $value) { if ($bits[$i]) { $values[] = $value; } } return $values; } case self::TYPE_OCTET_STRING: return $decoded['content']; case self::TYPE_NULL: return ''; case self::TYPE_BOOLEAN: return $decoded['content']; case self::TYPE_NUMERIC_STRING: case self::TYPE_PRINTABLE_STRING: case self::TYPE_TELETEX_STRING: case self::TYPE_VIDEOTEX_STRING: case self::TYPE_IA5_STRING: case self::TYPE_GRAPHIC_STRING: case self::TYPE_VISIBLE_STRING: case self::TYPE_GENERAL_STRING: case self::TYPE_UNIVERSAL_STRING: case self::TYPE_UTF8_STRING: case self::TYPE_BMP_STRING: return $decoded['content']; case self::TYPE_INTEGER: case self::TYPE_ENUMERATED: $temp = $decoded['content']; if (isset($mapping['implicit'])) { $temp = new BigInteger($decoded['content'], -256); } if (isset($mapping['mapping'])) { $temp = (int) $temp->toString(); return isset($mapping['mapping'][$temp]) ? $mapping['mapping'][$temp] : false; } return $temp; } } /** * DER-decode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. * * @access public * @param string $string * @return int */ public static function decodeLength(&$string) { $length = ord(Strings::shift($string)); if ($length & 0x80) { // definite length, long form $length&= 0x7F; $temp = Strings::shift($string, $length); list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); } return $length; } /** * ASN.1 Encode * * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function * an ASN.1 compiler. * * "Special" mappings can be applied via $special. * * @param string $source * @param array $mapping * @param array $special * @return string * @access public */ public static function encodeDER($source, $mapping, $special = []) { self::$location = []; return self::encode_der($source, $mapping, null, $special); } /** * ASN.1 Encode (Helper function) * * @param string $source * @param array $mapping * @param int $idx * @param array $special * @return string * @access private */ private static function encode_der($source, $mapping, $idx = null, $special = []) { if ($source instanceof Element) { return $source->element; } // do not encode (implicitly optional) fields with value set to default if (isset($mapping['default']) && $source === $mapping['default']) { return ''; } if (isset($idx)) { if (isset($special[$idx])) { $source = call_user_func($special[$idx], $source); } self::$location[] = $idx; } $tag = $mapping['type']; switch ($tag) { case self::TYPE_SET: // Children order is not important, thus process in sequence. case self::TYPE_SEQUENCE: $tag|= 0x20; // set the constructed bit // ignore the min and max if (isset($mapping['min']) && isset($mapping['max'])) { $value = []; $child = $mapping['children']; foreach ($source as $content) { $temp = self::encode_der($content, $child, null, $special); if ($temp === false) { return false; } $value[]= $temp; } /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared as octet strings with the shorter components being padded at their trailing end with 0-octets. NOTE - The padding octets are for comparison purposes only and do not appear in the encodings." -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */ if ($mapping['type'] == self::TYPE_SET) { sort($value); } $value = implode($value, ''); break; } $value = ''; foreach ($mapping['children'] as $key => $child) { if (!array_key_exists($key, $source)) { if (!isset($child['optional'])) { return false; } continue; } $temp = self::encode_der($source[$key], $child, $key, $special); if ($temp === false) { return false; } // An empty child encoding means it has been optimized out. // Else we should have at least one tag byte. if ($temp === '') { continue; } // if isset($child['constant']) is true then isset($child['optional']) should be true as well if (isset($child['constant'])) { /* From X.680-0207.pdf#page=58 (30.6): "The tagging construction specifies explicit tagging if any of the following holds: ... c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)." */ if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) { $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']); $temp = $subtag . self::encodeLength(strlen($temp)) . $temp; } else { $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']); $temp = $subtag . substr($temp, 1); } } $value.= $temp; } break; case self::TYPE_CHOICE: $temp = false; foreach ($mapping['children'] as $key => $child) { if (!isset($source[$key])) { continue; } $temp = self::encode_der($source[$key], $child, $key, $special); if ($temp === false) { return false; } // An empty child encoding means it has been optimized out. // Else we should have at least one tag byte. if ($temp === '') { continue; } $tag = ord($temp[0]); // if isset($child['constant']) is true then isset($child['optional']) should be true as well if (isset($child['constant'])) { if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) { $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']); $temp = $subtag . self::encodeLength(strlen($temp)) . $temp; } else { $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']); $temp = $subtag . substr($temp, 1); } } } if (isset($idx)) { array_pop(self::$location); } if ($temp && isset($mapping['cast'])) { $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']); } return $temp; case self::TYPE_INTEGER: case self::TYPE_ENUMERATED: if (!isset($mapping['mapping'])) { if (is_numeric($source)) { $source = new BigInteger($source); } $value = $source->toBytes(true); } else { $value = array_search($source, $mapping['mapping']); if ($value === false) { return false; } $value = new BigInteger($value); $value = $value->toBytes(true); } if (!strlen($value)) { $value = chr(0); } break; case self::TYPE_UTC_TIME: case self::TYPE_GENERALIZED_TIME: $format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y'; $format.= 'mdHis'; $date = new DateTime($source, new DateTimeZone('GMT')); $value = $date->format($format) . 'Z'; break; case self::TYPE_BIT_STRING: if (isset($mapping['mapping'])) { $bits = array_fill(0, count($mapping['mapping']), 0); $size = 0; for ($i = 0; $i < count($mapping['mapping']); $i++) { if (in_array($mapping['mapping'][$i], $source)) { $bits[$i] = 1; $size = $i; } } if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) { $size = $mapping['min'] - 1; } $offset = 8 - (($size + 1) & 7); $offset = $offset !== 8 ? $offset : 0; $value = chr($offset); for ($i = $size + 1; $i < count($mapping['mapping']); $i++) { unset($bits[$i]); } $bits = implode('', array_pad($bits, $size + $offset + 1, 0)); $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' '))); foreach ($bytes as $byte) { $value.= chr(bindec($byte)); } break; } case self::TYPE_OCTET_STRING: /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit, the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven. -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */ $value = $source; break; case self::TYPE_OBJECT_IDENTIFIER: $value = self::encodeOID($source); break; case self::TYPE_ANY: $loc = self::$location; if (isset($idx)) { array_pop(self::$location); } switch (true) { case !isset($source): return self::encode_der(null, ['type' => self::TYPE_NULL] + $mapping, null, $special); case is_int($source): case $source instanceof BigInteger: return self::encode_der($source, ['type' => self::TYPE_INTEGER] + $mapping, null, $special); case is_float($source): return self::encode_der($source, ['type' => self::TYPE_REAL] + $mapping, null, $special); case is_bool($source): return self::encode_der($source, ['type' => self::TYPE_BOOLEAN] + $mapping, null, $special); case is_array($source) && count($source) == 1: $typename = implode('', array_keys($source)); $outtype = array_search($typename, self::ANY_MAP, true); if ($outtype !== false) { return self::encode_der($source[$typename], ['type' => $outtype] + $mapping, null, $special); } } $filters = self::$filters; foreach ($loc as $part) { if (!isset($filters[$part])) { $filters = false; break; } $filters = $filters[$part]; } if ($filters === false) { throw new \RuntimeException('No filters defined for ' . implode('/', $loc)); } return self::encode_der($source, $filters + $mapping, null, $special); case self::TYPE_NULL: $value = ''; break; case self::TYPE_NUMERIC_STRING: case self::TYPE_TELETEX_STRING: case self::TYPE_PRINTABLE_STRING: case self::TYPE_UNIVERSAL_STRING: case self::TYPE_UTF8_STRING: case self::TYPE_BMP_STRING: case self::TYPE_IA5_STRING: case self::TYPE_VISIBLE_STRING: case self::TYPE_VIDEOTEX_STRING: case self::TYPE_GRAPHIC_STRING: case self::TYPE_GENERAL_STRING: $value = $source; break; case self::TYPE_BOOLEAN: $value = $source ? "\xFF" : "\x00"; break; default: throw new \RuntimeException('Mapping provides no type definition for ' . implode('/', self::$location)); } if (isset($idx)) { array_pop(self::$location); } if (isset($mapping['cast'])) { if (isset($mapping['explicit']) || $mapping['type'] == self::TYPE_CHOICE) { $value = chr($tag) . self::encodeLength(strlen($value)) . $value; $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast']; } else { $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast']; } } return chr($tag) . self::encodeLength(strlen($value)) . $value; } /** * BER-decode the OID * * Called by _decode_ber() * * @access public * @param string $content * @return string */ public static function decodeOID($content) { static $eighty; if (!$eighty) { $eighty = new BigInteger(80); } $oid = array(); $pos = 0; $len = strlen($content); $n = new BigInteger(); while ($pos < $len) { $temp = ord($content[$pos++]); $n = $n->bitwise_leftShift(7); $n = $n->bitwise_or(new BigInteger($temp & 0x7F)); if (~$temp & 0x80) { $oid[] = $n; $n = new BigInteger(); } } $part1 = array_shift($oid); $first = floor(ord($content[0]) / 40); /* "This packing of the first two object identifier components recognizes that only three values are allocated from the root node, and at most 39 subsequent values from nodes reached by X = 0 and X = 1." -- https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22 */ if ($first <= 2) { // ie. 0 <= ord($content[0]) < 120 (0x78) array_unshift($oid, ord($content[0]) % 40); array_unshift($oid, $first); } else { array_unshift($oid, $part1->subtract($eighty)); array_unshift($oid, 2); } return implode('.', $oid); } /** * DER-encode the OID * * Called by _encode_der() * * @access public * @param string $content * @return string */ public static function encodeOID($source) { static $mask, $zero, $forty; if (!$mask) { $mask = new BigInteger(0x7F); $zero = new BigInteger(); $forty = new BigInteger(40); } if (!preg_match('#(?:\d+\.)+#', $source)) { $oid = isset(self::$reverseOIDs[$source]) ? self::$reverseOIDs[$source] : false; } else { $oid = $source; } if ($oid === false) { throw new \RuntimeException('Invalid OID'); } $parts = explode('.', $oid); $part1 = array_shift($parts); $part2 = array_shift($parts); $first = new BigInteger($part1); $first = $first->multiply($forty); $first = $first->add(new BigInteger($part2)); array_unshift($parts, $first->toString()); $value = ''; foreach ($parts as $part) { if (!$part) { $temp = "\0"; } else { $temp = ''; $part = new BigInteger($part); while (!$part->equals($zero)) { $submask = $part->bitwise_and($mask); $submask->setPrecision(8); $temp = (chr(0x80) | $submask->toBytes()) . $temp; $part = $part->bitwise_rightShift(7); } $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F); } $value.= $temp; } return $value; } /** * BER-decode the time * * Called by _decode_ber() and in the case of implicit tags asn1map(). * * @access private * @param string $content * @param int $tag * @return string */ private static function decodeTime($content, $tag) { /* UTCTime: http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 http://www.obj-sys.com/asn1tutorial/node15.html GeneralizedTime: http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 http://www.obj-sys.com/asn1tutorial/node14.html */ $format = 'YmdHis'; if ($tag == self::TYPE_UTC_TIME) { // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the // browsers parse it phpseclib ought to too if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) { $content = $matches[1] . '00' . $matches[2]; } $prefix = substr($content, 0, 2) >= 50 ? '19' : '20'; $content = $prefix . $content; } elseif (strpos($content, '.') !== false) { $format.= '.u'; } if ($content[strlen($content) - 1] == 'Z') { $content = substr($content, 0, -1) . '+0000'; } if (strpos($content, '-') !== false || strpos($content, '+') !== false) { $format.= 'O'; } // error supression isn't necessary as of PHP 7.0: // http://php.net/manual/en/migration70.other-changes.php return @DateTime::createFromFormat($format, $content); } /** * Set the time format * * Sets the time / date format for asn1map(). * * @access public * @param string $format */ public static function setTimeFormat($format) { self::$format = $format; } /** * Load OIDs * * Load the relevant OIDs for a particular ASN.1 semantic mapping. * Previously loaded OIDs are retained. * * @access public * @param array $oids */ public static function loadOIDs($oids) { self::$reverseOIDs+= $oids; self::$oids = array_flip(self::$reverseOIDs); } /** * Set filters * * See \phpseclib\File\X509, etc, for an example. * Previously loaded filters are not retained. * * @access public * @param array $filters */ public static function setFilters($filters) { self::$filters = $filters; } /** * String type conversion * * This is a lazy conversion, dealing only with character size. * No real conversion table is used. * * @param string $in * @param int $from * @param int $to * @return string * @access public */ public static function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING) { // isset(self::STRING_TYPE_SIZE[$from] returns a fatal error on PHP 5.6 if (!array_key_exists($from, self::STRING_TYPE_SIZE) || !array_key_exists($to, self::STRING_TYPE_SIZE)) { return false; } $insize = self::STRING_TYPE_SIZE[$from]; $outsize = self::STRING_TYPE_SIZE[$to]; $inlength = strlen($in); $out = ''; for ($i = 0; $i < $inlength;) { if ($inlength - $i < $insize) { return false; } // Get an input character as a 32-bit value. $c = ord($in[$i++]); switch (true) { case $insize == 4: $c = ($c << 8) | ord($in[$i++]); $c = ($c << 8) | ord($in[$i++]); case $insize == 2: $c = ($c << 8) | ord($in[$i++]); case $insize == 1: break; case ($c & 0x80) == 0x00: break; case ($c & 0x40) == 0x00: return false; default: $bit = 6; do { if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) { return false; } $c = ($c << 6) | (ord($in[$i++]) & 0x3F); $bit += 5; $mask = 1 << $bit; } while ($c & $bit); $c &= $mask - 1; break; } // Convert and append the character to output string. $v = ''; switch (true) { case $outsize == 4: $v .= chr($c & 0xFF); $c >>= 8; $v .= chr($c & 0xFF); $c >>= 8; case $outsize == 2: $v .= chr($c & 0xFF); $c >>= 8; case $outsize == 1: $v .= chr($c & 0xFF); $c >>= 8; if ($c) { return false; } break; case ($c & 0x80000000) != 0: return false; case $c >= 0x04000000: $v .= chr(0x80 | ($c & 0x3F)); $c = ($c >> 6) | 0x04000000; case $c >= 0x00200000: $v .= chr(0x80 | ($c & 0x3F)); $c = ($c >> 6) | 0x00200000; case $c >= 0x00010000: $v .= chr(0x80 | ($c & 0x3F)); $c = ($c >> 6) | 0x00010000; case $c >= 0x00000800: $v .= chr(0x80 | ($c & 0x3F)); $c = ($c >> 6) | 0x00000800; case $c >= 0x00000080: $v .= chr(0x80 | ($c & 0x3F)); $c = ($c >> 6) | 0x000000C0; default: $v .= chr($c); break; } $out .= strrev($v); } return $out; } /** * Extract raw BER from Base64 encoding * * @access private * @param string $str * @return string */ public static function extractBER($str) { /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them * above and beyond the ceritificate. * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: * * Bag Attributes * localKeyID: 01 00 00 00 * subject=/O=organization/OU=org unit/CN=common name * issuer=/O=organization/CN=common name */ $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1); // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff $temp = preg_replace('#-+[^-]+-+#', '', $temp); // remove new lines $temp = str_replace(["\r", "\n", ' '], '', $temp); $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false; return $temp != false ? $temp : $str; } /** * DER-encode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. * * @access public * @param int $length * @return string */ public static function encodeLength($length) { if ($length <= 0x7F) { return chr($length); } $temp = ltrim(pack('N', $length), chr(0)); return pack('Ca*', 0x80 | strlen($temp), $temp); } /** * Returns the OID corresponding to a name * * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able * to work from version to version. * * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that * what's being passed to it already is an OID and return that instead. A few examples. * * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1' * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1' * getOID('zzz') == 'zzz' * * @access public * @param string $name * @return string */ public static function getOID($name) { return isset(self::$reverseOIDs[$name]) ? self::$reverseOIDs[$name] : $name; } } <?php /** * BadDecryptionException * * PHP version 5 * * @category Exception * @package BadDecryptionException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * BadDecryptionException * * @package BadDecryptionException * @author Jim Wigginton <terrafrost@php.net> */ class BadDecryptionException extends \RuntimeException { } <?php /** * InconsistentSetupException * * PHP version 5 * * @category Exception * @package InconsistentSetupException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * InconsistentSetupException * * @package InconsistentSetupException * @author Jim Wigginton <terrafrost@php.net> */ class InconsistentSetupException extends \RuntimeException { } <?php /** * NoSupportedAlgorithmsException * * PHP version 5 * * @category Exception * @package NoSupportedAlgorithmsException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * NoSupportedAlgorithmsException * * @package NoSupportedAlgorithmsException * @author Jim Wigginton <terrafrost@php.net> */ class NoSupportedAlgorithmsException extends \RuntimeException { } <?php /** * UnsupportedAlgorithmException * * PHP version 5 * * @category Exception * @package UnsupportedAlgorithmException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * UnsupportedAlgorithmException * * @package UnsupportedAlgorithmException * @author Jim Wigginton <terrafrost@php.net> */ class UnsupportedAlgorithmException extends \RuntimeException { } <?php /** * InsufficientSetupException * * PHP version 5 * * @category Exception * @package InsufficientSetupException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * InsufficientSetupException * * @package InsufficientSetupException * @author Jim Wigginton <terrafrost@php.net> */ class InsufficientSetupException extends \RuntimeException { } <?php /** * UnsupportedCurveException * * PHP version 5 * * @category Exception * @package UnsupportedCurveException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * UnsupportedCurveException * * @package UnsupportedCurveException * @author Jim Wigginton <terrafrost@php.net> */ class UnsupportedCurveException extends \RuntimeException { } <?php /** * BadModeException * * PHP version 5 * * @category Exception * @package BadModeException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * BadModeException * * @package BadModeException * @author Jim Wigginton <terrafrost@php.net> */ class BadModeException extends \RuntimeException { } <?php /** * BadConfigurationException * * PHP version 5 * * @category Exception * @package BadConfigurationException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * BadConfigurationException * * @package BadConfigurationException * @author Jim Wigginton <terrafrost@php.net> */ class BadConfigurationException extends \RuntimeException { } <?php /** * NoKeyLoadedException * * PHP version 5 * * @category Exception * @package NoKeyLoadedException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * NoKeyLoadedException * * @package NoKeyLoadedException * @author Jim Wigginton <terrafrost@php.net> */ class NoKeyLoadedException extends \RuntimeException { } <?php /** * UnsupportedFormatException * * PHP version 5 * * @category Exception * @package UnsupportedFormatException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * UnsupportedFormatException * * @package UnsupportedFormatException * @author Jim Wigginton <terrafrost@php.net> */ class UnsupportedFormatException extends \RuntimeException { } <?php /** * FileNotFoundException * * PHP version 5 * * @category Exception * @package FileNotFoundException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * FileNotFoundException * * @package FileNotFoundException * @author Jim Wigginton <terrafrost@php.net> */ class FileNotFoundException extends \RuntimeException { } <?php /** * UnsupportedOperationException * * PHP version 5 * * @category Exception * @package UnsupportedOperationException * @author Jim Wigginton <terrafrost@php.net> * @copyright 2015 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Exception; /** * UnsupportedOperationException * * @package UnsupportedOperationException * @author Jim Wigginton <terrafrost@php.net> */ class UnsupportedOperationException extends \RuntimeException { } <?php /** * Pure-PHP implementation of SSHv2. * * PHP version 5 * * Here are some examples of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $ssh = new \phpseclib\Net\SSH2('www.domain.tld'); * if (!$ssh->login('username', 'password')) { * exit('Login Failed'); * } * * echo $ssh->exec('pwd'); * echo $ssh->exec('ls -la'); * ?> * </code> * * <code> * <?php * include 'vendor/autoload.php'; * * \phpseclib\Crypt\PublicKeyLoader::load('...'); * //$key->setPassword('whatever'); * $key->load(file_get_contents('privatekey')); * * $ssh = new \phpseclib\Net\SSH2('www.domain.tld'); * if (!$ssh->login('username', $key)) { * exit('Login Failed'); * } * * echo $ssh->read('username@username:~$'); * $ssh->write("ls -la\n"); * echo $ssh->read('username@username:~$'); * ?> * </code> * * @category Net * @package SSH2 * @author Jim Wigginton <terrafrost@php.net> * @copyright 2007 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Net; use phpseclib\Crypt\Blowfish; use phpseclib\Crypt\Hash; use phpseclib\Crypt\Random; use phpseclib\Crypt\RC4; use phpseclib\Crypt\Rijndael; use phpseclib\Crypt\Common\PrivateKey; use phpseclib\Crypt\RSA; use phpseclib\Crypt\DSA; use phpseclib\Crypt\ECDSA; use phpseclib\Crypt\TripleDES; use phpseclib\Crypt\Twofish; use phpseclib\Crypt\ChaCha20; use phpseclib\Math\BigInteger; // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification. use phpseclib\System\SSH\Agent; use phpseclib\System\SSH\Agent\Identity as AgentIdentity; use phpseclib\Exception\NoSupportedAlgorithmsException; use phpseclib\Exception\UnsupportedAlgorithmException; use phpseclib\Exception\UnsupportedCurveException; use phpseclib\Common\Functions\Strings; use phpseclib\Crypt\Common\Keys\OpenSSH; /** * Pure-PHP implementation of SSHv2. * * @package SSH2 * @author Jim Wigginton <terrafrost@php.net> * @access public */ class SSH2 { /**#@+ * Execution Bitmap Masks * * @see \phpseclib\Net\SSH2::bitmap * @access private */ const MASK_CONSTRUCTOR = 0x00000001; const MASK_CONNECTED = 0x00000002; const MASK_LOGIN_REQ = 0x00000004; const MASK_LOGIN = 0x00000008; const MASK_SHELL = 0x00000010; const MASK_WINDOW_ADJUST = 0x00000020; /**#@-*/ /**#@+ * Channel constants * * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a * recipient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snippet: * The 'recipient channel' is the channel number given in the original * open request, and 'sender channel' is the channel number allocated by * the other side. * * @see \phpseclib\Net\SSH2::send_channel_packet() * @see \phpseclib\Net\SSH2::get_channel_packet() * @access private */ const CHANNEL_EXEC = 1; // PuTTy uses 0x100 const CHANNEL_SHELL = 2; const CHANNEL_SUBSYSTEM = 3; const CHANNEL_AGENT_FORWARD = 4; const CHANNEL_KEEP_ALIVE = 5; /**#@-*/ /**#@+ * @access public * @see \phpseclib\Net\SSH2::getLog() */ /** * Returns the message numbers */ const LOG_SIMPLE = 1; /** * Returns the message content */ const LOG_COMPLEX = 2; /** * Outputs the content real-time */ const LOG_REALTIME = 3; /** * Dumps the content real-time to a file */ const LOG_REALTIME_FILE = 4; /** * Make sure that the log never gets larger than this */ const LOG_MAX_SIZE = 1048576; // 1024 * 1024 /**#@-*/ /**#@+ * @access public * @see \phpseclib\Net\SSH2::read() */ /** * Returns when a string matching $expect exactly is found */ const READ_SIMPLE = 1; /** * Returns when a string matching the regular expression $expect is found */ const READ_REGEX = 2; /** * Returns whenever a data packet is received. * * Some data packets may only contain a single character so it may be necessary * to call read() multiple times when using this option */ const READ_NEXT = 3; /**#@-*/ /** * The SSH identifier * * @var string * @access private */ private $identifier; /** * The Socket Object * * @var object * @access private */ private $fsock; /** * Execution Bitmap * * The bits that are set represent functions that have been called already. This is used to determine * if a requisite function has been successfully executed. If not, an error should be thrown. * * @var int * @access private */ protected $bitmap = 0; /** * Error information * * @see self::getErrors() * @see self::getLastError() * @var array * @access private */ private $errors = []; /** * Server Identifier * * @see self::getServerIdentification() * @var array|false * @access private */ private $server_identifier = false; /** * Key Exchange Algorithms * * @see self::getKexAlgorithims() * @var array|false * @access private */ private $kex_algorithms = false; /** * Key Exchange Algorithm * * @see self::getMethodsNegotiated() * @var string|false * @access private */ private $kex_algorithm = false; /** * Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods * * @see self::_key_exchange() * @var int * @access private */ private $kex_dh_group_size_min = 1536; /** * Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods * * @see self::_key_exchange() * @var int * @access private */ private $kex_dh_group_size_preferred = 2048; /** * Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods * * @see self::_key_exchange() * @var int * @access private */ private $kex_dh_group_size_max = 4096; /** * Server Host Key Algorithms * * @see self::getServerHostKeyAlgorithms() * @var array|false * @access private */ private $server_host_key_algorithms = false; /** * Encryption Algorithms: Client to Server * * @see self::getEncryptionAlgorithmsClient2Server() * @var array|false * @access private */ private $encryption_algorithms_client_to_server = false; /** * Encryption Algorithms: Server to Client * * @see self::getEncryptionAlgorithmsServer2Client() * @var array|false * @access private */ private $encryption_algorithms_server_to_client = false; /** * MAC Algorithms: Client to Server * * @see self::getMACAlgorithmsClient2Server() * @var array|false * @access private */ private $mac_algorithms_client_to_server = false; /** * MAC Algorithms: Server to Client * * @see self::getMACAlgorithmsServer2Client() * @var array|false * @access private */ private $mac_algorithms_server_to_client = false; /** * Compression Algorithms: Client to Server * * @see self::getCompressionAlgorithmsClient2Server() * @var array|false * @access private */ private $compression_algorithms_client_to_server = false; /** * Compression Algorithms: Server to Client * * @see self::getCompressionAlgorithmsServer2Client() * @var array|false * @access private */ private $compression_algorithms_server_to_client = false; /** * Languages: Server to Client * * @see self::getLanguagesServer2Client() * @var array|false * @access private */ private $languages_server_to_client = false; /** * Languages: Client to Server * * @see self::getLanguagesClient2Server() * @var array|false * @access private */ private $languages_client_to_server = false; /** * Preferred Algorithms * * @see self::setPreferredAlgorithms() * @var array * @access private */ private $preferred = []; /** * Block Size for Server to Client Encryption * * "Note that the length of the concatenation of 'packet_length', * 'padding_length', 'payload', and 'random padding' MUST be a multiple * of the cipher block size or 8, whichever is larger. This constraint * MUST be enforced, even when using stream ciphers." * * -- http://tools.ietf.org/html/rfc4253#section-6 * * @see self::__construct() * @see self::_send_binary_packet() * @var int * @access private */ private $encrypt_block_size = 8; /** * Block Size for Client to Server Encryption * * @see self::__construct() * @see self::_get_binary_packet() * @var int * @access private */ private $decrypt_block_size = 8; /** * Server to Client Encryption Object * * @see self::_get_binary_packet() * @var object * @access private */ private $decrypt = false; /** * Server to Client Length Encryption Object * * @see self::_get_binary_packet() * @var object * @access private */ private $lengthDecrypt = false; /** * Client to Server Encryption Object * * @see self::_send_binary_packet() * @var object * @access private */ private $encrypt = false; /** * Client to Server Length Encryption Object * * @see self::_send_binary_packet() * @var object * @access private */ private $lengthEncrypt = false; /** * Client to Server HMAC Object * * @see self::_send_binary_packet() * @var object * @access private */ private $hmac_create = false; /** * Server to Client HMAC Object * * @see self::_get_binary_packet() * @var object * @access private */ private $hmac_check = false; /** * Size of server to client HMAC * * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read. * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is * append it. * * @see self::_get_binary_packet() * @var int * @access private */ private $hmac_size = false; /** * Server Public Host Key * * @see self::getServerPublicHostKey() * @var string * @access private */ private $server_public_host_key; /** * Session identifier * * "The exchange hash H from the first key exchange is additionally * used as the session identifier, which is a unique identifier for * this connection." * * -- http://tools.ietf.org/html/rfc4253#section-7.2 * * @see self::_key_exchange() * @var string * @access private */ private $session_id = false; /** * Exchange hash * * The current exchange hash * * @see self::_key_exchange() * @var string * @access private */ private $exchange_hash = false; /** * Message Numbers * * @see self::__construct() * @var array * @access private */ private $message_numbers = []; /** * Disconnection Message 'reason codes' defined in RFC4253 * * @see self::__construct() * @var array * @access private */ private $disconnect_reasons = []; /** * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254 * * @see self::__construct() * @var array * @access private */ private $channel_open_failure_reasons = []; /** * Terminal Modes * * @link http://tools.ietf.org/html/rfc4254#section-8 * @see self::__construct() * @var array * @access private */ private $terminal_modes = []; /** * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes * * @link http://tools.ietf.org/html/rfc4254#section-5.2 * @see self::__construct() * @var array * @access private */ private $channel_extended_data_type_codes = []; /** * Send Sequence Number * * See 'Section 6.4. Data Integrity' of rfc4253 for more info. * * @see self::_send_binary_packet() * @var int * @access private */ private $send_seq_no = 0; /** * Get Sequence Number * * See 'Section 6.4. Data Integrity' of rfc4253 for more info. * * @see self::_get_binary_packet() * @var int * @access private */ private $get_seq_no = 0; /** * Server Channels * * Maps client channels to server channels * * @see self::get_channel_packet() * @see self::exec() * @var array * @access private */ protected $server_channels = []; /** * Channel Buffers * * If a client requests a packet from one channel but receives two packets from another those packets should * be placed in a buffer * * @see self::get_channel_packet() * @see self::exec() * @var array * @access private */ private $channel_buffers = []; /** * Channel Status * * Contains the type of the last sent message * * @see self::get_channel_packet() * @var array * @access private */ protected $channel_status = []; /** * Packet Size * * Maximum packet size indexed by channel * * @see self::send_channel_packet() * @var array * @access private */ private $packet_size_client_to_server = []; /** * Message Number Log * * @see self::getLog() * @var array * @access private */ private $message_number_log = []; /** * Message Log * * @see self::getLog() * @var array * @access private */ private $message_log = []; /** * The Window Size * * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB) * * @var int * @see self::send_channel_packet() * @see self::exec() * @access private */ protected $window_size = 0x7FFFFFFF; /** * Window size, server to client * * Window size indexed by channel * * @see self::send_channel_packet() * @var array * @access private */ protected $window_size_server_to_client = []; /** * Window size, client to server * * Window size indexed by channel * * @see self::get_channel_packet() * @var array * @access private */ private $window_size_client_to_server = []; /** * Server signature * * Verified against $this->session_id * * @see self::getServerPublicHostKey() * @var string * @access private */ private $signature = ''; /** * Server signature format * * ssh-rsa or ssh-dss. * * @see self::getServerPublicHostKey() * @var string * @access private */ private $signature_format = ''; /** * Interactive Buffer * * @see self::read() * @var array * @access private */ private $interactiveBuffer = ''; /** * Current log size * * Should never exceed self::LOG_MAX_SIZE * * @see self::_send_binary_packet() * @see self::_get_binary_packet() * @var int * @access private */ private $log_size; /** * Timeout * * @see self::setTimeout() * @access private */ protected $timeout; /** * Current Timeout * * @see self::get_channel_packet() * @access private */ protected $curTimeout; /** * Real-time log file pointer * * @see self::_append_log() * @var resource * @access private */ private $realtime_log_file; /** * Real-time log file size * * @see self::_append_log() * @var int * @access private */ private $realtime_log_size; /** * Has the signature been validated? * * @see self::getServerPublicHostKey() * @var bool * @access private */ private $signature_validated = false; /** * Real-time log file wrap boolean * * @see self::_append_log() * @access private */ private $realtime_log_wrap; /** * Flag to suppress stderr from output * * @see self::enableQuietMode() * @access private */ private $quiet_mode = false; /** * Time of first network activity * * @var int * @access private */ private $last_packet; /** * Exit status returned from ssh if any * * @var int * @access private */ private $exit_status; /** * Flag to request a PTY when using exec() * * @var bool * @see self::enablePTY() * @access private */ private $request_pty = false; /** * Flag set while exec() is running when using enablePTY() * * @var bool * @access private */ private $in_request_pty_exec = false; /** * Flag set after startSubsystem() is called * * @var bool * @access private */ private $in_subsystem; /** * Contents of stdError * * @var string * @access private */ private $stdErrorLog; /** * The Last Interactive Response * * @see self::_keyboard_interactive_process() * @var string * @access private */ private $last_interactive_response = ''; /** * Keyboard Interactive Request / Responses * * @see self::_keyboard_interactive_process() * @var array * @access private */ private $keyboard_requests_responses = []; /** * Banner Message * * Quoting from the RFC, "in some jurisdictions, sending a warning message before * authentication may be relevant for getting legal protection." * * @see self::_filter() * @see self::getBannerMessage() * @var string * @access private */ private $banner_message = ''; /** * Did read() timeout or return normally? * * @see self::isTimeout() * @var bool * @access private */ private $is_timeout = false; /** * Log Boundary * * @see self::_format_log() * @var string * @access private */ private $log_boundary = ':'; /** * Log Long Width * * @see self::_format_log() * @var int * @access private */ private $log_long_width = 65; /** * Log Short Width * * @see self::_format_log() * @var int * @access private */ private $log_short_width = 16; /** * Hostname * * @see self::__construct() * @see self::_connect() * @var string * @access private */ private $host; /** * Port Number * * @see self::__construct() * @see self::_connect() * @var int * @access private */ private $port; /** * Number of columns for terminal window size * * @see self::getWindowColumns() * @see self::setWindowColumns() * @see self::setWindowSize() * @var int * @access private */ private $windowColumns = 80; /** * Number of columns for terminal window size * * @see self::getWindowRows() * @see self::setWindowRows() * @see self::setWindowSize() * @var int * @access private */ private $windowRows = 24; /** * Crypto Engine * * @see self::setCryptoEngine() * @see self::_key_exchange() * @var int * @access private */ private $crypto_engine = false; /** * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario * * @var \phpseclib\System\Ssh\Agent * @access private */ private $agent; /** * Connection storage to replicates ssh2 extension functionality: * {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples} * * @var SSH2[] */ private static $connections; /** * Send the identification string first? * * @var bool * @access private */ private $send_id_string_first = true; /** * Send the key exchange initiation packet first? * * @var bool * @access private */ private $send_kex_first = true; /** * Some versions of OpenSSH incorrectly calculate the key size * * @var bool * @access private */ private $bad_key_size_fix = false; /** * Should we try to re-connect to re-establish keys? * * @var bool * @access private */ private $retry_connect = false; /** * Binary Packet Buffer * * @var string|false * @access private */ private $binary_packet_buffer = false; /** * Preferred Signature Format * * @var string|false * @access private */ var $preferred_signature_format = false; /** * Authentication Credentials * * @var array * @access private */ var $auth = []; /** * Default Constructor. * * $host can either be a string, representing the host, or a stream resource. * * @param mixed $host * @param int $port * @param int $timeout * @see self::login() * @return SSH2|void * @access public */ public function __construct($host, $port = 22, $timeout = 10) { $this->message_numbers = [ 1 => 'NET_SSH2_MSG_DISCONNECT', 2 => 'NET_SSH2_MSG_IGNORE', 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', 4 => 'NET_SSH2_MSG_DEBUG', 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', 20 => 'NET_SSH2_MSG_KEXINIT', 21 => 'NET_SSH2_MSG_NEWKEYS', 30 => 'NET_SSH2_MSG_KEXDH_INIT', 31 => 'NET_SSH2_MSG_KEXDH_REPLY', 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', 94 => 'NET_SSH2_MSG_CHANNEL_DATA', 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', 96 => 'NET_SSH2_MSG_CHANNEL_EOF', 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' ]; $this->disconnect_reasons = [ 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', 4 => 'NET_SSH2_DISCONNECT_RESERVED', 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' ]; $this->channel_open_failure_reasons = [ 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' ]; $this->terminal_modes = [ 0 => 'NET_SSH2_TTY_OP_END' ]; $this->channel_extended_data_type_codes = [ 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' ]; $this->define_array( $this->message_numbers, $this->disconnect_reasons, $this->channel_open_failure_reasons, $this->terminal_modes, $this->channel_extended_data_type_codes, [60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'], [60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'], [60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'], // RFC 4419 - diffie-hellman-group-exchange-sha{1,256} [30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD', 31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP', 32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT', 33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY', 34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'], // RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org) [30 => 'NET_SSH2_MSG_KEX_ECDH_INIT', 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY'] ); self::$connections[$this->getResourceId()] = $this; if (is_resource($host)) { $this->fsock = $host; return; } if (is_string($host)) { $this->host = $host; $this->port = $port; $this->timeout = $timeout; } } /** * Set Crypto Engine Mode * * Possible $engine values: * OpenSSL, mcrypt, Eval, PHP * * @param int $engine * @access public */ public function setCryptoEngine($engine) { $this->crypto_engine = $engine; } /** * Send Identification String First * * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established, * both sides MUST send an identification string". It does not say which side sends it first. In * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy * * @access public */ public function sendIdentificationStringFirst() { $this->send_id_string_first = true; } /** * Send Identification String Last * * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established, * both sides MUST send an identification string". It does not say which side sends it first. In * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy * * @access public */ public function sendIdentificationStringLast() { $this->send_id_string_first = false; } /** * Send SSH_MSG_KEXINIT First * * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy * * @access public */ public function sendKEXINITFirst() { $this->send_kex_first = true; } /** * Send SSH_MSG_KEXINIT Last * * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy * * @access public */ public function sendKEXINITLast() { $this->send_kex_first = false; } /** * Connect to an SSHv2 server * * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @throws \RuntimeException on other errors * @access private */ private function connect() { if ($this->bitmap & self::MASK_CONSTRUCTOR) { return false; } $this->bitmap |= self::MASK_CONSTRUCTOR; $this->curTimeout = $this->timeout; $this->last_packet = microtime(true); if (!is_resource($this->fsock)) { $start = microtime(true); // with stream_select a timeout of 0 means that no timeout takes place; // with fsockopen a timeout of 0 means that you instantly timeout // to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0 $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout); if (!$this->fsock) { $host = $this->host . ':' . $this->port; throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr")); } $elapsed = microtime(true) - $start; if ($this->curTimeout) { $this->curTimeout-= $elapsed; if ($this->curTimeout < 0) { $this->is_timeout = true; return false; } } } $this->identifier = $this->generate_identifier(); if ($this->send_id_string_first) { fputs($this->fsock, $this->identifier . "\r\n"); } /* According to the SSH2 specs, "The server MAY send other lines of data before sending the version string. Each line SHOULD be terminated by a Carriage Return and Line Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients MUST be able to process such lines." */ $data = ''; while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms', $data, $matches)) { $line = ''; while (true) { if ($this->curTimeout) { if ($this->curTimeout < 0) { $this->is_timeout = true; return false; } $read = [$this->fsock]; $write = $except = null; $start = microtime(true); $sec = floor($this->curTimeout); $usec = 1000000 * ($this->curTimeout - $sec); // on windows this returns a "Warning: Invalid CRT parameters detected" error // the !count() is done as a workaround for <https://bugs.php.net/42682> if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { $this->is_timeout = true; return false; } $elapsed = microtime(true) - $start; $this->curTimeout-= $elapsed; } $temp = stream_get_line($this->fsock, 255, "\n"); if (strlen($temp) == 255) { continue; } $line.= "$temp\n"; // quoting RFC4253, "Implementers who wish to maintain // compatibility with older, undocumented versions of this protocol may // want to process the identification string without expecting the // presence of the carriage return character for reasons described in // Section 5 of this document." //if (substr($line, -2) == "\r\n") { // break; //} break; } $data.= $line; } if (feof($this->fsock)) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } $extra = $matches[1]; if (defined('NET_SSH2_LOGGING')) { $this->append_log('<-', $matches[0]); $this->append_log('->', $this->identifier . "\r\n"); } $this->server_identifier = trim($temp, "\r\n"); if (strlen($extra)) { $this->errors[] = $data; } if (version_compare($matches[3], '1.99', '<')) { throw new \RuntimeException("Cannot connect to SSH $matches[3] servers"); } if (!$this->send_id_string_first) { fputs($this->fsock, $this->identifier . "\r\n"); } if (!$this->send_kex_first) { $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) { throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); } if (!$this->key_exchange($response)) { return false; } } if ($this->send_kex_first && !$this->key_exchange()) { return false; } $this->bitmap|= self::MASK_CONNECTED; return true; } /** * Generates the SSH identifier * * You should overwrite this method in your own class if you want to use another identifier * * @access protected * @return string */ private function generate_identifier() { $identifier = 'SSH-2.0-phpseclib_2.0'; $ext = []; if (function_exists('\\Sodium\\library_version_major')) { $ext[] = 'libsodium'; } if (extension_loaded('openssl')) { $ext[] = 'openssl'; } elseif (extension_loaded('mcrypt')) { $ext[] = 'mcrypt'; } if (extension_loaded('gmp')) { $ext[] = 'gmp'; } elseif (extension_loaded('bcmath')) { $ext[] = 'bcmath'; } if (!empty($ext)) { $identifier .= ' (' . implode(', ', $ext) . ')'; } return $identifier; } /** * Key Exchange * @return bool * @param string|bool $kexinit_payload_server optional * @throws \UnexpectedValueException on receipt of unexpected packets * @throws \RuntimeException on other errors * @throws \phpseclib\Exception\NoSupportedAlgorithmsException when none of the algorithms phpseclib has loaded are compatible * @access private */ private function key_exchange($kexinit_payload_server = false) { $preferred = $this->preferred; $kex_algorithms = isset($preferred['kex']) ? $preferred['kex'] : SSH2::getSupportedKEXAlgorithms(); $server_host_key_algorithms = isset($preferred['hostkey']) ? $preferred['hostkey'] : SSH2::getSupportedHostKeyAlgorithms(); $s2c_encryption_algorithms = isset($preferred['server_to_client']['crypt']) ? $preferred['server_to_client']['crypt'] : SSH2::getSupportedEncryptionAlgorithms(); $c2s_encryption_algorithms = isset($preferred['client_to_server']['crypt']) ? $preferred['client_to_server']['crypt'] : SSH2::getSupportedEncryptionAlgorithms(); $s2c_mac_algorithms = isset($preferred['server_to_client']['mac']) ? $preferred['server_to_client']['mac'] : SSH2::getSupportedMACAlgorithms(); $c2s_mac_algorithms = isset($preferred['client_to_server']['mac']) ? $preferred['client_to_server']['mac'] : SSH2::getSupportedMACAlgorithms(); $s2c_compression_algorithms = isset($preferred['server_to_client']['comp']) ? $preferred['server_to_client']['comp'] : SSH2::getSupportedCompressionAlgorithms(); $c2s_compression_algorithms = isset($preferred['client_to_server']['comp']) ? $preferred['client_to_server']['comp'] : SSH2::getSupportedCompressionAlgorithms(); // some SSH servers have buggy implementations of some of the above algorithms switch (true) { case $this->server_identifier == 'SSH-2.0-SSHD': case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK': if (!isset($preferred['server_to_client']['mac'])) { $s2c_mac_algorithms = array_values(array_diff( $s2c_mac_algorithms, ['hmac-sha1-96', 'hmac-md5-96'] )); } if (!isset($preferred['client_to_server']['mac'])) { $c2s_mac_algorithms = array_values(array_diff( $c2s_mac_algorithms, ['hmac-sha1-96', 'hmac-md5-96'] )); } } $client_cookie = Random::string(16); $kexinit_payload_client = pack('Ca*', NET_SSH2_MSG_KEXINIT, $client_cookie); $kexinit_payload_client.= Strings::packSSH2( 'L10bN', $kex_algorithms, $server_host_key_algorithms, $c2s_encryption_algorithms, $s2c_encryption_algorithms, $c2s_mac_algorithms, $s2c_mac_algorithms, $c2s_compression_algorithms, $s2c_compression_algorithms, [], // language, client to server [], // language, server to client false, // first_kex_packet_follows 0 // reserved for future extension ); if ($this->send_kex_first) { $this->send_binary_packet($kexinit_payload_client); $kexinit_payload_server = $this->get_binary_packet(); if ($kexinit_payload_server === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) { throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); } } $response = $kexinit_payload_server; Strings::shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT) $server_cookie = Strings::shift($response, 16); list( $this->kex_algorithms, $this->server_host_key_algorithms, $this->encryption_algorithms_client_to_server, $this->encryption_algorithms_server_to_client, $this->mac_algorithms_client_to_server, $this->mac_algorithms_server_to_client, $this->compression_algorithms_client_to_server, $this->compression_algorithms_server_to_client, $this->languages_client_to_server, $this->languages_server_to_client, $first_kex_packet_follows ) = Strings::unpackSSH2('L10C', $response); if (!$this->send_kex_first) { $this->send_binary_packet($kexinit_payload_client); } // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the // diffie-hellman key exchange as fast as possible $decrypt = $this->array_intersect_first($s2c_encryption_algorithms, $this->encryption_algorithms_server_to_client); $decryptKeyLength = $this->encryption_algorithm_to_key_size($decrypt); if ($decryptKeyLength === null) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible server to client encryption algorithms found'); } $encrypt = $this->array_intersect_first($c2s_encryption_algorithms, $this->encryption_algorithms_client_to_server); $encryptKeyLength = $this->encryption_algorithm_to_key_size($encrypt); if ($encryptKeyLength === null) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible client to server encryption algorithms found'); } // through diffie-hellman key exchange a symmetric key is obtained $this->kex_algorithm = $this->array_intersect_first($kex_algorithms, $this->kex_algorithms); if ($this->kex_algorithm === false) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible key exchange algorithms found'); } // Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty. $exchange_hash_rfc4419 = ''; if ($this->kex_algorithm === 'curve25519-sha256@libssh.org') { $x = Random::string(32); $eBytes = \Sodium\crypto_box_publickey_from_secretkey($x); $clientKexInitMessage = NET_SSH2_MSG_KEX_ECDH_INIT; $serverKexReplyMessage = NET_SSH2_MSG_KEX_ECDH_REPLY; $kexHash = new Hash('sha256'); } else { if (strpos($this->kex_algorithm, 'diffie-hellman-group-exchange') === 0) { $dh_group_sizes_packed = pack( 'NNN', $this->kex_dh_group_size_min, $this->kex_dh_group_size_preferred, $this->kex_dh_group_size_max ); $packet = pack( 'Ca*', NET_SSH2_MSG_KEXDH_GEX_REQUEST, $dh_group_sizes_packed ); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type, $primeBytes, $gBytes) = unpack('Css', $response); if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) { throw new \UnexpectedValueException('Expected SSH_MSG_KEX_DH_GEX_GROUP'); } $prime = new BigInteger($primeBytes, -256); $g = new BigInteger($gBytes, -256); $exchange_hash_rfc4419 = $dh_group_sizes_packed . Strings::packSSH2( 'ss', $primeBytes, $gBytes ); $clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT; $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY; } else { switch ($this->kex_algorithm) { // see http://tools.ietf.org/html/rfc2409#section-6.2 and // http://tools.ietf.org/html/rfc2412, appendex E case 'diffie-hellman-group1-sha1': $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; break; // see http://tools.ietf.org/html/rfc3526#section-3 case 'diffie-hellman-group14-sha1': $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; break; } // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1 // the generator field element is 2 (decimal) and the hash function is sha1. $g = new BigInteger(2); $prime = new BigInteger($prime, 16); $clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT; $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY; } switch ($this->kex_algorithm) { case 'diffie-hellman-group-exchange-sha256': $kexHash = new Hash('sha256'); break; default: $kexHash = new Hash('sha1'); } /* To increase the speed of the key exchange, both client and server may reduce the size of their private exponents. It should be at least twice as long as the key material that is generated from the shared secret. For more details, see the paper by van Oorschot and Wiener [VAN-OORSCHOT]. -- http://tools.ietf.org/html/rfc4419#section-6.2 */ $one = new BigInteger(1); $keyLength = min($kexHash->getLengthInBytes(), max($encryptKeyLength, $decryptKeyLength)); $max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength $max = $max->subtract($one); $x = BigInteger::randomRange($one, $max); $e = $g->modPow($x, $prime); $eBytes = $e->toBytes(true); } $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes); $this->send_binary_packet($data); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } if (!strlen($response)) { return false; } list( $type, $server_public_host_key, $fBytes, $this->signature ) = Strings::unpackSSH2('Csss', $response); if ($type != $serverKexReplyMessage) { throw new \UnexpectedValueException('Expected SSH_MSG_KEXDH_REPLY'); } $this->server_public_host_key = $server_public_host_key; list($public_key_format) = Strings::unpackSSH2('s', $server_public_host_key); if (strlen($this->signature) < 4) { return false; } $temp = unpack('Nlength', substr($this->signature, 0, 4)); $this->signature_format = substr($this->signature, 4, $temp['length']); if ($this->kex_algorithm === 'curve25519-sha256@libssh.org') { if (strlen($fBytes) !== 32) { throw new \RuntimeException('Received curve25519 public key of invalid length.'); return false; } $key = new BigInteger(\Sodium\crypto_scalarmult($x, $fBytes), 256); \Sodium\memzero($x); } else { $f = new BigInteger($fBytes, -256); $key = $f->modPow($x, $prime); } $keyBytes = $key->toBytes(true); $this->exchange_hash = Strings::packSSH2('s5', $this->identifier, $this->server_identifier, $kexinit_payload_client, $kexinit_payload_server, $this->server_public_host_key ); $this->exchange_hash.= $exchange_hash_rfc4419; $this->exchange_hash.= Strings::packSSH2('s3', $eBytes, $fBytes, $keyBytes ); $this->exchange_hash = $kexHash->hash($this->exchange_hash); if ($this->session_id === false) { $this->session_id = $this->exchange_hash; } $server_host_key_algorithm = $this->array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms); if ($server_host_key_algorithm === false) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible server host key algorithms found'); } switch ($server_host_key_algorithm) { case 'rsa-sha2-256': case 'rsa-sha2-512': //case 'ssh-rsa': $expected_key_format = 'ssh-rsa'; break; default: $expected_key_format = $server_host_key_algorithm; } if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) { switch (true) { case $this->signature_format == $server_host_key_algorithm: case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512': case $this->signature_format != 'ssh-rsa': $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new \RuntimeException('Server Host Key Algorithm Mismatch'); } } $packet = pack('C', NET_SSH2_MSG_NEWKEYS); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); if ($type != NET_SSH2_MSG_NEWKEYS) { throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS'); } $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); $this->encrypt = self::encryption_algorithm_to_crypt_instance($encrypt); if ($this->encrypt) { if ($this->crypto_engine) { $this->encrypt->setPreferredEngine($this->crypto_engine); } if ($this->encrypt->getBlockLengthInBytes()) { $this->encrypt_block_size = $this->encrypt->getBlockLengthInBytes(); } $this->encrypt->disablePadding(); if ($this->encrypt->usesIV()) { $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id); while ($this->encrypt_block_size > strlen($iv)) { $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); } $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); } switch ($encrypt) { case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': $nonce = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id); $this->encrypt->fixed = substr($nonce, 0, 4); $this->encrypt->invocation_counter = substr($nonce, 4, 8); case 'chacha20-poly1305@openssh.com': break; default: $this->encrypt->enableContinuousBuffer(); } $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id); while ($encryptKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } switch ($encrypt) { case 'chacha20-poly1305@openssh.com': $encryptKeyLength = 32; $this->lengthEncrypt = self::encryption_algorithm_to_crypt_instance($encrypt); $this->lengthEncrypt->setKey(substr($key, 32, 32)); } $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); $this->encrypt->name = $encrypt; } $this->decrypt = self::encryption_algorithm_to_crypt_instance($decrypt); if ($this->decrypt) { if ($this->crypto_engine) { $this->decrypt->setPreferredEngine($this->crypto_engine); } if ($this->decrypt->getBlockLengthInBytes()) { $this->decrypt_block_size = $this->decrypt->getBlockLengthInBytes(); } $this->decrypt->disablePadding(); if ($this->decrypt->usesIV()) { $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id); while ($this->decrypt_block_size > strlen($iv)) { $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv); } $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); } switch ($decrypt) { case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': // see https://tools.ietf.org/html/rfc5647#section-7.1 $nonce = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id); $this->decrypt->fixed = substr($nonce, 0, 4); $this->decrypt->invocation_counter = substr($nonce, 4, 8); case 'chacha20-poly1305@openssh.com': break; default: $this->decrypt->enableContinuousBuffer(); } $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id); while ($decryptKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } switch ($decrypt) { case 'chacha20-poly1305@openssh.com': $decryptKeyLength = 32; $this->lengthDecrypt = self::encryption_algorithm_to_crypt_instance($decrypt); $this->lengthDecrypt->setKey(substr($key, 32, 32)); } $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); $this->decrypt->name = $decrypt; } /* The "arcfour128" algorithm is the RC4 cipher, as described in [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream generated by the cipher MUST be discarded, and the first byte of the first encrypted packet MUST be encrypted using the 1537th byte of keystream. -- http://tools.ietf.org/html/rfc4345#section-4 */ if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') { $this->encrypt->encrypt(str_repeat("\0", 1536)); } if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') { $this->decrypt->decrypt(str_repeat("\0", 1536)); } $mac_algorithm = $this->array_intersect_first($c2s_mac_algorithms, $this->mac_algorithms_client_to_server); if ($mac_algorithm === false) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible client to server message authentication algorithms found'); } if ($this->encrypt->usesNonce()) { $this->hmac_create = new \stdClass; $this->hmac_create->name = $mac_algorithm; $mac_algorithm = 'none'; } $createKeyLength = 0; // ie. $mac_algorithm == 'none' switch ($mac_algorithm) { case 'hmac-sha2-256': $this->hmac_create = new Hash('sha256'); $createKeyLength = 32; break; case 'hmac-sha1': $this->hmac_create = new Hash('sha1'); $createKeyLength = 20; break; case 'hmac-sha1-96': $this->hmac_create = new Hash('sha1-96'); $createKeyLength = 20; break; case 'hmac-md5': $this->hmac_create = new Hash('md5'); $createKeyLength = 16; break; case 'hmac-md5-96': $this->hmac_create = new Hash('md5-96'); $createKeyLength = 16; } if ($this->hmac_create instanceof Hash) { $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id); while ($createKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); $this->hmac_create->name = $mac_algorithm; } $mac_algorithm = $this->array_intersect_first($s2c_mac_algorithms, $this->mac_algorithms_server_to_client); if ($mac_algorithm === false) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible server to client message authentication algorithms found'); } if ($this->decrypt->usesNonce()) { $this->hmac_check = new \stdClass; $this->hmac_check->name = $mac_algorithm; $mac_algorithm = 'none'; } $checkKeyLength = 0; $this->hmac_size = 0; switch ($mac_algorithm) { case 'hmac-sha2-256': $this->hmac_check = new Hash('sha256'); $checkKeyLength = 32; $this->hmac_size = 32; break; case 'hmac-sha1': $this->hmac_check = new Hash('sha1'); $checkKeyLength = 20; $this->hmac_size = 20; break; case 'hmac-sha1-96': $this->hmac_check = new Hash('sha1-96'); $checkKeyLength = 20; $this->hmac_size = 12; break; case 'hmac-md5': $this->hmac_check = new Hash('md5'); $checkKeyLength = 16; $this->hmac_size = 16; break; case 'hmac-md5-96': $this->hmac_check = new Hash('md5-96'); $checkKeyLength = 16; $this->hmac_size = 12; } if ($this->hmac_check instanceof Hash) { $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id); while ($checkKeyLength > strlen($key)) { $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key); } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); $this->hmac_check->name = $mac_algorithm; } $compression_algorithm = $this->array_intersect_first($s2c_compression_algorithms, $this->compression_algorithms_server_to_client); if ($compression_algorithm === false) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible server to client compression algorithms found'); } $this->decompress = $compression_algorithm == 'zlib'; $compression_algorithm = $this->array_intersect_first($c2s_compression_algorithms, $this->compression_algorithms_client_to_server); if ($compression_algorithm === false) { $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new NoSupportedAlgorithmsException('No compatible client to server compression algorithms found'); } $this->compress = $compression_algorithm == 'zlib'; return true; } /** * Maps an encryption algorithm name to the number of key bytes. * * @param string $algorithm Name of the encryption algorithm * @return int|null Number of bytes as an integer or null for unknown * @access private */ private function encryption_algorithm_to_key_size($algorithm) { if ($this->bad_key_size_fix && self::bad_algorithm_candidate($algorithm)) { return 16; } switch ($algorithm) { case 'none': return 0; case 'aes128-gcm@openssh.com': case 'aes128-cbc': case 'aes128-ctr': case 'arcfour': case 'arcfour128': case 'blowfish-cbc': case 'blowfish-ctr': case 'twofish128-cbc': case 'twofish128-ctr': return 16; case '3des-cbc': case '3des-ctr': case 'aes192-cbc': case 'aes192-ctr': case 'twofish192-cbc': case 'twofish192-ctr': return 24; case 'aes256-gcm@openssh.com': case 'aes256-cbc': case 'aes256-ctr': case 'arcfour256': case 'twofish-cbc': case 'twofish256-cbc': case 'twofish256-ctr': return 32; case 'chacha20-poly1305@openssh.com': return 64; } return null; } /** * Maps an encryption algorithm name to an instance of a subclass of * \phpseclib\Crypt\Base. * * @param string $algorithm Name of the encryption algorithm * @return mixed Instance of \phpseclib\Crypt\Base or null for unknown * @access private */ private static function encryption_algorithm_to_crypt_instance($algorithm) { switch ($algorithm) { case '3des-cbc': return new TripleDES('cbc'); case '3des-ctr': return new TripleDES('ctr'); case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': return new Rijndael('cbc'); case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': return new Rijndael('ctr'); case 'blowfish-cbc': return new Blowfish('cbc'); case 'blowfish-ctr': return new Blowfish('ctr'); case 'twofish128-cbc': case 'twofish192-cbc': case 'twofish256-cbc': case 'twofish-cbc': return new Twofish('cbc'); case 'twofish128-ctr': case 'twofish192-ctr': case 'twofish256-ctr': return new Twofish('ctr'); case 'arcfour': case 'arcfour128': case 'arcfour256': return new RC4(); case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': return new Rijndael('gcm'); case 'chacha20-poly1305@openssh.com': return new ChaCha20(); } return null; } /* * Tests whether or not proposed algorithm has a potential for issues * * @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html * @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291 * @param string $algorithm Name of the encryption algorithm * @return bool * @access private */ private static function bad_algorithm_candidate($algorithm) { switch ($algorithm) { case 'arcfour256': case 'aes192-ctr': case 'aes256-ctr': return true; } return false; } /** * Login * * The $password parameter can be a plaintext password, a \phpseclib\Crypt\RSA object or an array * * @param string $username * @param $args[] param mixed $password * @return bool * @see self::_login() * @access public */ public function login($username,...$args) { $this->auth[] = array_merge([$username], $args); return $this->sublogin($username,...$args); } /** * Login Helper * * @param string $username * @param $args[] param mixed $password * @return bool * @see self::_login_helper() * @access private */ protected function sublogin($username,...$args) { if (!($this->bitmap & self::MASK_CONSTRUCTOR)) { if (!$this->connect()) { return false; } } if (empty($args)) { return $this->login_helper($username); } foreach ($args as $arg) { if ($this->login_helper($username, $arg)) { return true; } } return false; } /** * Login Helper * * @param string $username * @param string $password * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @throws \RuntimeException on other errors * @access private * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} * by sending dummy SSH_MSG_IGNORE messages. */ private function login_helper($username, $password = null) { if (!($this->bitmap & self::MASK_CONNECTED)) { return false; } if (!($this->bitmap & self::MASK_LOGIN_REQ)) { $packet = Strings::packSSH2('Cs', NET_SSH2_MSG_SERVICE_REQUEST, 'ssh-userauth'); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { if ($this->retry_connect) { $this->retry_connect = false; if (!$this->connect()) { return false; } return $this->login_helper($username, $password); } $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type, $service) = Strings::unpackSSH2('Cs', $response); if ($type != NET_SSH2_MSG_SERVICE_ACCEPT || $service != 'ssh-userauth') { throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT'); } $this->bitmap |= self::MASK_LOGIN_REQ; } if (strlen($this->last_interactive_response)) { return !is_string($password) && !is_array($password) ? false : $this->keyboard_interactive_process($password); } if ($password instanceof PrivateKey) { return $this->privatekey_login($username, $password); } if ($password instanceof Agent) { return $this->ssh_agent_login($username, $password); } if (is_array($password)) { if ($this->keyboard_interactive_login($username, $password)) { $this->bitmap |= self::MASK_LOGIN; return true; } return false; } if (!is_string($password)) { throw new \UnexpectedValueException('$password needs to either be an instance of \phpseclib\Crypt\Common\PrivateKey, \System\SSH\Agent, an array or a string'); } if (!isset($password)) { $packet = Strings::packSSH2( 'Cs3', NET_SSH2_MSG_USERAUTH_REQUEST, $username, 'ssh-connection', 'none' ); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= self::MASK_LOGIN; return true; //case NET_SSH2_MSG_USERAUTH_FAILURE: default: return false; } } $packet = Strings::packSSH2( 'Cs3bs', NET_SSH2_MSG_USERAUTH_REQUEST, $username, 'ssh-connection', 'password', false, $password ); // remove the username and password from the logged packet if (!defined('NET_SSH2_LOGGING')) { $logged = null; } else { $logged = Strings::packSSH2( 'Cs3bs', NET_SSH2_MSG_USERAUTH_REQUEST, $username, 'ssh-connection', 'password', false, 'password' ); } $this->send_binary_packet($packet, $logged); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; } list($message) = Strings::unpackSSH2('s', $response); $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $message; return $this->disconnect_helper(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_FAILURE: // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees // multi-factor authentication list($auth_methods, $partial_success) = Strings::unpackSSH2('Lb', $response); if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) { if ($this->keyboard_interactive_login($username, $password)) { $this->bitmap |= self::MASK_LOGIN; return true; } return false; } return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= self::MASK_LOGIN; return true; } return false; } /** * Login via keyboard-interactive authentication * * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator. * * @param string $username * @param string $password * @return bool * @access private */ private function keyboard_interactive_login($username, $password) { $packet = Strings::packSSH2( 'Cs5', NET_SSH2_MSG_USERAUTH_REQUEST, $username, 'ssh-connection', 'keyboard-interactive', '', // language tag '' // submethods ); $this->send_binary_packet($packet); return $this->keyboard_interactive_process($password); } /** * Handle the keyboard-interactive requests / responses. * * @param $responses[] * @return bool * @throws \RuntimeException on connection error * @access private */ private function keyboard_interactive_process(...$responses) { if (strlen($this->last_interactive_response)) { $response = $this->last_interactive_response; } else { $orig = $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: list( , // name; may be empty , // instruction; may be empty , // language tag; may be empty $num_prompts ) = Strings::unpackSSH2('s3N', $response); for ($i = 0; $i < count($responses); $i++) { if (is_array($responses[$i])) { foreach ($responses[$i] as $key => $value) { $this->keyboard_requests_responses[$key] = $value; } unset($responses[$i]); } } $responses = array_values($responses); if (isset($this->keyboard_requests_responses)) { for ($i = 0; $i < $num_prompts; $i++) { list( $prompt, // prompt - ie. "Password: "; must not be empty // echo ) = Strings::unpackSSH2('sC', $response); foreach ($this->keyboard_requests_responses as $key => $value) { if (substr($prompt, 0, strlen($key)) == $key) { $responses[] = $value; break; } } } } // see http://tools.ietf.org/html/rfc4256#section-3.2 if (strlen($this->last_interactive_response)) { $this->last_interactive_response = ''; } elseif (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', $this->message_number_log[count($this->message_number_log) - 1] ); } if (!count($responses) && $num_prompts) { $this->last_interactive_response = $orig; return false; } /* After obtaining the requested information from the user, the client MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message. */ // see http://tools.ietf.org/html/rfc4256#section-3.4 $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses)); for ($i = 0; $i < count($responses); $i++) { $packet.= Strings::packSSH2('s', $responses[$i]); $logged.= Strings::packSSH2('s', 'dummy-answer'); } $this->send_binary_packet($packet, $logged); if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', $this->message_number_log[count($this->message_number_log) - 1] ); } /* After receiving the response, the server MUST send either an SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another SSH_MSG_USERAUTH_INFO_REQUEST message. */ // maybe phpseclib should force close the connection after x request / responses? unless something like that is done // there could be an infinite loop of request / responses. return $this->keyboard_interactive_process(); case NET_SSH2_MSG_USERAUTH_SUCCESS: return true; case NET_SSH2_MSG_USERAUTH_FAILURE: return false; } return false; } /** * Login with an ssh-agent provided key * * @param string $username * @param \phpseclib\System\SSH\Agent $agent * @return bool * @access private */ private function ssh_agent_login($username, Agent $agent) { $this->agent = $agent; $keys = $agent->requestIdentities(); foreach ($keys as $key) { if ($this->privatekey_login($username, $key)) { return true; } } return false; } /** * Login with an RSA private key * * @param string $username * @param \phpseclib\Crypt\Common\PrivateKey $privatekey * @return bool * @throws \RuntimeException on connection error * @access private * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} * by sending dummy SSH_MSG_IGNORE messages. */ private function privatekey_login($username, PrivateKey $privatekey) { $publickey = $privatekey->getPublicKey(); if ($publickey instanceof RSA) { $privatekey = $privatekey->withPadding(RSA::SIGNATURE_PKCS1); switch ($this->signature_format) { case 'rsa-sha2-512': $hash = 'sha512'; $signatureType = 'rsa-sha2-512'; break; case 'rsa-sha2-256': $hash = 'sha256'; $signatureType = 'rsa-sha2-256'; break; //case 'ssh-rsa': default: $hash = 'sha1'; $signatureType = 'ssh-rsa'; } } else if ($publickey instanceof ECDSA) { $privatekey = $privatekey->withSignatureFormat('SSH2'); $curveName = $privatekey->getCurve(); switch ($curveName) { case 'Ed25519': $hash = 'sha512'; $signatureType = 'ssh-ed25519'; break; case 'secp256r1': // nistp256 $hash = 'sha256'; $signatureType = 'ecdsa-sha2-nistp256'; break; case 'secp384r1': // nistp384 $hash = 'sha384'; $signatureType = 'ecdsa-sha2-nistp384'; break; case 'secp521r1': // nistp521 $hash = 'sha512'; $signatureType = 'ecdsa-sha2-nistp521'; break; default: if (is_array($curveName)) { throw new UnsupportedCurveException('Specified Curves are not supported by SSH2'); } throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported by phpseclib\'s SSH2 implementation'); } } else if ($publickey instanceof DSA) { $privatekey = $privatekey->withSignatureFormat('SSH2'); $hash = 'sha1'; $signatureType = 'ssh-dss'; } else { throw new UnsupportedAlgorithmException('Please use either an RSA key, an ECDSA one or a DSA key'); } $publickeyStr = $publickey->toString('OpenSSH', ['binary' => true]); $part1 = Strings::packSSH2( 'Csss', NET_SSH2_MSG_USERAUTH_REQUEST, $username, 'ssh-connection', 'publickey' ); $part2 = Strings::packSSH2('ss', $signatureType, $publickeyStr); $packet = $part1 . chr(0) . $part2; $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: list($message) = Strings::unpackSSH2('s', $response); $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $message; return false; case NET_SSH2_MSG_USERAUTH_PK_OK: // we'll just take it on faith that the public key blob and the public key algorithm name are as // they should be if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace( 'UNKNOWN', 'NET_SSH2_MSG_USERAUTH_PK_OK', $this->message_number_log[count($this->message_number_log) - 1] ); } } $packet = $part1 . chr(1) . $part2; $privatekey = $privatekey->withHash($hash); $signature = $privatekey->sign(Strings::packSSH2('s', $this->session_id) . $packet); if ($publickey instanceof RSA) { $signature = Strings::packSSH2('ss', $signatureType, $signature); } $packet.= Strings::packSSH2('s', $signature); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: // either the login is bad or the server employs multi-factor authentication return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap |= self::MASK_LOGIN; return true; } return false; } /** * Set Timeout * * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout. * Setting $timeout to false or 0 will mean there is no timeout. * * @param mixed $timeout * @access public */ public function setTimeout($timeout) { $this->timeout = $this->curTimeout = $timeout; } /** * Get the output from stdError * * @access public */ public function getStdError() { return $this->stdErrorLog; } /** * Execute Command * * If $callback is set to false then \phpseclib\Net\SSH2::get_channel_packet(self::CHANNEL_EXEC) will need to be called manually. * In all likelihood, this is not a feature you want to be taking advantage of. * * @param string $command * @param Callback $callback * @return string * @throws \RuntimeException on connection error * @access public */ public function exec($command, $callback = null) { $this->curTimeout = $this->timeout; $this->is_timeout = false; $this->stdErrorLog = ''; if (!$this->isAuthenticated()) { return false; } if ($this->in_request_pty_exec) { throw new \RuntimeException('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.'); } // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, // honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway. // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info $this->window_size_server_to_client[self::CHANNEL_EXEC] = $this->window_size; // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy // uses 0x4000, that's what will be used here, as well. $packet_size = 0x4000; $packet = Strings::packSSH2( 'CsN3', NET_SSH2_MSG_CHANNEL_OPEN, 'session', self::CHANNEL_EXEC, $this->window_size_server_to_client[self::CHANNEL_EXEC], $packet_size ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->get_channel_packet(self::CHANNEL_EXEC); if ($response === false) { return false; } if ($this->request_pty === true) { $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = Strings::packSSH2( 'CNsCsN4s', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL_EXEC], 'pty-req', 1, 'vt100', $this->windowColumns, $this->windowRows, 0, 0, $terminal_modes ); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: break; case NET_SSH2_MSG_CHANNEL_FAILURE: default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); throw new \RuntimeException('Unable to request pseudo-terminal'); } $this->in_request_pty_exec = true; } // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things // down. the one place where it might be desirable is if you're doing something like \phpseclib\Net\SSH2::exec('ping localhost &'). // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then // then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but // neither will your script. // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates. $packet = Strings::packSSH2( 'CNsCs', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL_EXEC], 'exec', 1, $command ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->get_channel_packet(self::CHANNEL_EXEC); if ($response === false) { return false; } $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; if ($callback === false || $this->in_request_pty_exec) { return true; } $output = ''; while (true) { $temp = $this->get_channel_packet(self::CHANNEL_EXEC); switch (true) { case $temp === true: return is_callable($callback) ? true : $output; case $temp === false: return false; default: if (is_callable($callback)) { if (call_user_func($callback, $temp) === true) { $this->close_channel(self::CHANNEL_EXEC); return true; } } else { $output.= $temp; } } } } /** * Creates an interactive shell * * @see self::read() * @see self::write() * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @throws \RuntimeException on other errors * @access private */ private function initShell() { if ($this->in_request_pty_exec === true) { return true; } $this->window_size_server_to_client[self::CHANNEL_SHELL] = $this->window_size; $packet_size = 0x4000; $packet = Strings::packSSH2( 'CsN3', NET_SSH2_MSG_CHANNEL_OPEN, 'session', self::CHANNEL_SHELL, $this->window_size_server_to_client[self::CHANNEL_SHELL], $packet_size ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->get_channel_packet(self::CHANNEL_SHELL); if ($response === false) { return false; } $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = Strings::packSSH2( 'CNsCsN4s', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL_SHELL], 'pty-req', 1, 'vt100', $this->windowColumns, $this->windowRows, 0, 0, $terminal_modes ); $this->send_binary_packet($packet); $response = $this->get_binary_packet(); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: // if a pty can't be opened maybe commands can still be executed case NET_SSH2_MSG_CHANNEL_FAILURE: break; default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); throw new \UnexpectedValueException('Unable to request pseudo-terminal'); } $packet = Strings::packSSH2( 'CNsb', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL_SHELL], 'shell', true // want reply ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->get_channel_packet(self::CHANNEL_SHELL); if ($response === false) { return false; } $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap |= self::MASK_SHELL; return true; } /** * Return the channel to be used with read() / write() * * @see self::read() * @see self::write() * @return int * @access public */ private function get_interactive_channel() { switch (true) { case $this->in_subsystem: return self::CHANNEL_SUBSYSTEM; case $this->in_request_pty_exec: return self::CHANNEL_EXEC; default: return self::CHANNEL_SHELL; } } /** * Return an available open channel * * @return int * @access public */ private function get_open_channel() { $channel = self::CHANNEL_EXEC; do { if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) { return $channel; } } while ($channel++ < self::CHANNEL_SUBSYSTEM); return false; } /** * Request agent forwarding of remote server * * @return bool * @access public */ public function requestAgentForwarding() { $request_channel = $this->get_open_channel(); if ($request_channel === false) { return false; } $packet = Strings::packSSH2( 'CNsC', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[$request_channel], 'auth-agent-req@openssh.com', 1 ); $this->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST; $this->send_binary_packet($packet); $response = $this->get_channel_packet($request_channel); if ($response === false) { return false; } $this->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN; return true; } /** * Returns the output of an interactive shell * * Returns when there's a match for $expect, which can take the form of a string literal or, * if $mode == self::READ_REGEX, a regular expression. * * @see self::write() * @param string $expect * @param int $mode * @return string|bool|null * @throws \RuntimeException on connection error * @access public */ public function read($expect = '', $mode = self::READ_SIMPLE) { $this->curTimeout = $this->timeout; $this->is_timeout = false; if (!$this->isAuthenticated()) { throw new \RuntimeException('Operation disallowed prior to login()'); } if (!($this->bitmap & self::MASK_SHELL) && !$this->initShell()) { throw new \RuntimeException('Unable to initiate an interactive shell session'); } $channel = $this->get_interactive_channel(); if ($mode == self::READ_NEXT) { return $this->get_channel_packet($channel); } $match = $expect; while (true) { if ($mode == self::READ_REGEX) { preg_match($expect, substr($this->interactiveBuffer, -1024), $matches); $match = isset($matches[0]) ? $matches[0] : ''; } $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false; if ($pos !== false) { return Strings::shift($this->interactiveBuffer, $pos + strlen($match)); } $response = $this->get_channel_packet($channel); if (is_bool($response)) { $this->in_request_pty_exec = false; return $response ? Strings::shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false; } $this->interactiveBuffer.= $response; } } /** * Inputs a command into an interactive shell. * * @see self::read() * @param string $cmd * @return bool * @throws \RuntimeException on connection error * @access public */ public function write($cmd) { if (!$this->isAuthenticated()) { throw new \RuntimeException('Operation disallowed prior to login()'); } if (!($this->bitmap & self::MASK_SHELL) && !$this->initShell()) { throw new \RuntimeException('Unable to initiate an interactive shell session'); } return $this->send_channel_packet($this->get_interactive_channel(), $cmd); } /** * Start a subsystem. * * Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept * a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened. * To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and * returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented * if there's sufficient demand for such a feature. * * @see self::stopSubsystem() * @param string $subsystem * @return bool * @access public */ public function startSubsystem($subsystem) { $this->window_size_server_to_client[self::CHANNEL_SUBSYSTEM] = $this->window_size; $packet = Strings::packSSH2( 'CsN3', NET_SSH2_MSG_CHANNEL_OPEN, 'session', self::CHANNEL_SUBSYSTEM, $this->window_size, 0x4000 ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->get_channel_packet(self::CHANNEL_SUBSYSTEM); if ($response === false) { return false; } $packet = Strings::packSSH2( 'CNsCs', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL_SUBSYSTEM], 'subsystem', 1, $subsystem ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->get_channel_packet(self::CHANNEL_SUBSYSTEM); if ($response === false) { return false; } $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap |= self::MASK_SHELL; $this->in_subsystem = true; return true; } /** * Stops a subsystem. * * @see self::startSubsystem() * @return bool * @access public */ public function stopSubsystem() { $this->in_subsystem = false; $this->close_channel(self::CHANNEL_SUBSYSTEM); return true; } /** * Closes a channel * * If read() timed out you might want to just close the channel and have it auto-restart on the next read() call * * @access public */ public function reset() { $this->close_channel($this->get_interactive_channel()); } /** * Is timeout? * * Did exec() or read() return because they timed out or because they encountered the end? * * @access public */ public function isTimeout() { return $this->is_timeout; } /** * Disconnect * * @access public */ public function disconnect() { $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) { fclose($this->realtime_log_file); } unset(self::$connections[$this->getResourceId()]); } /** * Destructor. * * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call * disconnect(). * * @access public */ public function __destruct() { $this->disconnect(); } /** * Is the connection still active? * * @return bool * @access public */ public function isConnected() { return (bool) ($this->bitmap & self::MASK_CONNECTED); } /** * Have you successfully been logged in? * * @return bool * @access public */ public function isAuthenticated() { return (bool) ($this->bitmap & self::MASK_LOGIN); } /** * Pings a server connection, or tries to reconnect if the connection has gone down * * Inspired by http://php.net/manual/en/mysqli.ping.php * * @return bool */ public function ping() { if (!$this->isAuthenticated()) { return false; } $this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE] = $this->window_size; $packet_size = 0x4000; $packet = Strings::packSSH2( 'CsN3', NET_SSH2_MSG_CHANNEL_OPEN, 'session', self::CHANNEL_KEEP_ALIVE, $this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE], $packet_size ); try { $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->get_channel_packet(self::CHANNEL_KEEP_ALIVE); } catch (\RuntimeException $e) { return $this->reconnect(); } $this->close_channel(NET_SSH2_CHANNEL_KEEP_ALIVE); return true; } /** * In situ reconnect method * * @return boolean */ private function reconnect() { $this->reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST); $this->retry_connect = true; if (!$this->connect()) { return false; } foreach ($this->auth as $auth) { $result = $this->login(...$auth); } return $result; } /** * Resets a connection for re-use * * @param int $reason * @access private */ private function reset_connection($reason) { $this->disconnect_helper($reason); $this->decrypt = $this->encrypt = false; $this->decrypt_block_size = $this->encrypt_block_size = 8; $this->hmac_check = $this->hmac_create = false; $this->hmac_size = false; $this->session_id = false; $this->retry_connect = true; $this->get_seq_no = $this->send_seq_no = 0; } /** * Gets Binary Packets * * See '6. Binary Packet Protocol' of rfc4253 for more info. * * @see self::_send_binary_packet() * @param bool $filter_channel_packets * @return string * @access private */ private function get_binary_packet($skip_channel_filter = false) { if (!is_resource($this->fsock) || feof($this->fsock)) { $this->bitmap = 0; throw new \RuntimeException('Connection closed prematurely'); } $start = microtime(true); $raw = stream_get_contents($this->fsock, $this->decrypt_block_size); if (!strlen($raw)) { return ''; } if ($this->decrypt) { switch ($this->decrypt->name) { case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': $this->decrypt->setNonce( $this->decrypt->fixed . $this->decrypt->invocation_counter ); Strings::increment_str($this->decrypt->invocation_counter); $this->decrypt->setAAD($temp = Strings::shift($raw, 4)); extract(unpack('Npacket_length', $temp)); /** * @var integer $packet_length */ $raw.= $this->read_remaining_bytes($packet_length - $this->decrypt_block_size + 4); $stop = microtime(true); $tag = stream_get_contents($this->fsock, $this->decrypt_block_size); $this->decrypt->setTag($tag); $raw = $this->decrypt->decrypt($raw); $raw = $temp . $raw; $remaining_length = 0; break; case 'chacha20-poly1305@openssh.com': $nonce = pack('N2', 0, $this->get_seq_no); $this->lengthDecrypt->setNonce($nonce); $temp = $this->lengthDecrypt->decrypt($aad = Strings::shift($raw, 4)); extract(unpack('Npacket_length', $temp)); /** * @var integer $packet_length */ $raw.= $this->read_remaining_bytes($packet_length - $this->decrypt_block_size + 4); $stop = microtime(true); $tag = stream_get_contents($this->fsock, 16); $this->decrypt->setNonce($nonce); $this->decrypt->setCounter(0); // this is the same approach that's implemented in Salsa20::createPoly1305Key() // but we don't want to use the same AEAD construction that RFC8439 describes // for ChaCha20-Poly1305 so we won't rely on it (see Salsa20::poly1305()) $this->decrypt->setPoly1305Key( $this->decrypt->encrypt(str_repeat("\0", 32)) ); $this->decrypt->setAAD($aad); $this->decrypt->setCounter(1); $this->decrypt->setTag($tag); $raw = $this->decrypt->decrypt($raw); $raw = $temp . $raw; $remaining_length = 0; break; default: $raw = $this->decrypt->decrypt($raw); } } if (strlen($raw) < 5) { return false; } extract(unpack('Npacket_length/Cpadding_length', Strings::shift($raw, 5))); /** * @var integer $packet_length * @var integer $padding_length */ if (!isset($remaining_length)) { $remaining_length = $packet_length + 4 - $this->decrypt_block_size; } $buffer = $this->read_remaining_bytes($remaining_length); if (!isset($stop)) { $stop = microtime(true); } if (strlen($buffer)) { $raw.= $this->decrypt ? $this->decrypt->decrypt($buffer) : $buffer; } $payload = Strings::shift($raw, $packet_length - $padding_length - 1); $padding = Strings::shift($raw, $padding_length); // should leave $raw empty if ($this->hmac_check instanceof Hash) { $hmac = stream_get_contents($this->fsock, $this->hmac_size); if ($hmac === false || strlen($hmac) != $this->hmac_size) { $this->bitmap = 0; throw new \RuntimeException('Error reading socket'); } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { throw new \RuntimeException('Invalid HMAC'); } } //if ($this->decompress) { // $payload = gzinflate(substr($payload, 2)); //} $this->get_seq_no++; if (defined('NET_SSH2_LOGGING')) { $current = microtime(true); $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')'; $message_number = '<- ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; $this->append_log($message_number, $payload); $this->last_packet = $current; } return $this->filter($payload, $skip_channel_filter); } /** * Read Remaining Bytes * * @see self::get_binary_packet() * @param int $remaining_length * @return string * @access private */ private function read_remaining_bytes($remaining_length) { if (!$remaining_length) { return ''; } $adjustLength = false; if ($this->decrypt) { switch ($this->decrypt->name) { case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': case 'chacha20-poly1305@openssh.com': $remaining_length+= $this->decrypt_block_size - 4; $adjustLength = true; } } // quoting <http://tools.ietf.org/html/rfc4253#section-6.1>, // "implementations SHOULD check that the packet length is reasonable" // PuTTY uses 0x9000 as the actual max packet size and so to shall we // don't do this when GCM mode is used since GCM mode doesn't encrypt the length if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) { if (!$this->bad_key_size_fix && self::bad_algorithm_candidate($this->decrypt ? $this->decrypt->name : '') && !($this->bitmap & SSH2::MASK_LOGIN)) { $this->bad_key_size_fix = true; $this->reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); return false; } throw new \RuntimeException('Invalid size'); } if ($adjustLength) { $remaining_length-= $this->decrypt_block_size - 4; } $buffer = ''; while ($remaining_length > 0) { $temp = stream_get_contents($this->fsock, $remaining_length); if ($temp === false || feof($this->fsock)) { $this->bitmap = 0; throw new \RuntimeException('Error reading from socket'); } $buffer.= $temp; $remaining_length-= strlen($temp); } return $buffer; } /** * Filter Binary Packets * * Because some binary packets need to be ignored... * * @see self::_get_binary_packet() * @param string $payload * @param bool $filter_channel_packets * @return string * @access private */ private function filter($payload, $skip_channel_filter) { switch (ord($payload[0])) { case NET_SSH2_MSG_DISCONNECT: Strings::shift($payload, 1); list($reason_code, $message) = Strings::unpackSSH2('Ns', $payload); $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n$message"; $this->bitmap = 0; return false; case NET_SSH2_MSG_IGNORE: $payload = $this->get_binary_packet($skip_channel_filter); break; case NET_SSH2_MSG_DEBUG: Strings::shift($payload, 2); // second byte is "always_display" list($message) = Strings::unpackSSH2('s', $payload); $this->errors[] = "SSH_MSG_DEBUG: $message"; $payload = $this->get_binary_packet($skip_channel_filter); break; case NET_SSH2_MSG_UNIMPLEMENTED: return false; case NET_SSH2_MSG_KEXINIT: if ($this->session_id !== false) { if (!$this->key_exchange($payload)) { $this->bitmap = 0; return false; } $payload = $this->get_binary_packet($skip_channel_filter); } } // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { Strings::shift($payload, 1); list($this->banner_message) = Strings::unpackSSH2('s', $response); $payload = $this->get_binary_packet(); } // only called when we've already logged in if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) { switch (ord($payload[0])) { case NET_SSH2_MSG_CHANNEL_DATA: case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: case NET_SSH2_MSG_CHANNEL_REQUEST: case NET_SSH2_MSG_CHANNEL_CLOSE: case NET_SSH2_MSG_CHANNEL_EOF: if (!$skip_channel_filter && !empty($this->server_channels)) { $this->binary_packet_buffer = $payload; $this->get_channel_packet(true); $payload = $this->get_binary_packet(); } break; case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 Strings::shift($payload, 1); list($request_name) = Strings::unpackSSH2('s', $payload); $this->errors[] = "SSH_MSG_GLOBAL_REQUEST: $request_name"; try { $this->send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE)); } catch (\RuntimeException $e) { return $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->get_binary_packet($skip_channel_filter); break; case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 Strings::shift($payload, 1); list($data, $server_channel) = Strings::unpackSSH2('sN', $payload); switch ($data) { case 'auth-agent': case 'auth-agent@openssh.com': if (isset($this->agent)) { $new_channel = self::CHANNEL_AGENT_FORWARD; list( $remote_window_size, $remote_maximum_packet_size ) = Strings::unpackSSH2('NN', $payload); $this->packet_size_client_to_server[$new_channel] = $remote_window_size; $this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size; $this->window_size_client_to_server[$new_channel] = $this->window_size; $packet_size = 0x4000; $packet = pack( 'CN4', NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, $server_channel, $new_channel, $packet_size, $packet_size ); $this->server_channels[$new_channel] = $server_channel; $this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION; $this->send_binary_packet($packet); } break; default: $packet = Strings::packSSH2( 'CN2ss', NET_SSH2_MSG_CHANNEL_OPEN_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, '', // description '' // language tag ); try { $this->send_binary_packet($packet); } catch (\RuntimeException $e) { return $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); } } $payload = $this->get_binary_packet($skip_channel_filter); break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: Strings::shift($payload, 1); list($channel, $window_size) = Strings::unpackSSH2('NN', $payload); $this->window_size_client_to_server[$channel]+= $window_size; $payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->get_binary_packet($skip_channel_filter); } } return $payload; } /** * Enable Quiet Mode * * Suppress stderr from output * * @access public */ public function enableQuietMode() { $this->quiet_mode = true; } /** * Disable Quiet Mode * * Show stderr in output * * @access public */ public function disableQuietMode() { $this->quiet_mode = false; } /** * Returns whether Quiet Mode is enabled or not * * @see self::enableQuietMode() * @see self::disableQuietMode() * @access public * @return bool */ public function isQuietModeEnabled() { return $this->quiet_mode; } /** * Enable request-pty when using exec() * * @access public */ public function enablePTY() { $this->request_pty = true; } /** * Disable request-pty when using exec() * * @access public */ public function disablePTY() { if ($this->in_request_pty_exec) { $this->close_channel(self::CHANNEL_EXEC); $this->in_request_pty_exec = false; } $this->request_pty = false; } /** * Returns whether request-pty is enabled or not * * @see self::enablePTY() * @see self::disablePTY() * @access public * @return bool */ public function isPTYEnabled() { return $this->request_pty; } /** * Gets channel data * * Returns the data as a string if it's available and false if not. * * @param int $client_channel * @param bool $skip_extended * @return mixed * @throws \RuntimeException on connection error * @access private */ protected function get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { return array_shift($this->channel_buffers[$client_channel]); } while (true) { if ($this->binary_packet_buffer !== false) { $response = $this->binary_packet_buffer; $this->binary_packet_buffer = false; } else { $read = [$this->fsock]; $write = $except = null; if (!$this->curTimeout) { @stream_select($read, $write, $except, null); } else { if ($this->curTimeout < 0) { $this->is_timeout = true; return true; } $read = [$this->fsock]; $write = $except = null; $start = microtime(true); $sec = floor($this->curTimeout); $usec = 1000000 * ($this->curTimeout - $sec); // on windows this returns a "Warning: Invalid CRT parameters detected" error if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { $this->is_timeout = true; $this->close_channel($client_channel); return true; } $elapsed = microtime(true) - $start; $this->curTimeout-= $elapsed; } $response = $this->get_binary_packet(true); if ($response === false) { $this->bitmap = 0; throw new \RuntimeException('Connection closed by server'); } } if ($client_channel == -1 && $response === true) { return true; } list($type, $channel) = Strings::unpackSSH2('CN', $response); // will not be setup yet on incoming channel open request if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) { $this->window_size_server_to_client[$channel]-= strlen($response); // resize the window, if appropriate if ($this->window_size_server_to_client[$channel] < 0) { $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size); $this->send_binary_packet($packet); $this->window_size_server_to_client[$channel]+= $this->window_size; } switch ($type) { case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: /* if ($client_channel == NET_SSH2_CHANNEL_EXEC) { $this->send_channel_packet($client_channel, chr(0)); } */ // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR list($data_type_code, $data) = Strings::unpackSSH2('Ns', $response); $this->stdErrorLog.= $data; if ($skip_extended || $this->quiet_mode) { continue 2; } if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) { return $data; } if (!isset($this->channel_buffers[$channel])) { $this->channel_buffers[$channel] = []; } $this->channel_buffers[$channel][] = $data; continue 2; case NET_SSH2_MSG_CHANNEL_REQUEST: if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) { continue 2; } list($value) = Strings::unpackSSH2('s', $response); switch ($value) { case 'exit-signal': list( , // FALSE $signal_name, , // core dumped $error_message ) = Strings::unpackSSH2('bsbs', $response); $this->errors[] = "SSH_MSG_CHANNEL_REQUEST (exit-signal): $signal_name"; if (strlen($error_message)) { $this->errors[count($this->errors) - 1].= "\r\n$error_message"; } $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF; continue 3; case 'exit-status': list(, $this->exit_status) = Strings::unpackSSH2('CN', $response); // "The client MAY ignore these messages." // -- http://tools.ietf.org/html/rfc4254#section-6.10 continue 3; default: // "Some systems may not implement signals, in which case they SHOULD ignore this message." // -- http://tools.ietf.org/html/rfc4254#section-6.9 continue 3; } } switch ($this->channel_status[$channel]) { case NET_SSH2_MSG_CHANNEL_OPEN: switch ($type) { case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: list( $this->server_channels[$channel], $window_size, $this->packet_size_client_to_server[$channel] ) = Strings::unpackSSH2('NNN', $response); if ($window_size < 0) { $window_size&= 0x7FFFFFFF; $window_size+= 0x80000000; } $this->window_size_client_to_server[$channel] = $window_size; $result = $client_channel == $channel ? true : $this->get_channel_packet($client_channel, $skip_extended); $this->on_channel_open(); return $result; //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE: default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); throw new \RuntimeException('Unable to open channel'); } break; case NET_SSH2_MSG_CHANNEL_REQUEST: switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: return true; case NET_SSH2_MSG_CHANNEL_FAILURE: return false; default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); throw new \RuntimeException('Unable to fulfill channel request'); } case NET_SSH2_MSG_CHANNEL_CLOSE: return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->get_channel_packet($client_channel, $skip_extended); } } // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: /* if ($channel == self::CHANNEL_EXEC) { // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server // this actually seems to make things twice as fast. more to the point, the message right after // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise. // in OpenSSH it slows things down but only by a couple thousandths of a second. $this->send_channel_packet($channel, chr(0)); } */ list($data) = Strings::unpackSSH2('s', $response); if ($channel == self::CHANNEL_AGENT_FORWARD) { $agent_response = $this->agent->forwardData($data); if (!is_bool($agent_response)) { $this->send_channel_packet($channel, $agent_response); } break; } if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$channel])) { $this->channel_buffers[$channel] = []; } $this->channel_buffers[$channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_CLOSE: $this->curTimeout = 0; if ($this->bitmap & self::MASK_SHELL) { $this->bitmap&= ~self::MASK_SHELL; } if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); } $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE; if ($client_channel == $channel) { return true; } case NET_SSH2_MSG_CHANNEL_EOF: break; default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); throw new \RuntimeException('Error reading channel data'); } } } /** * Sends Binary Packets * * See '6. Binary Packet Protocol' of rfc4253 for more info. * * @param string $data * @param string $logged * @see self::_get_binary_packet() * @return bool * @access private */ protected function send_binary_packet($data, $logged = null) { if (!is_resource($this->fsock) || feof($this->fsock)) { $this->bitmap = 0; throw new \RuntimeException('Connection closed prematurely'); } //if ($this->compress) { // // the -4 removes the checksum: // // http://php.net/function.gzcompress#57710 // $data = substr(gzcompress($data), 0, -4); //} // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9 $packet_length = strlen($data) + 9; if ($this->encrypt && $this->encrypt->usesNonce()) { $packet_length-= 4; } // round up to the nearest $this->encrypt_block_size $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size; // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length $padding_length = $packet_length - strlen($data) - 5; if ($this->encrypt && $this->encrypt->usesNonce()) { $padding_length+= 4; $packet_length+= 4; } $padding = Random::string($padding_length); // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding); $hmac = $this->hmac_create instanceof Hash ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : ''; $this->send_seq_no++; if ($this->encrypt) { switch ($this->encrypt->name) { case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': $this->encrypt->setNonce( $this->encrypt->fixed . $this->encrypt->invocation_counter ); Strings::increment_str($this->encrypt->invocation_counter); $this->encrypt->setAAD($temp = ($packet & "\xFF\xFF\xFF\xFF")); $packet = $temp . $this->encrypt->encrypt(substr($packet, 4)); break; case 'chacha20-poly1305@openssh.com': $nonce = pack('N2', 0, $this->send_seq_no - 1); $this->encrypt->setNonce($nonce); $this->lengthEncrypt->setNonce($nonce); $length = $this->lengthEncrypt->encrypt($packet & "\xFF\xFF\xFF\xFF"); $this->encrypt->setCounter(0); // this is the same approach that's implemented in Salsa20::createPoly1305Key() // but we don't want to use the same AEAD construction that RFC8439 describes // for ChaCha20-Poly1305 so we won't rely on it (see Salsa20::poly1305()) $this->encrypt->setPoly1305Key( $this->encrypt->encrypt(str_repeat("\0", 32)) ); $this->encrypt->setAAD($length); $this->encrypt->setCounter(1); $packet = $length . $this->encrypt->encrypt(substr($packet, 4)); break; default: $packet = $this->encrypt->encrypt($packet); } } $packet.= $this->encrypt && $this->encrypt->usesNonce() ? $this->encrypt->getTag() : $hmac; $start = microtime(true); $sent = fputs($this->fsock, $packet); $stop = microtime(true); if (defined('NET_SSH2_LOGGING')) { $current = microtime(true); $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')'; $message_number = '-> ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; $this->append_log($message_number, isset($logged) ? $logged : $data); $this->last_packet = $current; } if (strlen($packet) != $sent) { $this->bitmap = 0; throw new \RuntimeException("Only $sent of " . strlen($packet) . " bytes were sent"); } } /** * Logs data packets * * Makes sure that only the last 1MB worth of packets will be logged * * @param string $message_number * @param string $message * @access private */ private function append_log($message_number, $message) { // remove the byte identifying the message type from all but the first two messages (ie. the identification strings) if (strlen($message_number) > 2) { Strings::shift($message); } switch (NET_SSH2_LOGGING) { // useful for benchmarks case self::LOG_SIMPLE: $this->message_number_log[] = $message_number; break; // the most useful log for SSH2 case self::LOG_COMPLEX: $this->message_number_log[] = $message_number; $this->log_size+= strlen($message); $this->message_log[] = $message; while ($this->log_size > self::LOG_MAX_SIZE) { $this->log_size-= strlen(array_shift($this->message_log)); array_shift($this->message_number_log); } break; // dump the output out realtime; packets may be interspersed with non packets, // passwords won't be filtered out and select other packets may not be correctly // identified case self::LOG_REALTIME: switch (PHP_SAPI) { case 'cli': $start = $stop = "\r\n"; break; default: $start = '<pre>'; $stop = '</pre>'; } echo $start . $this->format_log([$message], [$message_number]) . $stop; @flush(); @ob_flush(); break; // basically the same thing as self::LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILENAME // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE. // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily // at the beginning of the file case self::LOG_REALTIME_FILE: if (!isset($this->realtime_log_file)) { // PHP doesn't seem to like using constants in fopen() $filename = NET_SSH2_LOG_REALTIME_FILENAME; $fp = fopen($filename, 'w'); $this->realtime_log_file = $fp; } if (!is_resource($this->realtime_log_file)) { break; } $entry = $this->format_log([$message], [$message_number]); if ($this->realtime_log_wrap) { $temp = "<<< START >>>\r\n"; $entry.= $temp; fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp)); } $this->realtime_log_size+= strlen($entry); if ($this->realtime_log_size > self::LOG_MAX_SIZE) { fseek($this->realtime_log_file, 0); $this->realtime_log_size = strlen($entry); $this->realtime_log_wrap = true; } fputs($this->realtime_log_file, $entry); } } /** * Sends channel data * * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate * * @param int $client_channel * @param string $data * @return bool * @access private */ protected function send_channel_packet($client_channel, $data) { while (strlen($data)) { if (!$this->window_size_client_to_server[$client_channel]) { $this->bitmap^= self::MASK_WINDOW_ADJUST; // using an invalid channel will let the buffers be built up for the valid channels $this->get_channel_packet(-1); $this->bitmap^= self::MASK_WINDOW_ADJUST; } /* The maximum amount of data allowed is determined by the maximum packet size for the channel, and the current window size, whichever is smaller. -- http://tools.ietf.org/html/rfc4254#section-5.2 */ $max_size = min( $this->packet_size_client_to_server[$client_channel], $this->window_size_client_to_server[$client_channel] ); $temp = Strings::shift($data, $max_size); $packet = Strings::packSSH2( 'CNs', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], $temp ); $this->window_size_client_to_server[$client_channel]-= strlen($temp); $this->send_binary_packet($packet); } return true; } /** * Closes and flushes a channel * * \phpseclib\Net\SSH2 doesn't properly close most channels. For exec() channels are normally closed by the server * and for SFTP channels are presumably closed when the client disconnects. This functions is intended * for SCP more than anything. * * @param int $client_channel * @param bool $want_reply * @return bool * @access private */ private function close_channel($client_channel, $want_reply = false) { // see http://tools.ietf.org/html/rfc4254#section-5.3 $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel])); if (!$want_reply) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); } $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE; $this->curTimeout = 0; while (!is_bool($this->get_channel_packet($client_channel))) { } if ($want_reply) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel])); } if ($this->bitmap & self::MASK_SHELL) { $this->bitmap&= ~self::MASK_SHELL; } } /** * Disconnect * * @param int $reason * @return bool * @access protected */ protected function disconnect_helper($reason) { if ($this->bitmap & self::MASK_CONNECTED) { $data = Strings::packSSH2('CNss', NET_SSH2_MSG_DISCONNECT, $reason, '', ''); $this->send_binary_packet($data); $this->bitmap = 0; fclose($this->fsock); return false; } } /** * Define Array * * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of * named constants from it, using the value as the name of the constant and the index as the value of the constant. * If any of the constants that would be defined already exists, none of the constants will be defined. * * @param $args[] * @access protected */ protected function define_array(...$args) { foreach ($args as $arg) { foreach ($arg as $key => $value) { if (!defined($value)) { define($value, $key); } else { break 2; } } } } /** * Returns a log of the packets that have been sent and received. * * Returns a string if NET_SSH2_LOGGING == self::LOG_COMPLEX, an array if NET_SSH2_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING') * * @access public * @return array|false|string */ public function getLog() { if (!defined('NET_SSH2_LOGGING')) { return false; } switch (NET_SSH2_LOGGING) { case self::LOG_SIMPLE: return $this->message_number_log; case self::LOG_COMPLEX: $log = $this->format_log($this->message_log, $this->message_number_log); return PHP_SAPI == 'cli' ? $log : '<pre>' . $log . '</pre>'; default: return false; } } /** * Formats a log for printing * * @param array $message_log * @param array $message_number_log * @access private * @return string */ protected function format_log($message_log, $message_number_log) { $output = ''; for ($i = 0; $i < count($message_log); $i++) { $output.= $message_number_log[$i] . "\r\n"; $current_log = $message_log[$i]; $j = 0; do { if (strlen($current_log)) { $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; } $fragment = Strings::shift($current_log, $this->log_short_width); $hex = substr(preg_replace_callback('#.#s', [$this, 'format_log_helper'], $fragment), strlen($this->log_boundary)); // replace non ASCII printable characters with dots // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters // also replace < with a . since < messes up the output on web browsers $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n"; $j++; } while (strlen($current_log)); $output.= "\r\n"; } return $output; } /** * Helper function for _format_log * * For use with preg_replace_callback() * * @param array $matches * @access private * @return string */ private function format_log_helper($matches) { return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT); } /** * Helper function for agent->on_channel_open() * * Used when channels are created to inform agent * of said channel opening. Must be called after * channel open confirmation received * * @access private */ private function on_channel_open() { if (isset($this->agent)) { $this->agent->registerChannelOpen($this); } } /** * Returns the first value of the intersection of two arrays or false if * the intersection is empty. The order is defined by the first parameter. * * @param array $array1 * @param array $array2 * @return mixed False if intersection is empty, else intersected value. * @access private */ private function array_intersect_first($array1, $array2) { foreach ($array1 as $value) { if (in_array($value, $array2)) { return $value; } } return false; } /** * Returns all errors * * @return string[] * @access public */ public function getErrors() { return $this->errors; } /** * Returns the last error * * @return string * @access public */ public function getLastError() { $count = count($this->errors); if ($count > 0) { return $this->errors[$count - 1]; } } /** * Return the server identification. * * @return string * @access public */ public function getServerIdentification() { $this->connect(); return $this->server_identifier; } /** * Returns a list of algorithms the server supports * * @return array * @access public */ public function getServerAlgorithms() { $this->connect(); return [ 'kex' => $this->kex_algorithms, 'hostkey' => $this->server_host_key_algorithms, 'client_to_server' => [ 'crypt' => $this->encryption_algorithms_client_to_server, 'mac' => $this->mac_algorithms_client_to_server, 'comp' => $this->compression_algorithms_client_to_server, 'lang' => $this->languages_client_to_server ], 'server_to_client' => [ 'crypt' => $this->encryption_algorithms_server_to_client, 'mac' => $this->mac_algorithms_server_to_client, 'comp' => $this->compression_algorithms_server_to_client, 'lang' => $this->languages_server_to_client ] ]; } /** * Returns a list of KEX algorithms that phpseclib supports * * @return array * @access public */ public static function getSupportedKEXAlgorithms() { $kex_algorithms = [ // Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using // Curve25519. See doc/curve25519-sha256@libssh.org.txt in the // libssh repository for more information. 'curve25519-sha256@libssh.org', // Diffie-Hellman Key Agreement (DH) using integer modulo prime // groups. 'diffie-hellman-group1-sha1', // REQUIRED 'diffie-hellman-group14-sha1', // REQUIRED 'diffie-hellman-group-exchange-sha1', // RFC 4419 'diffie-hellman-group-exchange-sha256', // RFC 4419 ]; if (!function_exists('\\Sodium\\library_version_major')) { $kex_algorithms = array_diff( $kex_algorithms, ['curve25519-sha256@libssh.org'] ); } return $kex_algorithms; } /** * Returns a list of host key algorithms that phpseclib supports * * @return array * @access public */ public static function getSupportedHostKeyAlgorithms() { return [ 'ssh-ed25519', // https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-02 'ecdsa-sha2-nistp256', // RFC 5656 'ecdsa-sha2-nistp384', // RFC 5656 'ecdsa-sha2-nistp521', // RFC 5656 'rsa-sha2-256', // RFC 8332 'rsa-sha2-512', // RFC 8332 'ssh-rsa', // RECOMMENDED sign Raw RSA Key 'ssh-dss' // REQUIRED sign Raw DSS Key ]; } /** * Returns a list of symmetric key algorithms that phpseclib supports * * @return array * @access public */ public static function getSupportedEncryptionAlgorithms() { $algos = [ // from <https://tools.ietf.org/html/rfc5647>: 'aes128-gcm@openssh.com', 'aes256-gcm@openssh.com', // from <http://tools.ietf.org/html/rfc4345#section-4>: 'arcfour256', 'arcfour128', //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key // CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>: 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key 'aes192-ctr', // RECOMMENDED AES with 192-bit key 'aes256-ctr', // RECOMMENDED AES with 256-bit key // from <https://git.io/fhxOl>: // one of the big benefits of chacha20-poly1305 is speed. the problem is... // libsodium doesn't generate the poly1305 keys in the way ssh does and openssl's PHP bindings don't even // seem to support poly1305 currently. so even if libsodium or openssl are being used for the chacha20 // part, pure-PHP has to be used for the poly1305 part and that's gonna cause a big slow down. // speed-wise it winds up being faster to use AES (when openssl or mcrypt are available) and some HMAC // (which is always gonna be super fast to compute thanks to the hash extension, which // "is bundled and compiled into PHP by default") 'chacha20-poly1305@openssh.com', 'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key 'twofish192-ctr', // OPTIONAL Twofish with 192-bit key 'twofish256-ctr', // OPTIONAL Twofish with 256-bit key 'aes128-cbc', // RECOMMENDED AES with a 128-bit key 'aes192-cbc', // OPTIONAL AES with a 192-bit key 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key 'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key 'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key 'twofish256-cbc', 'twofish-cbc', // OPTIONAL alias for "twofish256-cbc" // (this is being retained for historical reasons) 'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode 'blowfish-cbc', // OPTIONAL Blowfish in CBC mode '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode '3des-cbc', // REQUIRED three-key 3DES in CBC mode //'none' // OPTIONAL no encryption; NOT RECOMMENDED ]; $engines = [ 'libsodium', 'OpenSSL (GCM)', 'OpenSSL', 'mcrypt', 'Eval', 'PHP' ]; $ciphers = []; foreach ($engines as $engine) { foreach ($algos as $algo) { $obj = self::encryption_algorithm_to_crypt_instance($algo); if ($obj instanceof Rijndael ) { $obj->setKeyLength(preg_replace('#[^\d]#', '', $algo)); } switch ($algo) { case 'chacha20-poly1305@openssh.com': case 'arcfour128': case 'arcfour256': if ($engine == 'Eval') { $algos = array_diff($algos, [$algo]); $ciphers[] = $algo; } else { continue 2; } break; case 'aes128-gcm@openssh.com': case 'aes256-gcm@openssh.com': if ($engine == 'OpenSSL') { continue 2; } $obj->setNonce('dummydummydu'); } if ($obj->isValidEngine($engine)) { $algos = array_diff($algos, [$algo]); $ciphers[] = $algo; } } } return $ciphers; } /** * Returns a list of MAC algorithms that phpseclib supports * * @return array * @access public */ public static function getSupportedMACAlgorithms() { return [ // from <http://www.ietf.org/rfc/rfc6668.txt>: 'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32) 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20) 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16) 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16) //'none' // OPTIONAL no MAC; NOT RECOMMENDED ]; } /** * Returns a list of compression algorithms that phpseclib supports * * @return array * @access public */ public static function getSupportedCompressionAlgorithms() { return [ 'none' // REQUIRED no compression //'zlib' // OPTIONAL ZLIB (LZ77) compression ]; } /** * Return list of negotiated algorithms * * Uses the same format as https://www.php.net/ssh2-methods-negotiated * * @return array * @access public */ public function getAlgorithmsNegotiated() { $this->connect(); return [ 'kex' => $this->kex_algorithm, 'hostkey' => $this->signature_format, 'client_to_server' => [ 'crypt' => $this->encrypt->name, 'mac' => $this->hmac_create->name, 'comp' => 'none', ], 'server_to_client' => [ 'crypt' => $this->decrypt->name, 'mac' => $this->hmac_check->name, 'comp' => 'none', ] ]; } /** * Accepts an associative array with up to four parameters as described at * <https://www.php.net/manual/en/function.ssh2-connect.php> * * @param array $methods * @access public */ public function setPreferredAlgorithms(array $methods) { $preferred = $methods; if (isset($preferred['kex'])) { $preferred['kex'] = array_intersect( $preferred['kex'], static::getSupportedKEXAlgorithms() ); } if (isset($preferred['hostkey'])) { $preferred['hostkey'] = array_intersect( $preferred['hostkey'], static::getSupportedHostKeyAlgorithms() ); } $keys = ['client_to_server', 'server_to_client']; foreach ($keys as $key) { if (isset($preferred[$key])) { $a = &$preferred[$key]; if (isset($a['crypt'])) { $a['crypt'] = array_intersect( $a['crypt'], static::getSupportedEncryptionAlgorithms() ); } if (isset($a['comp'])) { $a['comp'] = array_intersect( $a['comp'], static::getSupportedCompressionAlgorithms() ); } if (isset($a['mac'])) { $a['mac'] = array_intersect( $a['mac'], static::getSupportedMACAlgorithms() ); } } } $keys = [ 'kex', 'hostkey', 'client_to_server/crypt', 'client_to_server/comp', 'client_to_server/mac', 'server_to_client/crypt', 'server_to_client/comp', 'server_to_client/mac', ]; foreach ($keys as $key) { $p = $preferred; $m = $methods; $subkeys = explode('/', $key); foreach ($subkeys as $subkey) { if (!isset($p[$subkey])) { continue 2; } $p = $p[$subkey]; $m = $m[$subkey]; } if (count($p) != count($m)) { $diff = array_diff($m, $p); $msg = count($diff) == 1 ? ' is not a supported algorithm' : ' are not supported algorithms'; throw new UnsupportedAlgorithmException(implode(', ', $diff) . $msg); } } $this->preferred = $preferred; } /** * Returns the banner message. * * Quoting from the RFC, "in some jurisdictions, sending a warning message before * authentication may be relevant for getting legal protection." * * @return string * @access public */ public function getBannerMessage() { return $this->banner_message; } /** * Returns the server public host key. * * Caching this the first time you connect to a server and checking the result on subsequent connections * is recommended. Returns false if the server signature is not signed correctly with the public host key. * * @return mixed * @throws \RuntimeException on badly formatted keys * @throws \phpseclib\Exception\NoSupportedAlgorithmsException when the key isn't in a supported format * @access public */ public function getServerPublicHostKey() { if (!($this->bitmap & self::MASK_CONSTRUCTOR)) { if (!$this->connect()) { return false; } } $signature = $this->signature; $server_public_host_key = base64_encode($this->server_public_host_key); if ($this->signature_validated) { return $this->bitmap ? $this->signature_format . ' ' . $server_public_host_key : false; } $this->signature_validated = true; switch ($this->signature_format) { case 'ssh-ed25519': case 'ecdsa-sha2-nistp256': case 'ecdsa-sha2-nistp384': case 'ecdsa-sha2-nistp521': $key = ECDSA::load($server_public_host_key, 'OpenSSH') ->withSignatureFormat('SSH2'); switch ($this->signature_format) { case 'ssh-ed25519': Strings::shift($signature, 4 + strlen('ssh-ed25519') + 4); $hash = 'sha512'; break; case 'ecdsa-sha2-nistp256': $hash = 'sha256'; break; case 'ecdsa-sha2-nistp384': $hash = 'sha384'; break; case 'ecdsa-sha2-nistp521': $hash = 'sha512'; } $key = $key->withHash($hash); break; case 'ssh-dss': $key = DSA::load($server_public_host_key, 'OpenSSH') ->withSignatureFormat('SSH2') ->withHash('sha1'); break; case 'ssh-rsa': case 'rsa-sha2-256': case 'rsa-sha2-512': if (strlen($signature) < 15) { return false; } Strings::shift($signature, 11); $temp = unpack('Nlength', Strings::shift($signature, 4)); $signature = Strings::shift($signature, $temp['length']); $key = RSA::load($server_public_host_key, 'OpenSSH') ->withPadding(RSA::SIGNATURE_PKCS1); switch ($this->signature_format) { case 'rsa-sha2-512': $hash = 'sha512'; break; case 'rsa-sha2-256': $hash = 'sha256'; break; //case 'ssh-rsa': default: $hash = 'sha1'; } $key = $key->withHash($hash); break; default: $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); throw new NoSupportedAlgorithmsException('Unsupported signature format'); } if (!$key->verify($this->exchange_hash, $signature)) { return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); }; return $this->signature_format . ' ' . $server_public_host_key; } /** * Returns the exit status of an SSH command or false. * * @return false|int * @access public */ public function getExitStatus() { if (is_null($this->exit_status)) { return false; } return $this->exit_status; } /** * Returns the number of columns for the terminal window size. * * @return int * @access public */ public function getWindowColumns() { return $this->windowColumns; } /** * Returns the number of rows for the terminal window size. * * @return int * @access public */ public function getWindowRows() { return $this->windowRows; } /** * Sets the number of columns for the terminal window size. * * @param int $value * @access public */ public function setWindowColumns($value) { $this->windowColumns = $value; } /** * Sets the number of rows for the terminal window size. * * @param int $value * @access public */ public function setWindowRows($value) { $this->windowRows = $value; } /** * Sets the number of columns and rows for the terminal window size. * * @param int $columns * @param int $rows * @access public */ public function setWindowSize($columns = 80, $rows = 24) { $this->windowColumns = $columns; $this->windowRows = $rows; } /** * To String Magic Method * * @return string * @access public */ public function __toString() { return $this->getResourceId(); } /** * Get Resource ID * * We use {} because that symbols should not be in URL according to * {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}. * It will safe us from any conflicts, because otherwise regexp will * match all alphanumeric domains. * * @return string */ public function getResourceId() { return '{' . spl_object_hash($this) . '}'; } /** * Return existing connection * * @param string $id * * @return bool|SSH2 will return false if no such connection */ public static function getConnectionByResourceId($id) { return isset(self::$connections[$id]) ? self::$connections[$id] : false; } /** * Return all excising connections * * @return SSH2[] */ public static function getConnections() { return self::$connections; } } <?php /** * Pure-PHP implementation of SFTP. * * PHP version 5 * * Currently only supports SFTPv2 and v3, which, according to wikipedia.org, "is the most widely used version, * implemented by the popular OpenSSH SFTP server". If you want SFTPv4/5/6 support, provide me with access * to an SFTPv4/5/6 server. * * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}. * * Here's a short example of how to use this library: * <code> * <?php * include 'vendor/autoload.php'; * * $sftp = new \phpseclib\Net\SFTP('www.domain.tld'); * if (!$sftp->login('username', 'password')) { * exit('Login Failed'); * } * * echo $sftp->pwd() . "\r\n"; * $sftp->put('filename.ext', 'hello, world!'); * print_r($sftp->nlist()); * ?> * </code> * * @category Net * @package SFTP * @author Jim Wigginton <terrafrost@php.net> * @copyright 2009 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Net; use ParagonIE\ConstantTime\Hex; use phpseclib\Exception\FileNotFoundException; use phpseclib\Common\Functions\Strings; /** * Pure-PHP implementations of SFTP. * * @package SFTP * @author Jim Wigginton <terrafrost@php.net> * @access public */ class SFTP extends SSH2 { /** * SFTP channel constant * * \phpseclib\Net\SSH2::exec() uses 0 and \phpseclib\Net\SSH2::read() / \phpseclib\Net\SSH2::write() use 1. * * @see \phpseclib\Net\SSH2::send_channel_packet() * @see \phpseclib\Net\SSH2::get_channel_packet() * @access private */ const CHANNEL = 0x100; /**#@+ * @access public * @see \phpseclib\Net\SFTP::put() */ /** * Reads data from a local file. */ const SOURCE_LOCAL_FILE = 1; /** * Reads data from a string. */ // this value isn't really used anymore but i'm keeping it reserved for historical reasons const SOURCE_STRING = 2; /** * Reads data from callback: * function callback($length) returns string to proceed, null for EOF */ const SOURCE_CALLBACK = 16; /** * Resumes an upload */ const RESUME = 4; /** * Append a local file to an already existing remote file */ const RESUME_START = 8; /**#@-*/ /** * Packet Types * * @see self::__construct() * @var array * @access private */ private $packet_types = []; /** * Status Codes * * @see self::__construct() * @var array * @access private */ private $status_codes = []; /** * The Request ID * * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support * concurrent actions, so it's somewhat academic, here. * * @var boolean * @see self::_send_sftp_packet() * @access private */ private $use_request_id = false; /** * The Packet Type * * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support * concurrent actions, so it's somewhat academic, here. * * @var int * @see self::_get_sftp_packet() * @access private */ private $packet_type = -1; /** * Packet Buffer * * @var string * @see self::_get_sftp_packet() * @access private */ private $packet_buffer = ''; /** * Extensions supported by the server * * @var array * @see self::_initChannel() * @access private */ private $extensions = []; /** * Server SFTP version * * @var int * @see self::_initChannel() * @access private */ private $version; /** * Current working directory * * @var string * @see self::realpath() * @see self::chdir() * @access private */ private $pwd = false; /** * Packet Type Log * * @see self::getLog() * @var array * @access private */ private $packet_type_log = []; /** * Packet Log * * @see self::getLog() * @var array * @access private */ private $packet_log = []; /** * Error information * * @see self::getSFTPErrors() * @see self::getLastSFTPError() * @var array * @access private */ private $sftp_errors = []; /** * Stat Cache * * Rather than always having to open a directory and close it immediately there after to see if a file is a directory * we'll cache the results. * * @see self::_update_stat_cache() * @see self::_remove_from_stat_cache() * @see self::_query_stat_cache() * @var array * @access private */ private $stat_cache = []; /** * Max SFTP Packet Size * * @see self::__construct() * @see self::get() * @var array * @access private */ private $max_sftp_packet; /** * Stat Cache Flag * * @see self::disableStatCache() * @see self::enableStatCache() * @var bool * @access private */ private $use_stat_cache = true; /** * Sort Options * * @see self::_comparator() * @see self::setListOrder() * @var array * @access private */ private $sortOptions = []; /** * Canonicalization Flag * * Determines whether or not paths should be canonicalized before being * passed on to the remote server. * * @see self::enablePathCanonicalization() * @see self::disablePathCanonicalization() * @see self::realpath() * @var bool * @access private */ private $canonicalize_paths = true; /** * Request Buffers * * @see self::_get_sftp_packet() * @var array * @access private */ var $requestBuffer = array(); /** * Default Constructor. * * Connects to an SFTP server * * @param string $host * @param int $port * @param int $timeout * @return \phpseclib\Net\SFTP * @access public */ public function __construct($host, $port = 22, $timeout = 10) { parent::__construct($host, $port, $timeout); $this->max_sftp_packet = 1 << 15; $this->packet_types = [ 1 => 'NET_SFTP_INIT', 2 => 'NET_SFTP_VERSION', /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+: SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1 pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */ 3 => 'NET_SFTP_OPEN', 4 => 'NET_SFTP_CLOSE', 5 => 'NET_SFTP_READ', 6 => 'NET_SFTP_WRITE', 7 => 'NET_SFTP_LSTAT', 9 => 'NET_SFTP_SETSTAT', 11 => 'NET_SFTP_OPENDIR', 12 => 'NET_SFTP_READDIR', 13 => 'NET_SFTP_REMOVE', 14 => 'NET_SFTP_MKDIR', 15 => 'NET_SFTP_RMDIR', 16 => 'NET_SFTP_REALPATH', 17 => 'NET_SFTP_STAT', /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+: SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */ 18 => 'NET_SFTP_RENAME', 19 => 'NET_SFTP_READLINK', 20 => 'NET_SFTP_SYMLINK', 101=> 'NET_SFTP_STATUS', 102=> 'NET_SFTP_HANDLE', /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+: SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4 pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */ 103=> 'NET_SFTP_DATA', 104=> 'NET_SFTP_NAME', 105=> 'NET_SFTP_ATTRS', 200=> 'NET_SFTP_EXTENDED' ]; $this->status_codes = [ 0 => 'NET_SFTP_STATUS_OK', 1 => 'NET_SFTP_STATUS_EOF', 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE', 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED', 4 => 'NET_SFTP_STATUS_FAILURE', 5 => 'NET_SFTP_STATUS_BAD_MESSAGE', 6 => 'NET_SFTP_STATUS_NO_CONNECTION', 7 => 'NET_SFTP_STATUS_CONNECTION_LOST', 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED', 9 => 'NET_SFTP_STATUS_INVALID_HANDLE', 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH', 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS', 12 => 'NET_SFTP_STATUS_WRITE_PROTECT', 13 => 'NET_SFTP_STATUS_NO_MEDIA', 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM', 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED', 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL', 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT', 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY', 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY', 20 => 'NET_SFTP_STATUS_INVALID_FILENAME', 21 => 'NET_SFTP_STATUS_LINK_LOOP', 22 => 'NET_SFTP_STATUS_CANNOT_DELETE', 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER', 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY', 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT', 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED', 27 => 'NET_SFTP_STATUS_DELETE_PENDING', 28 => 'NET_SFTP_STATUS_FILE_CORRUPT', 29 => 'NET_SFTP_STATUS_OWNER_INVALID', 30 => 'NET_SFTP_STATUS_GROUP_INVALID', 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK' ]; // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1 // the order, in this case, matters quite a lot - see \phpseclib\Net\SFTP::_parseAttributes() to understand why $this->attributes = [ 0x00000001 => 'NET_SFTP_ATTR_SIZE', 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+ 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000. // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored. (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED' ]; // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name // the array for that $this->open5_flags and similarly alter the constant names. $this->open_flags = [ 0x00000001 => 'NET_SFTP_OPEN_READ', 0x00000002 => 'NET_SFTP_OPEN_WRITE', 0x00000004 => 'NET_SFTP_OPEN_APPEND', 0x00000008 => 'NET_SFTP_OPEN_CREATE', 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE', 0x00000020 => 'NET_SFTP_OPEN_EXCL' ]; // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 // see \phpseclib\Net\SFTP::_parseLongname() for an explanation $this->file_types = [ 1 => 'NET_SFTP_TYPE_REGULAR', 2 => 'NET_SFTP_TYPE_DIRECTORY', 3 => 'NET_SFTP_TYPE_SYMLINK', 4 => 'NET_SFTP_TYPE_SPECIAL', 5 => 'NET_SFTP_TYPE_UNKNOWN', // the following types were first defined for use in SFTPv5+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 6 => 'NET_SFTP_TYPE_SOCKET', 7 => 'NET_SFTP_TYPE_CHAR_DEVICE', 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE', 9 => 'NET_SFTP_TYPE_FIFO' ]; $this->define_array( $this->packet_types, $this->status_codes, $this->attributes, $this->open_flags, $this->file_types ); if (!defined('NET_SFTP_QUEUE_SIZE')) { define('NET_SFTP_QUEUE_SIZE', 32); } } /** * Login * * @param string $username * @param $args[] string password * @throws \UnexpectedValueException on receipt of unexpected packets * @return bool * @access public */ public function login($username,...$args) { if (!$this->sublogin($username,...$args)) { return false; } $this->window_size_server_to_client[self::CHANNEL] = $this->window_size; $packet = Strings::packSSH2( 'CsN3', NET_SSH2_MSG_CHANNEL_OPEN, 'session', self::CHANNEL, $this->window_size, 0x4000 ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->get_channel_packet(self::CHANNEL, true); if ($response === false) { return false; } $packet = Strings::packSSH2( 'CNsbs', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL], 'subsystem', true, 'sftp' ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->get_channel_packet(self::CHANNEL, true); if ($response === false) { // from PuTTY's psftp.exe $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" . "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" . "exec sftp-server"; // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does // is redundant $packet = Strings::packSSH2( 'CNsCs', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[self::CHANNEL], 'exec', 1, $command ); $this->send_binary_packet($packet); $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->get_channel_packet(self::CHANNEL, true); if ($response === false) { return false; } } $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA; if (!$this->send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) { return false; } $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_VERSION) { throw new \UnexpectedValueException('Expected NET_SFTP_VERSION. ' . 'Got packet type: ' . $this->packet_type); } list($this->version) = Strings::unpackSSH2('N', $response); while (!empty($response)) { list($key, $value) = Strings::unpackSSH2('ss', $response); $this->extensions[$key] = $value; } /* SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com', however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that 'newline@vandyke.com' would. */ /* if (isset($this->extensions['newline@vandyke.com'])) { $this->extensions['newline'] = $this->extensions['newline@vandyke.com']; unset($this->extensions['newline@vandyke.com']); } */ $this->use_request_id = true; /* A Note on SFTPv4/5/6 support: <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following: "If the client wishes to interoperate with servers that support noncontiguous version numbers it SHOULD send '3'" Given that the server only sends its version number after the client has already done so, the above seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the most popular. <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following; "If the server did not send the "versions" extension, or the version-from-list was not included, the server MAY send a status response describing the failure, but MUST then close the channel without processing any further requests." So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what \phpseclib\Net\SFTP would do is close the channel and reopen it with a new and updated SSH_FXP_INIT packet. */ switch ($this->version) { case 2: case 3: break; default: return false; } $this->pwd = $this->realpath('.'); $this->update_stat_cache($this->pwd, []); return true; } /** * Disable the stat cache * * @access public */ function disableStatCache() { $this->use_stat_cache = false; } /** * Enable the stat cache * * @access public */ public function enableStatCache() { $this->use_stat_cache = true; } /** * Clear the stat cache * * @access public */ public function clearStatCache() { $this->stat_cache = []; } /** * Enable path canonicalization * * @access public */ public function enablePathCanonicalization() { $this->canonicalize_paths = true; } /** * Enable path canonicalization * * @access public */ public function disablePathCanonicalization() { $this->canonicalize_paths = false; } /** * Returns the current directory name * * @return mixed * @access public */ public function pwd() { return $this->pwd; } /** * Logs errors * * @param string $response * @param int $status * @access private */ private function logError($response, $status = -1) { if ($status == -1) { list($status) = Strings::unpackSSH2('N', $response); } list($error) = $this->status_codes[$status]; if ($this->version > 2) { list($message) = Strings::unpackSSH2('s', $response); $this->sftp_errors[] = "$error: $message"; } else { $this->sftp_errors[] = $error; } } /** * Canonicalize the Server-Side Path Name * * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns * the absolute (canonicalized) path. * * If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is. * * @see self::chdir() * @see self::disablePathCanonicalization() * @param string $path * @throws \UnexpectedValueException on receipt of unexpected packets * @return mixed * @access public */ public function realpath($path) { if (!$this->canonicalize_paths) { return $path; } if ($this->pwd === false) { // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9 if (!$this->send_sftp_packet(NET_SFTP_REALPATH, Strings::packSSH2('s', $path))) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_NAME: // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks // at is the first part and that part is defined the same in SFTP versions 3 through 6. list(, $filename) = Strings::unpackSSH2('Ns', $response); return $filename; case NET_SFTP_STATUS: $this->logError($response); return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } } if ($path[0] != '/') { $path = $this->pwd . '/' . $path; } $path = explode('/', $path); $new = []; foreach ($path as $dir) { if (!strlen($dir)) { continue; } switch ($dir) { case '..': array_pop($new); case '.': break; default: $new[] = $dir; } } return '/' . implode('/', $new); } /** * Changes the current directory * * @param string $dir * @throws \UnexpectedValueException on receipt of unexpected packets * @return bool * @access public */ public function chdir($dir) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } // assume current dir if $dir is empty if ($dir === '') { $dir = './'; // suffix a slash if needed } elseif ($dir[strlen($dir) - 1] != '/') { $dir.= '/'; } $dir = $this->realpath($dir); // confirm that $dir is, in fact, a valid directory if ($this->use_stat_cache && is_array($this->query_stat_cache($dir))) { $this->pwd = $dir; return true; } // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us // the currently logged in user has the appropriate permissions or not. maybe you could see if // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy // way to get those with SFTP if (!$this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir))) { return false; } // see \phpseclib\Net\SFTP::nlist() for a more thorough explanation of the following $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: $handle = substr($response, 4); break; case NET_SFTP_STATUS: $this->logError($response); return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS' . 'Got packet type: ' . $this->packet_type); } if (!$this->close_handle($handle)) { return false; } $this->update_stat_cache($dir, []); $this->pwd = $dir; return true; } /** * Returns a list of files in the given directory * * @param string $dir * @param bool $recursive * @return mixed * @access public */ public function nlist($dir = '.', $recursive = false) { return $this->nlist_helper($dir, $recursive, ''); } /** * Helper method for nlist * * @param string $dir * @param bool $recursive * @param string $relativeDir * @return mixed * @access private */ private function nlist_helper($dir, $recursive, $relativeDir) { $files = $this->readlist($dir, false); if (!$recursive || $files === false) { return $files; } $result = []; foreach ($files as $value) { if ($value == '.' || $value == '..') { $result[] = $relativeDir . $value; continue; } if (is_array($this->query_stat_cache($this->realpath($dir . '/' . $value)))) { $temp = $this->nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/'); $result = array_merge($result, $temp); } else { $result[] = $relativeDir . $value; } } return $result; } /** * Returns a detailed list of files in the given directory * * @param string $dir * @param bool $recursive * @return mixed * @access public */ public function rawlist($dir = '.', $recursive = false) { $files = $this->readlist($dir, true); if (!$recursive || $files === false) { return $files; } static $depth = 0; foreach ($files as $key => $value) { if ($depth != 0 && $key == '..') { unset($files[$key]); continue; } $is_directory = false; if ($key != '.' && $key != '..') { if ($this->use_stat_cache) { $is_directory = is_array($this->query_stat_cache($this->realpath($dir . '/' . $key))); } else { $stat = $this->lstat($dir . '/' . $key); $is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY; } } if ($is_directory) { $depth++; $files[$key] = $this->rawlist($dir . '/' . $key, true); $depth--; } else { $files[$key] = (object) $value; } } return $files; } /** * Reads a list, be it detailed or not, of files in the given directory * * @param string $dir * @param bool $raw * @return mixed * @throws \UnexpectedValueException on receipt of unexpected packets * @access private */ private function readlist($dir, $raw = true) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $dir = $this->realpath($dir . '/'); if ($dir === false) { return false; } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2 if (!$this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir))) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2 // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that // represent the length of the string and leave it at that $handle = substr($response, 4); break; case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED $this->logError($response); return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } $this->update_stat_cache($dir, []); $contents = []; while (true) { // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2 // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many // SSH_MSG_CHANNEL_DATA messages is not known to me. if (!$this->send_sftp_packet(NET_SFTP_READDIR, Strings::packSSH2('s', $handle))) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_NAME: list($count) = Strings::unpackSSH2('N', $response); for ($i = 0; $i < $count; $i++) { list($shortname, $longname) = Strings::unpackSSH2('ss', $response); $attributes = $this->parseAttributes($response); if (!isset($attributes['type'])) { $fileType = $this->parseLongname($longname); if ($fileType) { $attributes['type'] = $fileType; } } $contents[$shortname] = $attributes + ['filename' => $shortname]; if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) { $this->update_stat_cache($dir . '/' . $shortname, []); } else { if ($shortname == '..') { $temp = $this->realpath($dir . '/..') . '/.'; } else { $temp = $dir . '/' . $shortname; } $this->update_stat_cache($temp, (object) ['lstat' => $attributes]); } // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the // final SSH_FXP_STATUS packet should tell us that, already. } break; case NET_SFTP_STATUS: list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_EOF) { $this->logError($response, $status); return false; } break 2; default: throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } } if (!$this->close_handle($handle)) { return false; } if (count($this->sortOptions)) { uasort($contents, [&$this, 'comparator']); } return $raw ? $contents : array_keys($contents); } /** * Compares two rawlist entries using parameters set by setListOrder() * * Intended for use with uasort() * * @param array $a * @param array $b * @return int * @access private */ private function comparator($a, $b) { switch (true) { case $a['filename'] === '.' || $b['filename'] === '.': if ($a['filename'] === $b['filename']) { return 0; } return $a['filename'] === '.' ? -1 : 1; case $a['filename'] === '..' || $b['filename'] === '..': if ($a['filename'] === $b['filename']) { return 0; } return $a['filename'] === '..' ? -1 : 1; case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY: if (!isset($b['type'])) { return 1; } if ($b['type'] !== $a['type']) { return -1; } break; case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY: return 1; } foreach ($this->sortOptions as $sort => $order) { if (!isset($a[$sort]) || !isset($b[$sort])) { if (isset($a[$sort])) { return -1; } if (isset($b[$sort])) { return 1; } return 0; } switch ($sort) { case 'filename': $result = strcasecmp($a['filename'], $b['filename']); if ($result) { return $order === SORT_DESC ? -$result : $result; } break; case 'permissions': case 'mode': $a[$sort]&= 07777; $b[$sort]&= 07777; default: if ($a[$sort] === $b[$sort]) { break; } return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort]; } } } /** * Defines how nlist() and rawlist() will be sorted - if at all. * * If sorting is enabled directories and files will be sorted independently with * directories appearing before files in the resultant array that is returned. * * Any parameter returned by stat is a valid sort parameter for this function. * Filename comparisons are case insensitive. * * Examples: * * $sftp->setListOrder('filename', SORT_ASC); * $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC); * $sftp->setListOrder(true); * Separates directories from files but doesn't do any sorting beyond that * $sftp->setListOrder(); * Don't do any sort of sorting * * @param $args[] * @access public */ public function setListOrder(...$args) { $this->sortOptions = []; if (empty($args)) { return; } $len = count($args) & 0x7FFFFFFE; for ($i = 0; $i < $len; $i+=2) { $this->sortOptions[$args[$i]] = $args[$i + 1]; } if (!count($this->sortOptions)) { $this->sortOptions = ['bogus' => true]; } } /** * Returns the file size, in bytes, or false, on failure * * Files larger than 4GB will show up as being exactly 4GB. * * @param string $filename * @return mixed * @access public */ public function size($filename) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $result = $this->stat($filename); if ($result === false) { return false; } return isset($result['size']) ? $result['size'] : -1; } /** * Save files / directories to cache * * @param string $path * @param mixed $value * @access private */ private function update_stat_cache($path, $value) { if ($this->use_stat_cache === false) { return; } // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/')) $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $temp = &$this->stat_cache; $max = count($dirs) - 1; foreach ($dirs as $i => $dir) { // if $temp is an object that means one of two things. // 1. a file was deleted and changed to a directory behind phpseclib's back // 2. it's a symlink. when lstat is done it's unclear what it's a symlink to if (is_object($temp)) { $temp = []; } if (!isset($temp[$dir])) { $temp[$dir] = []; } if ($i === $max) { if (is_object($temp[$dir]) && is_object($value)) { if (!isset($value->stat) && isset($temp[$dir]->stat)) { $value->stat = $temp[$dir]->stat; } if (!isset($value->lstat) && isset($temp[$dir]->lstat)) { $value->lstat = $temp[$dir]->lstat; } } $temp[$dir] = $value; break; } $temp = &$temp[$dir]; } } /** * Remove files / directories from cache * * @param string $path * @return bool * @access private */ private function remove_from_stat_cache($path) { $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $temp = &$this->stat_cache; $max = count($dirs) - 1; foreach ($dirs as $i => $dir) { if ($i === $max) { unset($temp[$dir]); return true; } if (!isset($temp[$dir])) { return false; } $temp = &$temp[$dir]; } } /** * Checks cache for path * * Mainly used by file_exists * * @param string $path * @return mixed * @access private */ private function query_stat_cache($path) { $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $temp = &$this->stat_cache; foreach ($dirs as $dir) { if (!isset($temp[$dir])) { return null; } $temp = &$temp[$dir]; } return $temp; } /** * Returns general information about a file. * * Returns an array on success and false otherwise. * * @param string $filename * @return mixed * @access public */ public function stat($filename) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $filename = $this->realpath($filename); if ($filename === false) { return false; } if ($this->use_stat_cache) { $result = $this->query_stat_cache($filename); if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) { return $result['.']->stat; } if (is_object($result) && isset($result->stat)) { return $result->stat; } } $stat = $this->stat_helper($filename, NET_SFTP_STAT); if ($stat === false) { $this->remove_from_stat_cache($filename); return false; } if (isset($stat['type'])) { if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } $this->update_stat_cache($filename, (object) ['stat' => $stat]); return $stat; } $pwd = $this->pwd; $stat['type'] = $this->chdir($filename) ? NET_SFTP_TYPE_DIRECTORY : NET_SFTP_TYPE_REGULAR; $this->pwd = $pwd; if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } $this->update_stat_cache($filename, (object) ['stat' => $stat]); return $stat; } /** * Returns general information about a file or symbolic link. * * Returns an array on success and false otherwise. * * @param string $filename * @return mixed * @access public */ public function lstat($filename) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $filename = $this->realpath($filename); if ($filename === false) { return false; } if ($this->use_stat_cache) { $result = $this->query_stat_cache($filename); if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) { return $result['.']->lstat; } if (is_object($result) && isset($result->lstat)) { return $result->lstat; } } $lstat = $this->stat_helper($filename, NET_SFTP_LSTAT); if ($lstat === false) { $this->remove_from_stat_cache($filename); return false; } if (isset($lstat['type'])) { if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } $this->update_stat_cache($filename, (object) ['lstat' => $lstat]); return $lstat; } $stat = $this->stat_helper($filename, NET_SFTP_STAT); if ($lstat != $stat) { $lstat = array_merge($lstat, ['type' => NET_SFTP_TYPE_SYMLINK]); $this->update_stat_cache($filename, (object) ['lstat' => $lstat]); return $stat; } $pwd = $this->pwd; $lstat['type'] = $this->chdir($filename) ? NET_SFTP_TYPE_DIRECTORY : NET_SFTP_TYPE_REGULAR; $this->pwd = $pwd; if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) { $filename.= '/.'; } $this->update_stat_cache($filename, (object) ['lstat' => $lstat]); return $lstat; } /** * Returns general information about a file or symbolic link * * Determines information without calling \phpseclib\Net\SFTP::realpath(). * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT. * * @param string $filename * @param int $type * @throws \UnexpectedValueException on receipt of unexpected packets * @return mixed * @access private */ private function stat_helper($filename, $type) { // SFTPv4+ adds an additional 32-bit integer field - flags - to the following: $packet = Strings::packSSH2('s', $filename); if (!$this->send_sftp_packet($type, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_ATTRS: return $this->parseAttributes($response); case NET_SFTP_STATUS: $this->logError($response); return false; } throw new \UnexpectedValueException('Expected NET_SFTP_ATTRS or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } /** * Truncates a file to a given length * * @param string $filename * @param int $new_size * @return bool * @access public */ public function truncate($filename, $new_size) { $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32 return $this->setstat($filename, $attr, false); } /** * Sets access and modification time of file. * * If the file does not exist, it will be created. * * @param string $filename * @param int $time * @param int $atime * @throws \UnexpectedValueException on receipt of unexpected packets * @return bool * @access public */ public function touch($filename, $time = null, $atime = null) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $filename = $this->realpath($filename); if ($filename === false) { return false; } if (!isset($time)) { $time = time(); } if (!isset($atime)) { $atime = $time; } $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL; $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime); $packet = Strings::packSSH2('sN', $filename, $flags) . $attr; if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: return $this->close_handle(substr($response, 4)); case NET_SFTP_STATUS: $this->logError($response); break; default: throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } return $this->setstat($filename, $attr, false); } /** * Changes file or directory owner * * Returns true on success or false on error. * * @param string $filename * @param int $uid * @param bool $recursive * @return bool * @access public */ public function chown($filename, $uid, $recursive = false) { // quoting from <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>, // "if the owner or group is specified as -1, then that ID is not changed" $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1); return $this->setstat($filename, $attr, $recursive); } /** * Changes file or directory group * * Returns true on success or false on error. * * @param string $filename * @param int $gid * @param bool $recursive * @return bool * @access public */ public function chgrp($filename, $gid, $recursive = false) { $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid); return $this->setstat($filename, $attr, $recursive); } /** * Set permissions on a file. * * Returns the new file permissions on success or false on error. * If $recursive is true than this just returns true or false. * * @param int $mode * @param string $filename * @param bool $recursive * @throws \UnexpectedValueException on receipt of unexpected packets * @return mixed * @access public */ public function chmod($mode, $filename, $recursive = false) { if (is_string($mode) && is_int($filename)) { $temp = $mode; $mode = $filename; $filename = $temp; } $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); if (!$this->setstat($filename, $attr, $recursive)) { return false; } if ($recursive) { return true; } $filename = $this->realpath($filename); // rather than return what the permissions *should* be, we'll return what they actually are. this will also // tell us if the file actually exists. // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following: $packet = pack('Na*', strlen($filename), $filename); if (!$this->send_sftp_packet(NET_SFTP_STAT, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_ATTRS: $attrs = $this->parseAttributes($response); return $attrs['permissions']; case NET_SFTP_STATUS: $this->logError($response); return false; } throw new \UnexpectedValueException('Expected NET_SFTP_ATTRS or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } /** * Sets information about a file * * @param string $filename * @param string $attr * @param bool $recursive * @throws \UnexpectedValueException on receipt of unexpected packets * @return bool * @access private */ private function setstat($filename, $attr, $recursive) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $filename = $this->realpath($filename); if ($filename === false) { return false; } $this->remove_from_stat_cache($filename); if ($recursive) { $i = 0; $result = $this->setstat_recursive($filename, $attr, $i); $this->read_put_responses($i); return $result; } // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT. if (!$this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $filename) . $attr)) { return false; } /* "Because some systems must use separate system calls to set various attributes, it is possible that a failure response will be returned, but yet some of the attributes may be have been successfully modified. If possible, servers SHOULD avoid this situation; however, clients MUST be aware that this is possible." -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6 */ $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); return false; } return true; } /** * Recursively sets information on directories on the SFTP server * * Minimizes directory lookups and SSH_FXP_STATUS requests for speed. * * @param string $path * @param string $attr * @param int $i * @return bool * @access private */ private function setstat_recursive($path, $attr, &$i) { if (!$this->read_put_responses($i)) { return false; } $i = 0; $entries = $this->readlist($path, true); if ($entries === false) { return $this->setstat($path, $attr, false); } // normally $entries would have at least . and .. but it might not if the directories // permissions didn't allow reading if (empty($entries)) { return false; } unset($entries['.'], $entries['..']); foreach ($entries as $filename => $props) { if (!isset($props['type'])) { return false; } $temp = $path . '/' . $filename; if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) { if (!$this->setstat_recursive($temp, $attr, $i)) { return false; } } else { if (!$this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $temp) . $attr)) { return false; } $i++; if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->read_put_responses($i)) { return false; } $i = 0; } } } if (!$this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $path) . $attr)) { return false; } $i++; if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->read_put_responses($i)) { return false; } $i = 0; } return true; } /** * Return the target of a symbolic link * * @param string $link * @throws \UnexpectedValueException on receipt of unexpected packets * @return mixed * @access public */ public function readlink($link) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $link = $this->realpath($link); if (!$this->send_sftp_packet(NET_SFTP_READLINK, Strings::packSSH2('s', $link))) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_NAME: break; case NET_SFTP_STATUS: $this->logError($response); return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($count) = Strings::unpackSSH2('N', $response); // the file isn't a symlink if (!$count) { return false; } list($filename) = Strings::unpackSSH2('s', $response); return $filename; } /** * Create a symlink * * symlink() creates a symbolic link to the existing target with the specified name link. * * @param string $target * @param string $link * @throws \UnexpectedValueException on receipt of unexpected packets * @return bool * @access public */ public function symlink($target, $link) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } //$target = $this->realpath($target); $link = $this->realpath($link); $packet = Strings::packSSH2('ss', $target, $link); if (!$this->send_sftp_packet(NET_SFTP_SYMLINK, $packet)) { return false; } $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); return false; } return true; } /** * Creates a directory. * * @param string $dir * @param int $mode * @param bool $recursive * @return bool * @access public */ public function mkdir($dir, $mode = -1, $recursive = false) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $dir = $this->realpath($dir); // by not providing any permissions, hopefully the server will use the logged in users umask - their // default permissions. $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); if ($recursive) { $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir)); if (empty($dirs[0])) { array_shift($dirs); $dirs[0] = '/' . $dirs[0]; } for ($i = 0; $i < count($dirs); $i++) { $temp = array_slice($dirs, 0, $i + 1); $temp = implode('/', $temp); $result = $this->mkdir_helper($temp, $attr); } return $result; } return $this->mkdir_helper($dir, $attr); } /** * Helper function for directory creation * * @param string $dir * @param string $attr * @return bool * @access private */ private function mkdir_helper($dir, $attr) { if (!$this->send_sftp_packet(NET_SFTP_MKDIR, Strings::packSSH2('s', $dir) . $attr)) { return false; } $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); return false; } return true; } /** * Removes a directory. * * @param string $dir * @throws \UnexpectedValueException on receipt of unexpected packets * @return bool * @access public */ public function rmdir($dir) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $dir = $this->realpath($dir); if ($dir === false) { return false; } if (!$this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $dir))) { return false; } $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED? $this->logError($response, $status); return false; } $this->remove_from_stat_cache($dir); // the following will do a soft delete, which would be useful if you deleted a file // and then tried to do a stat on the deleted file. the above, in contrast, does // a hard delete //$this->update_stat_cache($dir, false); return true; } /** * Uploads a file to the SFTP server. * * By default, \phpseclib\Net\SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. * So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SFTP::get(), you will get a file, twelve bytes * long, containing 'filename.ext' as its contents. * * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior. With self::SOURCE_LOCAL_FILE, $remote_file will * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * large $remote_file will be, as well. * * Setting $mode to self::SOURCE_CALLBACK will use $data as callback function, which gets only one parameter -- number of bytes to return, and returns a string if there is some data or null if there is no more data * * If $data is a resource then it'll be used as a resource instead. * * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. * * $mode can take an additional two parameters - self::RESUME and self::RESUME_START. These are bitwise AND'd with * $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following: * * self::SOURCE_LOCAL_FILE | self::RESUME * * If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace * self::RESUME with self::RESUME_START. * * If $mode & (self::RESUME | self::RESUME_START) then self::RESUME_START will be assumed. * * $start and $local_start give you more fine grained control over this process and take precident over self::RESUME * when they're non-negative. ie. $start could let you write at the end of a file (like self::RESUME) or in the middle * of one. $local_start could let you start your reading from the end of a file (like self::RESUME_START) or in the * middle of one. * * Setting $local_start to > 0 or $mode | self::RESUME_START doesn't do anything unless $mode | self::SOURCE_LOCAL_FILE. * * @param string $remote_file * @param string|resource $data * @param int $mode * @param int $start * @param int $local_start * @param callable|null $progressCallback * @throws \UnexpectedValueException on receipt of unexpected packets * @throws \BadFunctionCallException if you're uploading via a callback and the callback function is invalid * @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist * @return bool * @access public * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - \phpseclib\Net\SFTP::setMode(). */ public function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $remote_file = $this->realpath($remote_file); if ($remote_file === false) { return false; } $this->remove_from_stat_cache($remote_file); $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE; // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file." // in practice, it doesn't seem to do that. //$flags|= ($mode & self::RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE; if ($start >= 0) { $offset = $start; } elseif ($mode & self::RESUME) { // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called $size = $this->size($remote_file); $offset = $size !== false ? $size : 0; } else { $offset = 0; $flags|= NET_SFTP_OPEN_TRUNCATE; } $packet = Strings::packSSH2('sNN', $remote_file, $flags, 0); if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: $handle = substr($response, 4); break; case NET_SFTP_STATUS: $this->logError($response); return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 $dataCallback = false; switch (true) { case $mode & self::SOURCE_CALLBACK: if (!is_callable($data)) { throw new \BadFunctionCallException("\$data should be is_callable() if you specify SOURCE_CALLBACK flag"); } $dataCallback = $data; // do nothing break; case is_resource($data): $mode = $mode & ~self::SOURCE_LOCAL_FILE; $info = stream_get_meta_data($data); if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') { $fp = fopen('php://memory', 'w+'); stream_copy_to_stream($data, $fp); rewind($fp); } else { $fp = $data; } break; case $mode & self::SOURCE_LOCAL_FILE: if (!is_file($data)) { throw new FileNotFoundException("$data is not a valid file"); } $fp = @fopen($data, 'rb'); if (!$fp) { return false; } } if (isset($fp)) { $stat = fstat($fp); $size = !empty($stat) ? $stat['size'] : 0; if ($local_start >= 0) { fseek($fp, $local_start); $size-= $local_start; } } elseif ($dataCallback) { $size = 0; } else { $size = strlen($data); } $sent = 0; $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; $sftp_packet_size = 4096; // PuTTY uses 4096 // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" $sftp_packet_size-= strlen($handle) + 25; $i = 0; while ($dataCallback || ($size === 0 || $sent < $size)) { if ($dataCallback) { $temp = call_user_func($dataCallback, $sftp_packet_size); if (is_null($temp)) { break; } } else { $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); if ($temp === false || $temp === '') { break; } } $subtemp = $offset + $sent; $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); if (!$this->send_sftp_packet(NET_SFTP_WRITE, $packet)) { if ($mode & self::SOURCE_LOCAL_FILE) { fclose($fp); } return false; } $sent+= strlen($temp); if (is_callable($progressCallback)) { call_user_func($progressCallback, $sent); } $i++; if ($i == NET_SFTP_QUEUE_SIZE) { if (!$this->read_put_responses($i)) { $i = 0; break; } $i = 0; } } if (!$this->read_put_responses($i)) { if ($mode & self::SOURCE_LOCAL_FILE) { fclose($fp); } $this->close_handle($handle); return false; } if ($mode & self::SOURCE_LOCAL_FILE) { fclose($fp); } return $this->close_handle($handle); } /** * Reads multiple successive SSH_FXP_WRITE responses * * Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i * SSH_FXP_WRITEs, in succession, and then reading $i responses. * * @param int $i * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @access private */ private function read_put_responses($i) { while ($i--) { $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); break; } } return $i < 0; } /** * Close handle * * @param string $handle * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @access private */ private function close_handle($handle) { if (!$this->send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { return false; } // "The client MUST release all resources associated with the handle regardless of the status." // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); return false; } return true; } /** * Downloads a file from the SFTP server. * * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the * operation. * * $offset and $length can be used to download files in chunks. * * @param string $remote_file * @param string|bool|resource $local_file * @param int $offset * @param int $length * @throws \UnexpectedValueException on receipt of unexpected packets * @return mixed * @access public */ public function get($remote_file, $local_file = false, $offset = 0, $length = -1) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $remote_file = $this->realpath($remote_file); if ($remote_file === false) { return false; } $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0); if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: $handle = substr($response, 4); break; case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED $this->logError($response); return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } if (is_resource($local_file)) { $fp = $local_file; $stat = fstat($fp); $res_offset = $stat['size']; } else { $res_offset = 0; if ($local_file !== false) { $fp = fopen($local_file, 'wb'); if (!$fp) { return false; } } else { $content = ''; } } $fclose_check = $local_file !== false && !is_resource($local_file); $start = $offset; $read = 0; while (true) { $i = 0; while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) { $tempoffset = $start + $read; $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet; $packet = Strings::packSSH2('sN3', $handle, $tempoffset / 4294967296, $tempoffset, $packet_size); if (!$this->send_sftp_packet(NET_SFTP_READ, $packet, $i)) { if ($fclose_check) { fclose($fp); } return false; } $packet = null; $read+= $packet_size; $i++; } if (!$i) { break; } $packets_sent = $i - 1; $clear_responses = false; while ($i > 0) { $i--; if ($clear_responses) { $this->get_sftp_packet($packets_sent - $i); continue; } else { $response = $this->get_sftp_packet($packets_sent - $i); } switch ($this->packet_type) { case NET_SFTP_DATA: $temp = substr($response, 4); $offset+= strlen($temp); if ($local_file === false) { $content.= $temp; } else { fputs($fp, $temp); } $temp = null; break; case NET_SFTP_STATUS: // could, in theory, return false if !strlen($content) but we'll hold off for the time being $this->logError($response); $clear_responses = true; // don't break out of the loop yet, so we can read the remaining responses break; default: if ($fclose_check) { fclose($fp); } throw new \UnexpectedValueException('Expected NET_SFTP_DATA or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } $response = null; } if ($clear_responses) { break; } } if ($length > 0 && $length <= $offset - $start) { if ($local_file === false) { $content = substr($content, 0, $length); } else { ftruncate($fp, $length + $res_offset); } } if ($fclose_check) { fclose($fp); } if (!$this->close_handle($handle)) { return false; } // if $content isn't set that means a file was written to return isset($content) ? $content : true; } /** * Deletes a file on the SFTP server. * * @param string $path * @param bool $recursive * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @access public */ public function delete($path, $recursive = true) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } if (is_object($path)) { // It's an object. Cast it as string before we check anything else. $path = (string) $path; } if (!is_string($path) || $path == '') { return false; } $path = $this->realpath($path); if ($path === false) { return false; } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 if (!$this->send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) { return false; } $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); if (!$recursive) { return false; } $i = 0; $result = $this->delete_recursive($path, $i); $this->read_put_responses($i); return $result; } $this->remove_from_stat_cache($path); return true; } /** * Recursively deletes directories on the SFTP server * * Minimizes directory lookups and SSH_FXP_STATUS requests for speed. * * @param string $path * @param int $i * @return bool * @access private */ private function delete_recursive($path, &$i) { if (!$this->read_put_responses($i)) { return false; } $i = 0; $entries = $this->readlist($path, true); // normally $entries would have at least . and .. but it might not if the directories // permissions didn't allow reading if (empty($entries)) { return false; } unset($entries['.'], $entries['..']); foreach ($entries as $filename => $props) { if (!isset($props['type'])) { return false; } $temp = $path . '/' . $filename; if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) { if (!$this->delete_recursive($temp, $i)) { return false; } } else { if (!$this->send_sftp_packet(NET_SFTP_REMOVE, Strings::packSSH2('s', $temp))) { return false; } $this->remove_from_stat_cache($temp); $i++; if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->read_put_responses($i)) { return false; } $i = 0; } } } if (!$this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $path))) { return false; } $this->remove_from_stat_cache($path); $i++; if ($i >= NET_SFTP_QUEUE_SIZE) { if (!$this->read_put_responses($i)) { return false; } $i = 0; } return true; } /** * Checks whether a file or directory exists * * @param string $path * @return bool * @access public */ public function file_exists($path) { if ($this->use_stat_cache) { $path = $this->realpath($path); $result = $this->query_stat_cache($path); if (isset($result)) { // return true if $result is an array or if it's an stdClass object return $result !== false; } } return $this->stat($path) !== false; } /** * Tells whether the filename is a directory * * @param string $path * @return bool * @access public */ public function is_dir($path) { $result = $this->get_stat_cache_prop($path, 'type'); if ($result === false) { return false; } return $result === NET_SFTP_TYPE_DIRECTORY; } /** * Tells whether the filename is a regular file * * @param string $path * @return bool * @access public */ public function is_file($path) { $result = $this->get_stat_cache_prop($path, 'type'); if ($result === false) { return false; } return $result === NET_SFTP_TYPE_REGULAR; } /** * Tells whether the filename is a symbolic link * * @param string $path * @return bool * @access public */ public function is_link($path) { $result = $this->get_lstat_cache_prop($path, 'type'); if ($result === false) { return false; } return $result === NET_SFTP_TYPE_SYMLINK; } /** * Tells whether a file exists and is readable * * @param string $path * @return bool * @access public */ public function is_readable($path) { $packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_READ, 0); if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: return true; case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED return false; default: throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } } /** * Tells whether the filename is writable * * @param string $path * @return bool * @access public */ public function is_writable($path) { $packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_WRITE, 0); if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { return false; } $response = $this->get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_HANDLE: return true; case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED return false; default: throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } } /** * Tells whether the filename is writeable * * Alias of is_writable * * @param string $path * @return bool * @access public */ public function is_writeable($path) { return $this->is_writable($path); } /** * Gets last access time of file * * @param string $path * @return mixed * @access public */ public function fileatime($path) { return $this->get_stat_cache_prop($path, 'atime'); } /** * Gets file modification time * * @param string $path * @return mixed * @access public */ public function filemtime($path) { return $this->get_stat_cache_prop($path, 'mtime'); } /** * Gets file permissions * * @param string $path * @return mixed * @access public */ public function fileperms($path) { return $this->get_stat_cache_prop($path, 'permissions'); } /** * Gets file owner * * @param string $path * @return mixed * @access public */ public function fileowner($path) { return $this->get_stat_cache_prop($path, 'uid'); } /** * Gets file group * * @param string $path * @return mixed * @access public */ public function filegroup($path) { return $this->get_stat_cache_prop($path, 'gid'); } /** * Gets file size * * @param string $path * @return mixed * @access public */ public function filesize($path) { return $this->get_stat_cache_prop($path, 'size'); } /** * Gets file type * * @param string $path * @return mixed * @access public */ public function filetype($path) { $type = $this->get_stat_cache_prop($path, 'type'); if ($type === false) { return false; } switch ($type) { case NET_SFTP_TYPE_BLOCK_DEVICE: return 'block'; case NET_SFTP_TYPE_CHAR_DEVICE: return 'char'; case NET_SFTP_TYPE_DIRECTORY: return 'dir'; case NET_SFTP_TYPE_FIFO: return 'fifo'; case NET_SFTP_TYPE_REGULAR: return 'file'; case NET_SFTP_TYPE_SYMLINK: return 'link'; default: return false; } } /** * Return a stat properity * * Uses cache if appropriate. * * @param string $path * @param string $prop * @return mixed * @access private */ private function get_stat_cache_prop($path, $prop) { return $this->get_xstat_cache_prop($path, $prop, 'stat'); } /** * Return an lstat properity * * Uses cache if appropriate. * * @param string $path * @param string $prop * @return mixed * @access private */ private function get_lstat_cache_prop($path, $prop) { return $this->get_xstat_cache_prop($path, $prop, 'lstat'); } /** * Return a stat or lstat properity * * Uses cache if appropriate. * * @param string $path * @param string $prop * @param string $type * @return mixed * @access private */ private function get_xstat_cache_prop($path, $prop, $type) { if ($this->use_stat_cache) { $path = $this->realpath($path); $result = $this->query_stat_cache($path); if (is_object($result) && isset($result->$type)) { return $result->{$type}[$prop]; } } $result = $this->$type($path); if ($result === false || !isset($result[$prop])) { return false; } return $result[$prop]; } /** * Renames a file or a directory on the SFTP server * * @param string $oldname * @param string $newname * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @access public */ public function rename($oldname, $newname) { if (!($this->bitmap & SSH2::MASK_LOGIN)) { return false; } $oldname = $this->realpath($oldname); $newname = $this->realpath($newname); if ($oldname === false || $newname === false) { return false; } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 $packet = Strings::packSSH2('ss', $oldname, $newname); if (!$this->send_sftp_packet(NET_SFTP_RENAME, $packet)) { return false; } $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED list($status) = Strings::unpackSSH2('N', $response); if ($status != NET_SFTP_STATUS_OK) { $this->logError($response, $status); return false; } // don't move the stat cache entry over since this operation could very well change the // atime and mtime attributes //$this->update_stat_cache($newname, $this->query_stat_cache($oldname)); $this->remove_from_stat_cache($oldname); $this->remove_from_stat_cache($newname); return true; } /** * Parse Attributes * * See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info. * * @param string $response * @return array * @access private */ private function parseAttributes(&$response) { $attr = []; list($flags) = Strings::unpackSSH2('N', $response); // SFTPv4+ have a type field (a byte) that follows the above flag field foreach ($this->attributes as $key => $value) { switch ($flags & $key) { case NET_SFTP_ATTR_SIZE: // 0x00000001 // The size attribute is defined as an unsigned 64-bit integer. // The following will use floats on 32-bit platforms, if necessary. // As can be seen in the BigInteger class, floats are generally // IEEE 754 binary64 "double precision" on such platforms and // as such can represent integers of at least 2^50 without loss // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB. list($upper, $size) = Strings::unpackSSH2('NN', $response); $attr['size'] = $upper ? 4294967296 * $upper : 0; $attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; break; case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) list($attr['uid'], $attr['gid']) = Strings::unpackSSH2('NN', $response); break; case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004 list($attr['permissions']) = Strings::unpackSSH2('N', $response); // mode == permissions; permissions was the original array key and is retained for bc purposes. // mode was added because that's the more industry standard terminology $attr+= ['mode' => $attr['permissions']]; $fileType = $this->parseMode($attr['permissions']); if ($fileType !== false) { $attr+= ['type' => $fileType]; } break; case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008 list($attr['atime'], $attr['mtime']) = Strings::unpackSSH2('NN', $response); break; case NET_SFTP_ATTR_EXTENDED: // 0x80000000 list($count) = Strings::unpack('N', $response); for ($i = 0; $i < $count; $i++) { list($key, $value) = Strings::unpackSSH2('ss', $response); $attr[$key] = $value; } } } return $attr; } /** * Attempt to identify the file type * * Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway * * @param int $mode * @return int * @access private */ private function parseMode($mode) { // values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12 // see, also, http://linux.die.net/man/2/stat switch ($mode & 0170000) {// ie. 1111 0000 0000 0000 case 0000000: // no file type specified - figure out the file type using alternative means return false; case 0040000: return NET_SFTP_TYPE_DIRECTORY; case 0100000: return NET_SFTP_TYPE_REGULAR; case 0120000: return NET_SFTP_TYPE_SYMLINK; // new types introduced in SFTPv5+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 case 0010000: // named pipe (fifo) return NET_SFTP_TYPE_FIFO; case 0020000: // character special return NET_SFTP_TYPE_CHAR_DEVICE; case 0060000: // block special return NET_SFTP_TYPE_BLOCK_DEVICE; case 0140000: // socket return NET_SFTP_TYPE_SOCKET; case 0160000: // whiteout // "SPECIAL should be used for files that are of // a known type which cannot be expressed in the protocol" return NET_SFTP_TYPE_SPECIAL; default: return NET_SFTP_TYPE_UNKNOWN; } } /** * Parse Longname * * SFTPv3 doesn't provide any easy way of identifying a file type. You could try to open * a file as a directory and see if an error is returned or you could try to parse the * SFTPv3-specific longname field of the SSH_FXP_NAME packet. That's what this function does. * The result is returned using the * {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}. * * If the longname is in an unrecognized format bool(false) is returned. * * @param string $longname * @return mixed * @access private */ private function parseLongname($longname) { // http://en.wikipedia.org/wiki/Unix_file_types // http://en.wikipedia.org/wiki/Filesystem_permissions#Notation_of_traditional_Unix_permissions if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) { switch ($longname[0]) { case '-': return NET_SFTP_TYPE_REGULAR; case 'd': return NET_SFTP_TYPE_DIRECTORY; case 'l': return NET_SFTP_TYPE_SYMLINK; default: return NET_SFTP_TYPE_SPECIAL; } } return false; } /** * Sends SFTP Packets * * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info. * * @param int $type * @param string $data * @see self::_get_sftp_packet() * @see self::send_channel_packet() * @return bool * @access private */ private function send_sftp_packet($type, $data, $request_id = 1) { $packet = $this->use_request_id ? pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) : pack('NCa*', strlen($data) + 1, $type, $data); $start = microtime(true); $result = $this->send_channel_packet(self::CHANNEL, $packet); $stop = microtime(true); if (defined('NET_SFTP_LOGGING')) { $packet_type = '-> ' . $this->packet_types[$type] . ' (' . round($stop - $start, 4) . 's)'; if (NET_SFTP_LOGGING == self::LOG_REALTIME) { echo "<pre>\r\n" . $this->format_log([$data], [$packet_type]) . "\r\n</pre>\r\n"; flush(); ob_flush(); } else { $this->packet_type_log[] = $packet_type; if (NET_SFTP_LOGGING == self::LOG_COMPLEX) { $this->packet_log[] = $data; } } } return $result; } /** * Receives SFTP Packets * * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info. * * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present. * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA * messages containing one SFTP packet. * * @see self::_send_sftp_packet() * @return string * @access private */ private function get_sftp_packet($request_id = null) { if (isset($request_id) && isset($this->requestBuffer[$request_id])) { $this->packet_type = $this->requestBuffer[$request_id]['packet_type']; $temp = $this->requestBuffer[$request_id]['packet']; unset($this->requestBuffer[$request_id]); return $temp; } // in SSH2.php the timeout is cumulative per function call. eg. exec() will // timeout after 10s. but for SFTP.php it's cumulative per packet $this->curTimeout = $this->timeout; $start = microtime(true); // SFTP packet length while (strlen($this->packet_buffer) < 4) { $temp = $this->get_channel_packet(self::CHANNEL, true); if (is_bool($temp)) { $this->packet_type = false; $this->packet_buffer = ''; return false; } $this->packet_buffer.= $temp; } if (strlen($this->packet_buffer) < 4) { return false; } extract(unpack('Nlength', Strings::shift($this->packet_buffer, 4))); /** @var integer $length */ $tempLength = $length; $tempLength-= strlen($this->packet_buffer); // 256 * 1024 is what SFTP_MAX_MSG_LENGTH is set to in OpenSSH's sftp-common.h if ($tempLength > 256 * 1024) { throw new \RuntimeException('Invalid Size'); } // SFTP packet type and data payload while ($tempLength > 0) { $temp = $this->get_channel_packet(self::CHANNEL, true); if (is_bool($temp)) { $this->packet_type = false; $this->packet_buffer = ''; return false; } $this->packet_buffer.= $temp; $tempLength-= strlen($temp); } $stop = microtime(true); $this->packet_type = ord(Strings::shift($this->packet_buffer)); if ($this->use_request_id) { extract(unpack('Npacket_id', Strings::shift($this->packet_buffer, 4))); // remove the request id $length-= 5; // account for the request id and the packet type } else { $length-= 1; // account for the packet type } $packet = Strings::shift($this->packet_buffer, $length); if (defined('NET_SFTP_LOGGING')) { $packet_type = '<- ' . $this->packet_types[$this->packet_type] . ' (' . round($stop - $start, 4) . 's)'; if (NET_SFTP_LOGGING == self::LOG_REALTIME) { echo "<pre>\r\n" . $this->format_log([$packet], [$packet_type]) . "\r\n</pre>\r\n"; flush(); ob_flush(); } else { $this->packet_type_log[] = $packet_type; if (NET_SFTP_LOGGING == self::LOG_COMPLEX) { $this->packet_log[] = $packet; } } } if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) { $this->requestBuffer[$packet_id] = array( 'packet_type' => $this->packet_type, 'packet' => $packet ); return $this->_get_sftp_packet($request_id); } return $packet; } /** * Returns a log of the packets that have been sent and received. * * Returns a string if NET_SFTP_LOGGING == self::LOG_COMPLEX, an array if NET_SFTP_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING') * * @access public * @return array|string */ public function getSFTPLog() { if (!defined('NET_SFTP_LOGGING')) { return false; } switch (NET_SFTP_LOGGING) { case self::LOG_COMPLEX: return $this->format_log($this->packet_log, $this->packet_type_log); break; //case self::LOG_SIMPLE: default: return $this->packet_type_log; } } /** * Returns all errors * * @return array * @access public */ public function getSFTPErrors() { return $this->sftp_errors; } /** * Returns the last error * * @return string * @access public */ public function getLastSFTPError() { return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : ''; } /** * Get supported SFTP versions * * @return array * @access public */ public function getSupportedVersions() { $temp = ['version' => $this->version]; if (isset($this->extensions['versions'])) { $temp['extensions'] = $this->extensions['versions']; } return $temp; } /** * Disconnect * * @param int $reason * @return bool * @access protected */ protected function disconnect_helper($reason) { $this->pwd = false; parent::disconnect_helper($reason); } } <?php /** * SFTP Stream Wrapper * * Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc. * * PHP version 5 * * @category Net * @package SFTP * @author Jim Wigginton <terrafrost@php.net> * @copyright 2013 Jim Wigginton * @license http://www.opensource.org/licenses/mit-license.html MIT License * @link http://phpseclib.sourceforge.net */ namespace phpseclib\Net\SFTP; use phpseclib\Crypt\RSA; use phpseclib\Net\SFTP; use phpseclib\Net\SSH2; /** * SFTP Stream Wrapper * * @package SFTP * @author Jim Wigginton <terrafrost@php.net> * @access public */ class Stream { /** * SFTP instances * * Rather than re-create the connection we re-use instances if possible * * @var array */ static $instances; /** * SFTP instance * * @var object * @access private */ private $sftp; /** * Path * * @var string * @access private */ private $path; /** * Mode * * @var string * @access private */ private $mode; /** * Position * * @var int * @access private */ private $pos; /** * Size * * @var int * @access private */ private $size; /** * Directory entries * * @var array * @access private */ private $entries; /** * EOF flag * * @var bool * @access private */ private $eof; /** * Context resource * * Technically this needs to be publicly accessible so PHP can set it directly * * @var resource * @access public */ public $context; /** * Notification callback function * * @var callable * @access public */ private $notification; /** * Registers this class as a URL wrapper. * * @param string $protocol The wrapper name to be registered. * @return bool True on success, false otherwise. * @access public */ public static function register($protocol = 'sftp') { if (in_array($protocol, stream_get_wrappers(), true)) { return false; } return stream_wrapper_register($protocol, get_called_class()); } /** * The Constructor * * @access public */ public function __construct() { if (defined('NET_SFTP_STREAM_LOGGING')) { echo "__construct()\r\n"; } } /** * Path Parser * * Extract a path from a URI and actually connect to an SSH server if appropriate * * If "notification" is set as a context parameter the message code for successful login is * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE. * * @param string $path * @return string * @access private */ private function parse_path($path) { $orig = $path; extract(parse_url($path) + ['port' => 22]); if (isset($query)) { $path.= '?' . $query; } elseif (preg_match('/(\?|\?#)$/', $orig)) { $path.= '?'; } if (isset($fragment)) { $path.= '#' . $fragment; } elseif ($orig[strlen($orig) - 1] == '#') { $path.= '#'; } if (!isset($host)) { return false; } if (isset($this->context)) { $context = stream_context_get_params($this->context); if (isset($context['notification'])) { $this->notification = $context['notification']; } } if (preg_match('/^{[a-z0-9]+}$/i', $host)) { $host = SSH2::getConnectionByResourceId($host); if ($host === false) { return false; } $this->sftp = $host; } else { if (isset($this->context)) { $context = stream_context_get_options($this->context); } if (isset($context[$scheme]['session'])) { $sftp = $context[$scheme]['session']; } if (isset($context[$scheme]['sftp'])) { $sftp = $context[$scheme]['sftp']; } if (isset($sftp) && $sftp instanceof SFTP) { $this->sftp = $sftp; return $path; } if (isset($context[$scheme]['username'])) { $user = $context[$scheme]['username']; } if (isset($context[$scheme]['password'])) { $pass = $context[$scheme]['password']; } if (isset($context[$scheme]['privkey']) && $context[$scheme]['privkey'] instanceof RSA) { $pass = $context[$scheme]['privkey']; } if (!isset($user) || !isset($pass)) { return false; } // casting $pass to a string is necessary in the event that it's a \phpseclib\Crypt\RSA object if (isset(self::$instances[$host][$port][$user][(string) $pass])) { $this->sftp = self::$instances[$host][$port][$user][(string) $pass]; } else { $this->sftp = new SFTP($host, $port); $this->sftp->disableStatCache(); if (isset($this->notification) && is_callable($this->notification)) { /* if !is_callable($this->notification) we could do this: user_error('fopen(): failed to call user notifier', E_USER_WARNING); the ftp wrapper gives errors like that when the notifier isn't callable. i've opted not to do that, however, since the ftp wrapper gives the line on which the fopen occurred as the line number - not the line that the user_error is on. */ call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); if (!$this->sftp->login($user, $pass)) { call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0); return false; } call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0); } else { if (!$this->sftp->login($user, $pass)) { return false; } } self::$instances[$host][$port][$user][(string) $pass] = $this->sftp; } } return $path; } /** * Opens file or URL * * @param string $path * @param string $mode * @param int $options * @param string $opened_path * @return bool * @access public */ private function _stream_open($path, $mode, $options, &$opened_path) { $path = $this->parse_path($path); if ($path === false) { return false; } $this->path = $path; $this->size = $this->sftp->size($path); $this->mode = preg_replace('#[bt]$#', '', $mode); $this->eof = false; if ($this->size === false) { if ($this->mode[0] == 'r') { return false; } else { $this->sftp->touch($path); $this->size = 0; } } else { switch ($this->mode[0]) { case 'x': return false; case 'w': $this->sftp->truncate($path, 0); $this->size = 0; } } $this->pos = $this->mode[0] != 'a' ? 0 : $this->size; return true; } /** * Read from stream * * @param int $count * @return mixed * @access public */ private function _stream_read($count) { switch ($this->mode) { case 'w': case 'a': case 'x': case 'c': return false; } // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite //if ($this->pos >= $this->size) { // $this->eof = true; // return false; //} $result = $this->sftp->get($this->path, false, $this->pos, $count); if (isset($this->notification) && is_callable($this->notification)) { if ($result === false) { call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); return 0; } // seems that PHP calls stream_read in 8k chunks call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size); } if (empty($result)) { // ie. false or empty string $this->eof = true; return false; } $this->pos+= strlen($result); return $result; } /** * Write to stream * * @param string $data * @return mixed * @access public */ private function _stream_write($data) { switch ($this->mode) { case 'r': return false; } $result = $this->sftp->put($this->path, $data, SFTP::SOURCE_STRING, $this->pos); if (isset($this->notification) && is_callable($this->notification)) { if (!$result) { call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); return 0; } // seems that PHP splits up strings into 8k blocks before calling stream_write call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data)); } if ($result === false) { return false; } $this->pos+= strlen($data); if ($this->pos > $this->size) { $this->size = $this->pos; } $this->eof = false; return strlen($data); } /** * Retrieve the current position of a stream * * @return int * @access public */ private function _stream_tell() { return $this->pos; } /** * Tests for end-of-file on a file pointer * * In my testing there are four classes functions that normally effect the pointer: * fseek, fputs / fwrite, fgets / fread and ftruncate. * * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof() * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof() * will return false. do fread($fp, 1) and feof() will then return true. * * @return bool * @access public */ private function _stream_eof() { return $this->eof; } /** * Seeks to specific location in a stream * * @param int $offset * @param int $whence * @return bool * @access public */ private function _stream_seek($offset, $whence) { switch ($whence) { case SEEK_SET: if ($offset >= $this->size || $offset < 0) { return false; } break; case SEEK_CUR: $offset+= $this->pos; break; case SEEK_END: $offset+= $this->size; } $this->pos = $offset; $this->eof = false; return true; } /** * Change stream options * * @param string $path * @param int $option * @param mixed $var * @return bool * @access public */ private function _stream_metadata($path, $option, $var) { $path = $this->parse_path($path); if ($path === false) { return false; } // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246 // and https://github.com/php/php-src/blob/master/main/php_streams.h#L592 switch ($option) { case 1: // PHP_STREAM_META_TOUCH return $this->sftp->touch($path, $var[0], $var[1]); case 2: // PHP_STREAM_OWNER_NAME case 3: // PHP_STREAM_GROUP_NAME return false; case 4: // PHP_STREAM_META_OWNER return $this->sftp->chown($path, $var); case 5: // PHP_STREAM_META_GROUP return $this->sftp->chgrp($path, $var); case 6: // PHP_STREAM_META_ACCESS return $this->sftp->chmod($path, $var) !== false; } } /** * Retrieve the underlaying resource * * @param int $cast_as * @return resource * @access public */ private function _stream_cast($cast_as) { return $this->sftp->fsock; } /** * Advisory file locking * * @param int $operation * @return bool * @access public */ private function _stream_lock($operation) { return false; } /** * Renames a file or directory * * Attempts to rename oldname to newname, moving it between directories if necessary. * If newname exists, it will be overwritten. This is a departure from what \phpseclib\Net\SFTP * does. * * @param string $path_from * @param string $path_to * @return bool * @access public */ private function _rename($path_from, $path_to) { $path1 = parse_url($path_from); $path2 = parse_url($path_to); unset($path1['path'], $path2['path']); if ($path1 != $path2) { return false; } $path_from = $this->parse_path($path_from); $path_to = parse_url($path_to); if ($path_from === false) { return false; } $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2 // "It is an error if there already exists a file with the name specified by newpath." // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 if (!$this->sftp->rename($path_from, $path_to)) { if ($this->sftp->stat($path_to)) { return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to); } return false; } return true; } /** * Open directory handle * * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and * removed in 5.4 I'm just going to ignore it. * * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting * the SFTP specs: * * The SSH_FXP_NAME response has the following format: * * uint32 id * uint32 count * repeats count times: * string filename * string longname * ATTRS attrs * * @param string $path * @param int $options * @return bool * @access public */ private function _dir_opendir($path, $options) { $path = $this->parse_path($path); if ($path === false) { return false; } $this->pos = 0; $this->entries = $this->sftp->nlist($path); return $this->entries !== false; } /** * Read entry from directory handle * * @return mixed * @access public */ private function _dir_readdir() { if (isset($this->entries[$this->pos])) { return $this->entries[$this->pos++]; } return false; } /** * Rewind directory handle * * @return bool * @access public */ private function _dir_rewinddir() { $this->pos = 0; return true; } /** * Close directory handle * * @return bool * @access public */ private function _dir_closedir() { return true; } /** * Create a directory * * Only valid $options is STREAM_MKDIR_RECURSIVE * * @param string $path * @param int $mode * @param int $options * @return bool * @access public */ private function _mkdir($path, $mode, $options) { $path = $this->parse_path($path); if ($path === false) { return false; } return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE); } /** * Removes a directory * * Only valid $options is STREAM_MKDIR_RECURSIVE per <http://php.net/streamwrapper.rmdir>, however, * <http://php.net/rmdir> does not have a $recursive parameter as mkdir() does so I don't know how * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as * $options. What does 8 correspond to? * * @param string $path * @param int $options * @return bool * @access public */ private function _rmdir($path, $options) { $path = $this->parse_path($path); if ($path === false) { return false; } return $this->sftp->rmdir($path); } /** * Flushes the output * * See <http://php.net/fflush>. Always returns true because \phpseclib\Net\SFTP doesn't cache stuff before writing * * @return bool * @access public */ private function _stream_flush() { return true; } /** * Retrieve information about a file resource * * @return mixed * @access public */ private function _stream_stat() { $results = $this->sftp->stat($this->path); if ($results === false) { return false; } return $results; } /** * Delete a file * * @param string $path * @return bool * @access public */ private function _unlink($path) { $path = $this->parse_path($path); if ($path === false) { return false; } return $this->sftp->delete($path, false); } /** * Retrieve information about a file * * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of \phpseclib\Net\SFTP\Stream is quiet by default * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll * cross that bridge when and if it's reached * * @param string $path * @param int $flags * @return mixed * @access public */ private function _url_stat($path, $flags) { $path = $this->parse_path($path); if ($path === false) { return false; } $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path); if ($results === false) { return false; } return $results; } /** * Truncate stream * * @param int $new_size * @return bool * @access public */ private function _stream_truncate($new_size) { if (!$this->sftp->truncate($this->path, $new_size)) { return false; } $this->eof = false; $this->size = $new_size; return true; } /** * Change stream options * * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't. * The other two aren't supported because of limitations in \phpseclib\Net\SFTP. * * @param int $option * @param int $arg1 * @param int $arg2 * @return bool * @access public */ private function _stream_set_option($option, $arg1, $arg2) { return false; } /** * Close an resource * * @access public */ private function _stream_close() { } /** * __call Magic Method * * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you. * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function * lets you figure that out. * * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method. * * @param string * @param array * @return mixed * @access public */ public function __call($name, $arguments) { if (defined('NET_SFTP_STREAM_LOGGING')) { echo $name . '('; $last = count($arguments) - 1; foreach ($arguments as $i => $argument) { var_export($argument); if ($i != $last) { echo ','; } } echo ")\r\n"; } $name = '_' . $name; if (!method_exists($this, $name)) { return false; } return call_user_func_array([$this, $name], $arguments); } } { "name": "phpseclib/phpseclib", "type": "library", "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", "keywords": [ "security", "crypto", "cryptography", "encryption", "signature", "signing", "rsa", "aes", "blowfish", "twofish", "ssh", "sftp", "x509", "x.509", "asn1", "asn.1", "BigInteger" ], "homepage": "http://phpseclib.sourceforge.net", "license": "MIT", "authors": [ { "name": "Jim Wigginton", "email": "terrafrost@php.net", "role": "Lead Developer" }, { "name": "Patrick Monnerat", "email": "pm@datasphere.ch", "role": "Developer" }, { "name": "Andreas Fischer", "email": "bantu@phpbb.com", "role": "Developer" }, { "name": "Hans-Jürgen Petrich", "email": "petrich@tronic-media.com", "role": "Developer" }, { "name": "Graham Campbell", "email": "graham@alt-three.com", "role": "Developer" } ], "require": { "paragonie/constant_time_encoding": "^1", "paragonie/random_compat": "^1.4|^2.0", "php": ">=5.6.1" }, "require-dev": { "phing/phing": "~2.7", "phpunit/phpunit": "^4.8.35|^5.7|^6.0", "sami/sami": "~2.0", "squizlabs/php_codesniffer": "~2.0" }, "suggest": { "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations." }, "autoload": { "files": [ "phpseclib/bootstrap.php" ], "psr-4": { "phpseclib\\": "phpseclib/" } } } <?php // Prevent e.g. 'Notice: Constant MATH_BIGINTEGER_MONTGOMERY already defined'. class MyArrayStore extends Sami\Store\ArrayStore { public function removeClass(Sami\Project $project, $name) { unset($this->classes[$name]); } } $iterator = Symfony\Component\Finder\Finder::create() ->files() ->name('*.php') ->in(__DIR__ . '/../phpseclib/') ; $versions = Sami\Version\GitVersionCollection::create(__DIR__ . '/../') ->add('1.0') ->add('2.0') ->add('master') ; return new Sami\Sami($iterator, array( 'theme' => 'enhanced', 'versions' => $versions, 'title' => 'phpseclib API Documentation', 'build_dir' => __DIR__.'/api/output/%version%', 'cache_dir' => __DIR__.'/api/cache/%version%', 'default_opened_level' => 2, 'store' => new MyArrayStore, )); { "name": "league/uri-interfaces", "description" : "Common interface for URI representation", "keywords": [ "url", "uri", "rfc3986", "rfc3987" ], "license": "MIT", "homepage": "http://github.com/thephpleague/uri-interfaces", "authors": [ { "name" : "Ignace Nyamagana Butera", "email" : "nyamsprod@gmail.com", "homepage" : "https://nyamsprod.com" } ], "require": { "php" : ">=5.3.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0.0" }, "autoload": { "psr-4": { "League\\Uri\\": "src/" } }, "scripts": { "test": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes;" }, "extra": { "branch-alias": { "dev-master": "1.x-dev" } } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Interfaces * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @copyright 2016 Ignace Nyamagana Butera * @license https://github.com/thephpleague/uri-interfaces/blob/master/LICENSE (MIT License) * @version 1.1.0 * @link https://github.com/thephpleague/uri-interfaces/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri; use InvalidArgumentException; /** * Value object representing a URI. * * Instances of this interface are considered immutable; all methods that * might change state MUST be implemented such that they retain the internal * state of the current instance and return an instance that contains the * changed state. * * @see https://tools.ietf.org/html/rfc3986 * @package League\Uri * @subpackage League\Uri\Interfaces * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.1.0 */ interface UriInterface { /** * Retrieve the scheme component of the URI. * * If no scheme is present, this method MUST return an empty string. * * The value returned MUST be normalized to lowercase, per RFC 3986 * Section 3.1. * * The trailing ":" character is not part of the scheme and MUST NOT be * added. * * @see https://tools.ietf.org/html/rfc3986#section-3.1 * * @return string The URI scheme. */ public function getScheme(); /** * Retrieve the authority component of the URI. * * If no authority information is present, this method MUST return an empty * string. * * The authority syntax of the URI is: * * <pre> * [user-info@]host[:port] * </pre> * * If the port component is not set or is the standard port for the current * scheme, it SHOULD NOT be included. * * @see https://tools.ietf.org/html/rfc3986#section-3.2 * * @return string The URI authority, in "[user-info@]host[:port]" format. */ public function getAuthority(); /** * Retrieve the user information component of the URI. * * If no user information is present, this method MUST return an empty * string. * * If a user is present in the URI, this will return that value; * additionally, if the password is also present, it will be appended to the * user value, with a colon (":") separating the values. * * The trailing "@" character is not part of the user information and MUST * NOT be added. * * @return string The URI user information, in "username[:password]" format. */ public function getUserInfo(); /** * Retrieve the host component of the URI. * * If no host is present, this method MUST return an empty string. * * The value returned MUST be normalized to lowercase, per RFC 3986 * Section 3.2.2. * * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 * * @return string The URI host. */ public function getHost(); /** * Retrieve the port component of the URI. * * If a port is present, and it is non-standard for the current scheme, * this method MUST return it as an integer. If the port is the standard port * used with the current scheme, this method SHOULD return null. * * If no port is present, and no scheme is present, this method MUST return * a null value. * * If no port is present, but a scheme is present, this method MAY return * the standard port for that scheme, but SHOULD return null. * * @return null|int The URI port. */ public function getPort(); /** * Retrieve the path component of the URI. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * Normally, the empty path "" and absolute path "/" are considered equal as * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically * do this normalization because in contexts with a trimmed base path, e.g. * the front controller, this difference becomes significant. It's the task * of the user to handle both "" and "/". * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.3. * * As an example, if the value should include a slash ("/") not intended as * delimiter between path segments, that value MUST be passed in encoded * form (e.g., "%2F") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.3 * * @return string The URI path. */ public function getPath(); /** * Retrieve the query string of the URI. * * If no query string is present, this method MUST return an empty string. * * The leading "?" character is not part of the query and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.4. * * As an example, if a value in a key/value pair of the query string should * include an ampersand ("&") not intended as a delimiter between values, * that value MUST be passed in encoded form (e.g., "%26") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.4 * * @return string The URI query string. */ public function getQuery(); /** * Retrieve the fragment component of the URI. * * If no fragment is present, this method MUST return an empty string. * * The leading "#" character is not part of the fragment and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.5. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.5 * * @return string The URI fragment. */ public function getFragment(); /** * Return an instance with the specified scheme. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified scheme. * * An empty scheme is equivalent to removing the scheme. * * @param string $scheme The scheme to use with the new instance. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * @return self A new instance with the specified scheme. */ public function withScheme($scheme); /** * Return an instance with the specified user information. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified user information. * * Password is optional, but the user information MUST include the * user; an empty string for the user is equivalent to removing user * information. * * @param string $user The user name to use for authority. * @param null|string $password The password associated with $user. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * @return self A new instance with the specified user information. */ public function withUserInfo($user, $password = null); /** * Return an instance with the specified host. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified host. * * An empty host value is equivalent to removing the host. * * @param string $host The hostname to use with the new instance. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * * @return self A new instance with the specified host. */ public function withHost($host); /** * Return an instance with the specified port. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified port. * * Implementations MUST raise an exception for ports outside the * established TCP and UDP port ranges. * * A null value provided for the port is equivalent to removing the port * information. * * @param null|int $port The port to use with the new instance; a null value * removes the port information. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * @return self A new instance with the specified port. */ public function withPort($port); /** * Return an instance with the specified path. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified path. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * Users can provide both encoded and decoded path characters. * Implementations ensure the correct encoding as outlined in getPath(). * * @param string $path The path to use with the new instance. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * @return self A new instance with the specified path. */ public function withPath($path); /** * Return an instance with the specified query string. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified query string. * * Users can provide both encoded and decoded query characters. * Implementations ensure the correct encoding as outlined in getQuery(). * * An empty query string value is equivalent to removing the query string. * * @param string $query The query string to use with the new instance. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * @return self A new instance with the specified query string. */ public function withQuery($query); /** * Return an instance with the specified URI fragment. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified URI fragment. * * Users can provide both encoded and decoded fragment characters. * Implementations ensure the correct encoding as outlined in getFragment(). * * An empty fragment value is equivalent to removing the fragment. * * @param string $fragment The fragment to use with the new instance. * * @throws InvalidArgumentException for invalid component or transformations * that would result in a object in invalid state. * * @return self A new instance with the specified fragment. */ public function withFragment($fragment); /** * Return the string representation as a URI reference. * * Depending on which components of the URI are present, the resulting * string is either a full URI or relative reference according to RFC 3986, * Section 4.1. The method concatenates the various components of the URI, * using the appropriate delimiters: * * - If a scheme is present, it MUST be suffixed by ":". * - If an authority is present, it MUST be prefixed by "//". * - The path is concatenated without delimiters. * - If a query is present, it MUST be prefixed by "?". * - If a fragment is present, it MUST be prefixed by "#". * * @see http://tools.ietf.org/html/rfc3986#section-4.1 * * @return string */ public function __toString(); } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Interfaces * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @copyright 2016 Ignace Nyamagana Butera * @license https://github.com/thephpleague/uri-interfaces/blob/master/LICENSE (MIT License) * @version 1.1.0 * @link https://github.com/thephpleague/uri-interfaces/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Interfaces; use League\Uri\UriInterface; /** * Value object representing a URI. * * Instances of this interface are considered immutable; all methods that * might change state MUST be implemented such that they retain the internal * state of the current instance and return an instance that contains the * changed state. * * @deprecated 1.1.0 will be removed in the next major point release * @see League\Uri\UriInterface * * @package League\Uri * @subpackage League\Uri\Interfaces * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.0.0 */ interface Uri extends UriInterface { } { "name": "league/uri-parser", "type": "library", "description" : "userland URI parser RFC 3986 compliant", "keywords": [ "url", "uri", "rfc3986", "rfc3987", "parse_url", "parser" ], "license": "MIT", "homepage": "https://github.com/thephpleague/uri-parser", "authors": [ { "name" : "Ignace Nyamagana Butera", "email" : "nyamsprod@gmail.com", "homepage" : "https://nyamsprod.com" } ], "require": { "php" : ">=7.0.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", "phpunit/phpunit" : "^6.0", "phpstan/phpstan": "^0.9.2", "phpstan/phpstan-strict-rules": "^0.9.0", "phpstan/phpstan-phpunit": "^0.9.4" }, "autoload": { "psr-4": { "League\\Uri\\": "src" }, "files": ["src/functions_include.php"] }, "autoload-dev": { "psr-4": { "LeagueTest\\Uri\\Parser\\": "tests" } }, "suggest": { "ext-intl" : "Allow parsing RFC3987 compliant hosts", "league/uri-schemes": "Allow validating and normalizing URI parsing results" }, "scripts": { "phpcs": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes;", "phpstan-src": "phpstan analyse -l 7 -c phpstan.src.neon src", "phpstan-tests": "phpstan analyse -l 7 -c phpstan.tests.neon tests", "phpstan": [ "@phpstan-src", "@phpstan-tests" ], "phpunit": "phpunit --coverage-text", "test": [ "@phpunit", "@phpcs", "@phpstan" ] }, "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "config": { "sort-packages": true } } <?php /** * League.Uri (http://uri.thephpleague.com/parser). * * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-parser/blob/master/LICENSE (MIT License) * @version 1.4.1 * @link https://uri.thephpleague.com/parser/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; /** * Returns whether the URI host component is valid according to RFC3986. * * @see https://tools.ietf.org/html/rfc3986#section-3.2.2 * @see Parser::isHost() */ function is_host(string $host): bool { static $parser; $parser = $parser ?? new Parser(); return $parser->isHost($host); } /** * Returns whether the URI port component is valid according to RFC3986. * * @see https://tools.ietf.org/html/rfc3986#section-3.2.3 * @see Parser::isPort() */ function is_port($port): bool { static $parser; $parser = $parser ?? new Parser(); return $parser->isPort($port); } /** * Returns whether the URI scheme component is valid according to RFC3986. * * @see https://tools.ietf.org/html/rfc3986#section-3.1 * @see Parser::isScheme() */ function is_scheme(string $scheme): bool { static $parser; $parser = $parser ?? new Parser(); return $parser->isScheme($scheme); } /** * Parse an URI string into its components. * * This method parses a URL and returns an associative array containing any * of the various components of the URL that are present. * * @see https://tools.ietf.org/html/rfc3986 * @see https://tools.ietf.org/html/rfc3986#section-2 * @see Parser::parse() * * @throws Exception if the URI contains invalid characters */ function parse(string $uri): array { static $parser; $parser = $parser ?? new Parser(); return $parser->parse($uri); } /** * Generate an URI string representation from its parsed representation * returned by League\Uri\Parser::parse() or PHP's parse_url. * * If you supply your own array, you are responsible for providing * valid components without their URI delimiters. * * For security reasons the password (pass) component has been deprecated * as per RFC3986 and is never returned in the URI string * * @see https://tools.ietf.org/html/rfc3986#section-5.3 * @see https://tools.ietf.org/html/rfc3986#section-7.5 */ function build(array $components): string { $uri = $components['path'] ?? ''; if (isset($components['query'])) { $uri .= '?'.$components['query']; } if (isset($components['fragment'])) { $uri .= '#'.$components['fragment']; } if (isset($components['host'])) { $authority = $components['host']; if (isset($components['port'])) { $authority .= ':'.$components['port']; } if (isset($components['user'])) { $authority = $components['user'].'@'.$authority; } $uri = '//'.$authority.$uri; } if (isset($components['scheme'])) { return $components['scheme'].':'.$uri; } return $uri; } <?php /** * League.Uri (http://uri.thephpleague.com/parser). * * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-parser/blob/master/LICENSE (MIT License) * @version 1.4.1 * @link https://uri.thephpleague.com/parser/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use UnexpectedValueException; /** * A class to parse a URI string according to RFC3986. * * @see https://tools.ietf.org/html/rfc3986 * @package League\Uri * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 0.1.0 */ class Parser { /** @deprecated 1.4.0 will be removed in the next major point release */ const INVALID_URI_CHARS = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F"; /** @deprecated 1.4.0 will be removed in the next major point release */ const SCHEME_VALID_STARTING_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; /** @deprecated 1.4.0 will be removed in the next major point release */ const SCHEME_VALID_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-'; /** @deprecated 1.4.0 will be removed in the next major point release */ const LABEL_VALID_STARTING_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; /** @deprecated 1.4.0 will be removed in the next major point release */ const LOCAL_LINK_PREFIX = '1111111010'; const URI_COMPONENTS = [ 'scheme' => null, 'user' => null, 'pass' => null, 'host' => null, 'port' => null, 'path' => '', 'query' => null, 'fragment' => null, ]; /** @deprecated 1.4.0 will be removed in the next major point release */ const SUB_DELIMITERS = '!$&\'()*+,;='; /** * Returns whether a scheme is valid. * * @see https://tools.ietf.org/html/rfc3986#section-3.1 */ public function isScheme(string $scheme): bool { static $pattern = '/^[a-z][a-z0-9\+\.\-]*$/i'; return '' === $scheme || 1 === preg_match($pattern, $scheme); } /** * Returns whether a hostname is valid. * * @see https://tools.ietf.org/html/rfc3986#section-3.2.2 */ public function isHost(string $host): bool { return '' === $host || $this->isIpHost($host) || $this->isRegisteredName($host); } /** * Validate a IPv6/IPvfuture host. * * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 * @see http://tools.ietf.org/html/rfc6874#section-2 * @see http://tools.ietf.org/html/rfc6874#section-4 */ private function isIpHost(string $host): bool { if ('[' !== ($host[0] ?? '') || ']' !== substr($host, -1)) { return false; } $ip = substr($host, 1, -1); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return true; } static $ip_future = '/^ v(?<version>[A-F0-9])+\. (?: (?<unreserved>[a-z0-9_~\-\.])| (?<sub_delims>[!$&\'()*+,;=:]) # also include the : character )+ $/ix'; if (1 === preg_match($ip_future, $ip, $matches) && !in_array($matches['version'], ['4', '6'], true)) { return true; } if (false === ($pos = strpos($ip, '%'))) { return false; } static $gen_delims = '/[:\/?#\[\]@ ]/'; // Also includes space. if (1 === preg_match($gen_delims, rawurldecode(substr($ip, $pos)))) { return false; } $ip = substr($ip, 0, $pos); if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return false; } //Only the address block fe80::/10 can have a Zone ID attach to //let's detect the link local significant 10 bits static $address_block = "\xfe\x80"; return 0 === strpos((string) inet_pton($ip), $address_block); } /** * Returns whether the host is an IPv4 or a registered named. * * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 * * @throws MissingIdnSupport if the registered name contains non-ASCII characters * and IDN support or ICU requirement are not available or met. * */ protected function isRegisteredName(string $host): bool { // Note that unreserved is purposely missing . as it is used to separate labels. static $reg_name = '/(?(DEFINE) (?<unreserved>[a-z0-9_~\-]) (?<sub_delims>[!$&\'()*+,;=]) (?<encoded>%[A-F0-9]{2}) (?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*) ) ^(?:(?®_name)\.)*(?®_name)\.?$/ix'; if (1 === preg_match($reg_name, $host)) { return true; } //to test IDN host non-ascii characters must be present in the host static $idn_pattern = '/[^\x20-\x7f]/'; if (1 !== preg_match($idn_pattern, $host)) { return false; } static $idn_support = null; $idn_support = $idn_support ?? function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46'); // @codeCoverageIgnoreStart // added because it is not possible in travis to disabled the ext/intl extension // see travis issue https://github.com/travis-ci/travis-ci/issues/4701 if (!$idn_support) { throw new MissingIdnSupport(sprintf('the host `%s` could not be processed for IDN. Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6.', $host)); } // @codeCoverageIgnoreEnd $ascii_host = idn_to_ascii($host, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46, $arr); // @codeCoverageIgnoreStart if (false === $ascii_host && 0 === $arr['errors']) { throw new UnexpectedValueException(sprintf('The Intl extension is misconfigured for %s, please correct this issue before proceeding.', PHP_OS)); } // @codeCoverageIgnoreEnd return 0 === $arr['errors']; } /** * Returns whether a port is valid. * * @see https://tools.ietf.org/html/rfc3986#section-3.2.2 */ public function isPort($port): bool { static $pattern = '/^[0-9]+$/'; if (null === $port || '' === $port) { return true; } return 1 === preg_match($pattern, (string) $port); } /** * Parse a URI string into its components. * * @see Parser::parse * * @throws Exception if the URI contains invalid characters */ public function __invoke(string $uri): array { return $this->parse($uri); } /** * Parse an URI string into its components. * * This method parses a URI and returns an associative array containing any * of the various components of the URI that are present. * * <code> * $components = (new Parser())->parse('http://foo@test.example.com:42?query#'); * var_export($components); * //will display * array( * 'scheme' => 'http', // the URI scheme component * 'user' => 'foo', // the URI user component * 'pass' => null, // the URI pass component * 'host' => 'test.example.com', // the URI host component * 'port' => 42, // the URI port component * 'path' => '', // the URI path component * 'query' => 'query', // the URI query component * 'fragment' => '', // the URI fragment component * ); * </code> * * The returned array is similar to PHP's parse_url return value with the following * differences: * * <ul> * <li>All components are always present in the returned array</li> * <li>Empty and undefined component are treated differently. And empty component is * set to the empty string while an undefined component is set to the `null` value.</li> * <li>The path component is never undefined</li> * <li>The method parses the URI following the RFC3986 rules but you are still * required to validate the returned components against its related scheme specific rules.</li> * </ul> * * @see https://tools.ietf.org/html/rfc3986 * @see https://tools.ietf.org/html/rfc3986#section-2 * * @throws Exception if the URI contains invalid characters */ public function parse(string $uri): array { static $pattern = '/[\x00-\x1f\x7f]/'; //simple URI which do not need any parsing static $simple_uri = [ '' => [], '#' => ['fragment' => ''], '?' => ['query' => ''], '?#' => ['query' => '', 'fragment' => ''], '/' => ['path' => '/'], '//' => ['host' => ''], ]; if (isset($simple_uri[$uri])) { return array_merge(self::URI_COMPONENTS, $simple_uri[$uri]); } if (1 === preg_match($pattern, $uri)) { throw Exception::createFromInvalidCharacters($uri); } //if the first character is a known URI delimiter parsing can be simplified $first_char = $uri[0]; //The URI is made of the fragment only if ('#' === $first_char) { $components = self::URI_COMPONENTS; $components['fragment'] = (string) substr($uri, 1); return $components; } //The URI is made of the query and fragment if ('?' === $first_char) { $components = self::URI_COMPONENTS; list($components['query'], $components['fragment']) = explode('#', substr($uri, 1), 2) + [1 => null]; return $components; } //The URI does not contain any scheme part if (0 === strpos($uri, '//')) { return $this->parseSchemeSpecificPart($uri); } //The URI is made of a path, query and fragment if ('/' === $first_char || false === strpos($uri, ':')) { return $this->parsePathQueryAndFragment($uri); } //Fallback parser return $this->fallbackParser($uri); } /** * Extract components from a URI without a scheme part. * * The URI MUST start with the authority component * preceded by its delimiter the double slash ('//') * * Example: //user:pass@host:42/path?query#fragment * * The authority MUST adhere to the RFC3986 requirements. * * If the URI contains a path component, it MUST be empty or absolute * according to RFC3986 path classification. * * This method returns an associative array containing all URI components. * * @see https://tools.ietf.org/html/rfc3986#section-3.2 * @see https://tools.ietf.org/html/rfc3986#section-3.3 * * @throws Exception If any component of the URI is invalid */ protected function parseSchemeSpecificPart(string $uri): array { //We remove the authority delimiter $remaining_uri = (string) substr($uri, 2); $components = self::URI_COMPONENTS; //Parsing is done from the right upmost part to the left //1 - detect fragment, query and path part if any list($remaining_uri, $components['fragment']) = explode('#', $remaining_uri, 2) + [1 => null]; list($remaining_uri, $components['query']) = explode('?', $remaining_uri, 2) + [1 => null]; if (false !== strpos($remaining_uri, '/')) { list($remaining_uri, $components['path']) = explode('/', $remaining_uri, 2) + [1 => null]; $components['path'] = '/'.$components['path']; } //2 - The $remaining_uri represents the authority part //if the authority part is empty parsing is simplified if ('' === $remaining_uri) { $components['host'] = ''; return $components; } //otherwise we split the authority into the user information and the hostname parts $parts = explode('@', $remaining_uri, 2); $hostname = $parts[1] ?? $parts[0]; $user_info = isset($parts[1]) ? $parts[0] : null; if (null !== $user_info) { list($components['user'], $components['pass']) = explode(':', $user_info, 2) + [1 => null]; } list($components['host'], $components['port']) = $this->parseHostname($hostname); return $components; } /** * Parse and validate the URI hostname. * * @throws Exception If the hostname is invalid */ protected function parseHostname(string $hostname): array { if (false === strpos($hostname, '[')) { list($host, $port) = explode(':', $hostname, 2) + [1 => null]; return [$this->filterHost($host), $this->filterPort($port)]; } $delimiter_offset = strpos($hostname, ']') + 1; if (isset($hostname[$delimiter_offset]) && ':' !== $hostname[$delimiter_offset]) { throw Exception::createFromInvalidHostname($hostname); } return [ $this->filterHost(substr($hostname, 0, $delimiter_offset)), $this->filterPort(substr($hostname, ++$delimiter_offset)), ]; } /** * validate the host component. * * @param string|null $host * * @throws Exception If the hostname is invalid * * @return string|null */ protected function filterHost($host) { if (null === $host || $this->isHost($host)) { return $host; } throw Exception::createFromInvalidHost($host); } /** * Validate a port number. * * An exception is raised for ports outside the established TCP and UDP port ranges. * * @param mixed $port the port number * * @throws Exception If the port number is invalid. * * @return null|int */ protected function filterPort($port) { static $pattern = '/^[0-9]+$/'; if (null === $port || false === $port || '' === $port) { return null; } if (1 !== preg_match($pattern, (string) $port)) { throw Exception::createFromInvalidPort($port); } return (int) $port; } /** * Extract Components from an URI without scheme or authority part. * * The URI contains a path component and MUST adhere to path requirements * of RFC3986. The path can be * * <code> * path = path-abempty ; begins with "/" or is empty * / path-absolute ; begins with "/" but not "//" * / path-noscheme ; begins with a non-colon segment * / path-rootless ; begins with a segment * / path-empty ; zero characters * </code> * * ex: path?q#f * ex: /path * ex: /pa:th#f * * This method returns an associative array containing all URI components. * * @see https://tools.ietf.org/html/rfc3986#section-3.3 * * @throws Exception If the path component is invalid */ protected function parsePathQueryAndFragment(string $uri): array { //No scheme is present so we ensure that the path respects RFC3986 if (false !== ($pos = strpos($uri, ':')) && false === strpos(substr($uri, 0, $pos), '/')) { throw Exception::createFromInvalidPath($uri); } $components = self::URI_COMPONENTS; //Parsing is done from the right upmost part to the left //1 - detect the fragment part if any list($remaining_uri, $components['fragment']) = explode('#', $uri, 2) + [1 => null]; //2 - detect the query and the path part list($components['path'], $components['query']) = explode('?', $remaining_uri, 2) + [1 => null]; return $components; } /** * Extract components from an URI containing a colon. * * Depending on the colon ":" position and on the string * composition before the presence of the colon, the URI * will be considered to have an scheme or not. * * <ul> * <li>In case no valid scheme is found according to RFC3986 the URI will * be parsed as an URI without a scheme and an authority</li> * <li>In case an authority part is detected the URI specific part is parsed * as an URI without scheme</li> * </ul> * * ex: email:johndoe@thephpleague.com?subject=Hellow%20World! * * This method returns an associative array containing all * the URI components. * * @see https://tools.ietf.org/html/rfc3986#section-3.1 * @see Parser::parsePathQueryAndFragment * @see Parser::parseSchemeSpecificPart * * @throws Exception If the URI scheme component is empty */ protected function fallbackParser(string $uri): array { //1 - we split the URI on the first detected colon character $parts = explode(':', $uri, 2); $remaining_uri = $parts[1] ?? $parts[0]; $scheme = isset($parts[1]) ? $parts[0] : null; //1.1 - a scheme can not be empty (ie a URI can not start with a colon) if ('' === $scheme) { throw Exception::createFromInvalidScheme($uri); } //2 - depending on the scheme presence and validity we will differ the parsing //2.1 - If the scheme part is invalid the URI may be an URI with a path-noscheme // let's differ the parsing to the Parser::parsePathQueryAndFragment method if (!$this->isScheme($scheme)) { return $this->parsePathQueryAndFragment($uri); } $components = self::URI_COMPONENTS; $components['scheme'] = $scheme; //2.2 - if no scheme specific part is detect parsing is finished if ('' == $remaining_uri) { return $components; } //2.3 - if the scheme specific part is a double forward slash if ('//' === $remaining_uri) { $components['host'] = ''; return $components; } //2.4 - if the scheme specific part starts with double forward slash // we differ the remaining parsing to the Parser::parseSchemeSpecificPart method if (0 === strpos($remaining_uri, '//')) { $components = $this->parseSchemeSpecificPart($remaining_uri); $components['scheme'] = $scheme; return $components; } //2.5 - Parsing is done from the right upmost part to the left from the scheme specific part //2.5.1 - detect the fragment part if any list($remaining_uri, $components['fragment']) = explode('#', $remaining_uri, 2) + [1 => null]; //2.5.2 - detect the part and query part if any list($components['path'], $components['query']) = explode('?', $remaining_uri, 2) + [1 => null]; return $components; } /** * Convert a registered name label to its IDNA ASCII form. * * DEPRECATION WARNING! This method will be removed in the next major point release * * @deprecated 1.4.0 this method is no longer used to validate RFC3987 compliant host component * @codeCoverageIgnore * * Conversion is done only if the label contains none valid label characters * if a '%' sub delimiter is detected the label MUST be rawurldecode prior to * making the conversion * * @return string|false */ protected function toAscii(string $label) { trigger_error( self::class.'::'.__METHOD__.' is deprecated and will be removed in the next major point release', E_USER_DEPRECATED ); if (false !== strpos($label, '%')) { $label = rawurldecode($label); } static $idn_support = null; $idn_support = $idn_support ?? function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46'); if (!$idn_support) { throw new MissingIdnSupport(sprintf('the label `%s` could not be processed for IDN. Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6.', $label)); } $ascii_host = idn_to_ascii($label, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46, $arr); if (false === $ascii_host && 0 === $arr['errors']) { throw new UnexpectedValueException(sprintf('The Intl extension is misconfigured for %s, please correct this issue before proceeding.', PHP_OS)); } return $ascii_host; } /** * Returns whether the registered name label is valid. * * DEPRECATION WARNING! This method will be removed in the next major point release * * @deprecated 1.4.0 this method is no longer used to validated the host component * @codeCoverageIgnore * * A valid registered name label MUST conform to the following ABNF * * reg-name = *( unreserved / pct-encoded / sub-delims ) * * @see https://tools.ietf.org/html/rfc3986#section-3.2.2 * * @param string $label */ protected function isHostLabel($label): bool { trigger_error( self::class.'::'.__METHOD__.' is deprecated and will be removed in the next major point release', E_USER_DEPRECATED ); return '' != $label && 63 >= strlen($label) && strlen($label) == strspn($label, self::LABEL_VALID_STARTING_CHARS.'-_~'.self::SUB_DELIMITERS); } /** * Validate an IPv6 host. * * DEPRECATION WARNING! This method will be removed in the next major point release * * @deprecated 1.4.0 this method is no longer used to validated the host component * @codeCoverageIgnore * * @see http://tools.ietf.org/html/rfc6874#section-2 * @see http://tools.ietf.org/html/rfc6874#section-4 */ protected function isIpv6Host(string $ipv6): bool { trigger_error( self::class.'::'.__METHOD__.' is deprecated and will be removed in the next major point release', E_USER_DEPRECATED ); if ('[' !== ($ipv6[0] ?? '') || ']' !== substr($ipv6, -1)) { return false; } $ipv6 = substr($ipv6, 1, -1); if (false === ($pos = strpos($ipv6, '%'))) { return (bool) filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); } $scope = rawurldecode(substr($ipv6, $pos)); if (strlen($scope) !== strcspn($scope, '?#@[]')) { return false; } $ipv6 = substr($ipv6, 0, $pos); if (!filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return false; } //Only the address block fe80::/10 can have a Zone ID attach to //let's detect the link local significant 10 bits return 0 === strpos((string) inet_pton($ipv6), "\xfe\x80"); } } <?php /** * League.Uri (http://uri.thephpleague.com/parser). * * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-parser/blob/master/LICENSE (MIT License) * @version 1.4.1 * @link https://uri.thephpleague.com/parser/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use InvalidArgumentException; /** * An exception thrown on parse attempts of invalid URIs. * * @see https://tools.ietf.org/html/rfc3986 * @package League\Uri * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 0.2.0 */ class Exception extends InvalidArgumentException { /** * Returns a new Instance from an error in URI characters. * * @return static */ public static function createFromInvalidCharacters(string $uri) { return new static(sprintf('The submitted uri `%s` contains invalid characters', $uri)); } /** * Returns a new Instance from an error in URI characters. * * @return static */ public static function createFromInvalidScheme(string $uri) { return new static(sprintf('The submitted uri `%s` contains an invalid scheme', $uri)); } /** * Returns a new Instance from an error in Host validation. * * @return static */ public static function createFromInvalidHost(string $host) { return new static(sprintf('The submitted host `%s` is invalid', $host)); } /** * Returns a new Instance from an error in port validation. * * @return static */ public static function createFromInvalidHostname(string $hostname) { return new static(sprintf('The submitted hostname `%s` is invalid', $hostname)); } /** * Returns a new Instance from an error in port validation. * * @param string|int $port * * @return static */ public static function createFromInvalidPort($port) { return new static(sprintf('The submitted port `%s` is invalid', $port)); } /** * Returns a new Instance from an error in Uri path component. * * @return static */ public static function createFromInvalidPath(string $uri) { return new static(sprintf('The submitted uri `%s` contains an invalid path', $uri)); } } <?php /** * League.Uri (http://uri.thephpleague.com/parser). * * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-parser/blob/master/LICENSE (MIT License) * @version 1.4.1 * @link https://uri.thephpleague.com/parser/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; /** * An exception thrown if the IDN support is missing or * the ICU is not at least version 4.6. * * @see https://tools.ietf.org/html/rfc3986 * @package League\Uri * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.4.0 */ class MissingIdnSupport extends Exception { } <?php /** * League.Uri (http://uri.thephpleague.com/parser). * * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-parser/blob/master/LICENSE (MIT License) * @version 1.4.1 * @link https://uri.thephpleague.com/parser/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (!function_exists('League\Uri\parse')) { require __DIR__.'/functions.php'; } { "name": "league/uri-schemes", "type": "library", "description" : "URI manipulation library", "keywords": [ "url", "uri", "rfc3986", "psr-7", "parse_url", "http", "https", "ws", "wss", "ftp", "data-uri", "file" ], "license": "MIT", "homepage": "http://uri.thephpleague.com", "authors": [ { "name" : "Ignace Nyamagana Butera", "email" : "nyamsprod@gmail.com", "homepage" : "https://nyamsprod.com" } ], "support": { "forum": "https://groups.google.com/forum/#!forum/thephpleague", "issues": "https://github.com/thephpleague/uri/issues" }, "require": { "php": ">=7.0.13", "ext-fileinfo": "*", "league/uri-interfaces": "^1.1", "league/uri-parser": "^1.4.0", "psr/http-message": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", "phpunit/phpunit" : "^6.0", "phpstan/phpstan": "^0.9.2", "phpstan/phpstan-strict-rules": "^0.9.0", "phpstan/phpstan-phpunit": "^0.9.4" }, "autoload": { "psr-4": { "League\\Uri\\": "src" }, "files": ["src/functions_include.php"] }, "autoload-dev": { "psr-4": { "LeagueTest\\Uri\\": "tests" } }, "scripts": { "phpcs": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes;", "phpstan-src": "phpstan analyse -l 7 -c phpstan.src.neon src", "phpstan-tests": "phpstan analyse -l 7 -c phpstan.tests.neon tests", "phpstan": [ "@phpstan-src", "@phpstan-tests" ], "phpunit": "phpunit --coverage-text", "test": [ "@phpunit", "@phpcs", "@phpstan" ] }, "suggest": { "ext-intl" : "Allow parsing RFC3987 compliant hosts", "league/uri-manipulations" : "Needed to easily manipulate URI objects" }, "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "config": { "sort-packages": true } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require __DIR__.'/../vendor/autoload.php'; $components = [ 'scheme' => 'https', 'host' => 'uri.thephpleague.com', 'path' => '/5.0', ]; for ($i = 0; $i < 100000; $i++) { League\Uri\Http::createFromComponents($components); } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; /** * Immutable Value object representing a Ws(s) Uri. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class Ws extends AbstractUri { /** * @inheritdoc */ protected static $supported_schemes = [ 'ws' => 80, 'wss' => 443, ]; /** * Tell whether the Ws(s) URI is in valid state according to RFC6455. * * A valid Ws(s) URI: * * <ul> * <li>can be schemeless or supports only 'ws' and 'wss' schemes * <li>can not contain a fragment component * <li>has the same validation rules as an HTTP(s) URI * </ul> * * @see https://tools.ietf.org/html/rfc6455#section-3 */ protected function isValidUri(): bool { return null === $this->fragment && '' !== $this->host && (null === $this->scheme || isset(static::$supported_schemes[$this->scheme])) && !('' != $this->scheme && null === $this->host); } /** * @inheritdoc */ protected static function filterPort($port) { if (null === $port) { return $port; } if (1 > $port || 65535 < $port) { throw UriException::createFromInvalidPort($port); } return $port; } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use League\Uri\Interfaces\Uri as DeprecatedLeagueUriInterface; use Psr\Http\Message\UriInterface as Psr7UriInterface; /** * Create a new URI optionally according to * a base URI object. * * @see Uri\Factory::__construct * @see Uri\Factory::create * * @param null|mixed $base_uri * @return Psr7UriInterface|DeprecatedLeagueUriInterface|UriInterface */ function create(string $uri, $base_uri = null) { static $factory; $factory = $factory ?? new Factory(); return $factory->create($uri, $base_uri); } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use Psr\Http\Message\UriInterface as Psr7UriInterface; use function base64_decode; use function explode; use function filter_var; use function preg_match; use function rawurlencode; use function strpos; use function strtolower; use function substr; use const FILTER_FLAG_IPV4; use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; use const FILTER_VALIDATE_IP; /** * Immutable Value object representing a HTTP(s) Uri. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class Http extends AbstractUri implements Psr7UriInterface { /** * @inheritdoc */ protected static $supported_schemes = [ 'http' => 80, 'https' => 443, ]; /** * Tell whether the Http(s) URI is in valid state. * * A valid HTTP(S) URI: * * <ul> * <li>can be schemeless or supports only 'http' and 'https' schemes * <li>Host can not be an empty string * <li>If a scheme is defined an authority must be present * </ul> * * @see https://tools.ietf.org/html/rfc6455#section-3 */ protected function isValidUri(): bool { return '' !== $this->host && (null === $this->scheme || isset(static::$supported_schemes[$this->scheme])) && !('' != $this->scheme && null === $this->host); } /** * @inheritdoc */ protected static function filterPort($port) { if (null === $port) { return $port; } if (1 > $port || 65535 < $port) { throw UriException::createFromInvalidPort($port); } return $port; } /** * Create a new instance from the environment. * * @param array $server the server and execution environment information array typically ($_SERVER) * * @return static */ public static function createFromServer(array $server): self { list($user, $pass) = static::fetchUserInfo($server); list($host, $port) = static::fetchHostname($server); list($path, $query) = static::fetchRequestUri($server); return new static(static::fetchScheme($server), $user, $pass, $host, $port, $path, $query); } /** * Returns the environment scheme. * * @param array $server the environment server typically $_SERVER */ protected static function fetchScheme(array $server): string { $server += ['HTTPS' => '']; $res = filter_var($server['HTTPS'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); return $res !== false ? 'https' : 'http'; } /** * Returns the environment user info. * * @param array $server the environment server typically $_SERVER */ protected static function fetchUserInfo(array $server): array { $server += ['PHP_AUTH_USER' => null, 'PHP_AUTH_PW' => null, 'HTTP_AUTHORIZATION' => '']; $user = $server['PHP_AUTH_USER']; $pass = $server['PHP_AUTH_PW']; if (0 === strpos(strtolower($server['HTTP_AUTHORIZATION']), 'basic')) { list($user, $pass) = explode(':', base64_decode(substr($server['HTTP_AUTHORIZATION'], 6)), 2) + [1 => null]; } if (null !== $user) { $user = rawurlencode($user); } if (null !== $pass) { $pass = rawurlencode($pass); } return [$user, $pass]; } /** * Returns the environment host. * * @param array $server the environment server typically $_SERVER * * @throws UriException If the host can not be detected */ protected static function fetchHostname(array $server): array { $server += ['SERVER_PORT' => null]; if (null !== $server['SERVER_PORT']) { $server['SERVER_PORT'] = (int) $server['SERVER_PORT']; } if (isset($server['HTTP_HOST'])) { preg_match(',^(?<host>(\[.*\]|[^:])*)(\:(?<port>[^/?\#]*))?$,x', $server['HTTP_HOST'], $matches); return [ $matches['host'], isset($matches['port']) ? (int) $matches['port'] : $server['SERVER_PORT'], ]; } if (!isset($server['SERVER_ADDR'])) { throw new UriException('Hostname could not be detected'); } if (!filter_var($server['SERVER_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $server['SERVER_ADDR'] = '['.$server['SERVER_ADDR'].']'; } return [$server['SERVER_ADDR'], $server['SERVER_PORT']]; } /** * Returns the environment path. * * @param array $server the environment server typically $_SERVER */ protected static function fetchRequestUri(array $server): array { $server += ['IIS_WasUrlRewritten' => null, 'UNENCODED_URL' => '', 'PHP_SELF' => '', 'QUERY_STRING' => null]; if ('1' === $server['IIS_WasUrlRewritten'] && '' !== $server['UNENCODED_URL']) { return explode('?', $server['UNENCODED_URL'], 2) + [1 => null]; } if (isset($server['REQUEST_URI'])) { list($path, ) = explode('?', $server['REQUEST_URI'], 2); $query = ('' !== $server['QUERY_STRING']) ? $server['QUERY_STRING'] : null; return [$path, $query]; } return [$server['PHP_SELF'], $server['QUERY_STRING']]; } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; /** * Immutable Value object representing a RFC3986 Uri. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class Uri extends AbstractUri { /** * @inheritdoc */ protected static $supported_schemes = []; /** * @inheritdoc */ protected function isValidUri(): bool { return true; } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use function array_filter; use function base64_decode; use function base64_encode; use function count; use function explode; use function file_exists; use function file_get_contents; use function is_readable; use function preg_match; use function sprintf; use function strpos; use function strtolower; use function substr; /** * Immutable Value object representing a Data Uri. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class Data extends AbstractUri { /** * @inheritdoc */ protected static $supported_schemes = [ 'data' => null, ]; /** * Tell whether the Data URI is in valid state. * * A valid Data URI: * * <ul> * <li>scheme is 'data' * <li>only contains a scheme and a path component * </ul> * * @see https://tools.ietf.org/html/rfc2397#section-3 */ protected function isValidUri(): bool { return 'data' === $this->scheme && null === $this->authority && null === $this->query && null === $this->fragment; } /** * Filter the Path component. * * @see https://tools.ietf.org/html/rfc2397 * * @throws UriException If the path is not compliant with RFC2397 */ protected function filterPath(string $path): string { if ('' === $path) { return 'text/plain;charset=us-ascii,'; } static $idn_pattern = '/[^\x20-\x7f]/'; if (preg_match($idn_pattern, $path) || false === strpos($path, ',')) { throw new UriException(sprintf('The submitted path `%s` is invalid according to RFC2937', $path)); } $parts = explode(',', $path, 2) + [1 => null]; $mediatype = explode(';', $parts[0], 2) + [1 => null]; $data = $parts[1]; $mimetype = $mediatype[0]; if (null === $mimetype || '' === $mimetype) { $mimetype = 'text/plain'; } $parameters = $mediatype[1]; if (null === $parameters || '' === $parameters) { $parameters = 'charset=us-ascii'; } $this->assertValidPath($mimetype, $parameters, $data); return $this->formatPath($mimetype.';'.$parameters.','.$data); } /** * Assert the path is a compliant with RFC2397. * * @see https://tools.ietf.org/html/rfc2397 * * @throws UriException If the mediatype or the data are not compliant * with the RFC2397 */ protected function assertValidPath(string $mimetype, string $parameters, string $data) { if (!preg_match(',^\w+/[-.\w]+(?:\+[-.\w]+)?$,', $mimetype)) { throw new UriException(sprintf('The path mimetype `%s` is invalid', $mimetype)); } $is_binary = preg_match(',(;|^)base64$,', $parameters, $matches); if ($is_binary) { $parameters = substr($parameters, 0, - strlen($matches[0])); } $res = array_filter(array_filter(explode(';', $parameters), [$this, 'validateParameter'])); if (!empty($res)) { throw new UriException(sprintf('The path paremeters `%s` contains is invalid', $parameters)); } if (!$is_binary) { return; } $res = base64_decode($data, true); if (false === $res || $data !== base64_encode($res)) { throw new UriException(sprintf('The submitted path data `%s` is invalid', $data)); } } /** * Validate mediatype parameter. */ protected function validateParameter(string $parameter): bool { $properties = explode('=', $parameter); return 2 != count($properties) || strtolower($properties[0]) === 'base64'; } /** * Create a new instance from a file path. * * @return static */ public static function createFromPath(string $path): self { if (!file_exists($path) || !is_readable($path)) { throw new UriException(sprintf('The specified file `%s` does not exist or is not readable', $path)); } $mimetype = str_replace(' ', '', (new \finfo(FILEINFO_MIME))->file($path)); return new static( 'data', null, null, null, null, $mimetype.';base64,'.base64_encode(file_get_contents($path)) ); } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; /** * Immutable Value object representing a FTP Uri. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class Ftp extends AbstractUri { /** * @inheritdoc */ protected static $supported_schemes = [ 'ftp' => 21, ]; /** * Tell whether the FTP URI is in valid state. * * A valid FTP URI: * * <ul> * <li>can be schemeless or supports only 'ftp' scheme * <li>can not contain a fragment component * <li>can not contain a query component * <li>has the same validation rules as an HTTP(s) URI * </ul> * * @see https://tools.ietf.org/html/rfc1738#section-3.2 */ protected function isValidUri(): bool { return null === $this->query && null === $this->fragment && '' !== $this->host && (null === $this->scheme || isset(static::$supported_schemes[$this->scheme])) && !('' != $this->scheme && null === $this->host); } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use BadMethodCallException; use League\Uri\Interfaces\Uri as DeprecatedLeagueUriInterface; use UnexpectedValueException; use function array_keys; use function defined; use function explode; use function filter_var; use function function_exists; use function idn_to_ascii; use function implode; use function in_array; use function inet_pton; use function preg_match; use function preg_replace_callback; use function rawurldecode; use function rawurlencode; use function sprintf; use function strpos; use function strtolower; use function substr; use const FILTER_FLAG_IPV6; use const FILTER_VALIDATE_IP; /** * common URI Object properties and methods. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ abstract class AbstractUri implements UriInterface, DeprecatedLeagueUriInterface { /** * @deprecated 1.2.0 will be removed in the next major point release * * Invalid Characters * * @see http://tools.ietf.org/html/rfc3986#section-2 * * @var string */ const INVALID_CHARS = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F"; /** * RFC3986 Sub delimiter characters regular expression pattern. * * @see http://tools.ietf.org/html/rfc3986#section-2.2 * * @var string */ const REGEXP_CHARS_SUBDELIM = "\!\$&'\(\)\*\+,;\=%"; /** * RFC3986 unreserved characters regular expression pattern. * * @see http://tools.ietf.org/html/rfc3986#section-2.3 * * @var string */ const REGEXP_CHARS_UNRESERVED = 'A-Za-z0-9_\-\.~'; /** * URI scheme component. * * @var string|null */ protected $scheme; /** * URI user info part. * * @var string|null */ protected $user_info; /** * URI host component. * * @var string|null */ protected $host; /** * URI port component. * * @var int|null */ protected $port; /** * URI authority string representation. * * @var string|null */ protected $authority; /** * URI path component. * * @var string */ protected $path = ''; /** * URI query component. * * @var string|null */ protected $query; /** * URI fragment component. * * @var string|null */ protected $fragment; /** * URI string representation. * * @var string|null */ protected $uri; /** * Supported schemes and corresponding default port. * * @var array */ protected static $supported_schemes; /** * Static method called by PHP's var export. * * @return static */ public static function __set_state(array $components): self { $components['user'] = null; $components['pass'] = null; if (null !== $components['user_info']) { list($components['user'], $components['pass']) = explode(':', $components['user_info'], 2) + [1 => null]; } return new static( $components['scheme'], $components['user'], $components['pass'], $components['host'], $components['port'], $components['path'], $components['query'], $components['fragment'] ); } /** * Create a new instance from a string. * * @return static */ public static function createFromString(string $uri = ''): self { $components = parse($uri); return new static( $components['scheme'], $components['user'], $components['pass'], $components['host'], $components['port'], $components['path'], $components['query'], $components['fragment'] ); } /** * Create a new instance from a hash of parse_url parts. * * @param array $components a hash representation of the URI similar * to PHP parse_url function result * * @return static */ public static function createFromComponents(array $components = []): self { $components += [ 'scheme' => null, 'user' => null, 'pass' => null, 'host' => null, 'port' => null, 'path' => '', 'query' => null, 'fragment' => null, ]; return new static( $components['scheme'], $components['user'], $components['pass'], $components['host'], $components['port'], $components['path'], $components['query'], $components['fragment'] ); } /** * Create a new instance. * */ protected function __construct( string $scheme = null, string $user = null, string $pass = null, string $host = null, int $port = null, string $path = '', string $query = null, string $fragment = null ) { $this->scheme = $this->formatScheme($scheme); $this->user_info = $this->formatUserInfo($user, $pass); $this->host = $this->formatHost($host); $this->port = $this->formatPort($port); $this->authority = $this->setAuthority(); $this->path = $this->filterPath($path); $this->query = $this->formatQueryAndFragment($query); $this->fragment = $this->formatQueryAndFragment($fragment); $this->assertValidState(); } /** * Format the Scheme and Host component. * * * @return string|null */ protected function formatScheme(string $scheme = null) { if ('' === $scheme || null === $scheme) { return $scheme; } $formatted_scheme = strtolower($scheme); static $pattern = '/^[a-z][a-z0-9\+\.\-]*$/'; if (preg_match($pattern, $formatted_scheme)) { return $formatted_scheme; } throw new UriException(sprintf('The submitted scheme `%s` is invalid', $scheme)); } /** * Set the UserInfo component. * * @return string|null */ protected static function formatUserInfo(string $user = null, string $password = null) { if (null === $user) { return $user; } static $user_pattern = '/(?:[^%'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.']++|%(?![A-Fa-f0-9]{2}))/'; $user = preg_replace_callback($user_pattern, [AbstractUri::class, 'urlEncodeMatch'], $user); if (null === $password) { return $user; } static $password_pattern = '/(?:[^%:'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.']++|%(?![A-Fa-f0-9]{2}))/'; return $user.':'.preg_replace_callback($password_pattern, [AbstractUri::class, 'urlEncodeMatch'], $password); } /** * Returns the RFC3986 encoded string matched. */ protected static function urlEncodeMatch(array $matches): string { return rawurlencode($matches[0]); } /** * Validate and Format the Host component. * * @param string|null $host * * @return string|null */ protected function formatHost($host) { if (null === $host || '' === $host) { return $host; } if ('[' !== $host[0]) { return $this->formatRegisteredName($host); } return $this->formatIp($host); } /** * Validate and format a registered name. * * The host is converted to its ascii representation if needed * * @throws UriException if the submitted host is not a valid registered name */ private function formatRegisteredName(string $host): string { $formatted_host = rawurldecode(strtolower($host)); static $reg_name = '/^( (?<unreserved>[a-z0-9_~\-\.])| (?<sub_delims>[!$&\'()*+,;=])| (?<encoded>%[A-F0-9]{2}) )+$/x'; if (preg_match($reg_name, $formatted_host)) { return $formatted_host; } //to test IDN host non-ascii characters must be present in the host static $idn_pattern = '/[^\x20-\x7f]/'; if (!preg_match($idn_pattern, $formatted_host)) { throw new UriException(sprintf('Host `%s` is invalid : the registered name is malformed', $host)); } static $idn_support = null; $idn_support = $idn_support ?? function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46'); if (!$idn_support) { // @codeCoverageIgnoreStart // added because it is not possible in travis to disabled the ext/intl extension // see travis issue https://github.com/travis-ci/travis-ci/issues/4701 throw new MissingIdnSupport(sprintf('the host `%s` could not be processed for IDN. Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6.', $host)); // @codeCoverageIgnoreEnd } $formatted_host = idn_to_ascii($formatted_host, 0, INTL_IDNA_VARIANT_UTS46, $arr); if (0 !== $arr['errors']) { throw new UriException(sprintf('Host `%s` is invalid : %s', $host, $this->getIdnaErrorMessage($arr['errors']))); } // @codeCoverageIgnoreStart if (false === $formatted_host) { throw new UnexpectedValueException(sprintf('The Intl extension is misconfigured for %s, please correct this issue before proceeding.', PHP_OS)); } // @codeCoverageIgnoreEnd return $formatted_host; } /** * Retrieves and format IDNA conversion error message. * * @see http://icu-project.org/apiref/icu4j/com/ibm/icu/text/IDNA.Error.html */ private function getIdnaErrorMessage(int $error_byte): string { /** * IDNA errors. */ static $idn_errors = [ IDNA_ERROR_EMPTY_LABEL => 'a non-final domain name label (or the whole domain name) is empty', IDNA_ERROR_LABEL_TOO_LONG => 'a domain name label is longer than 63 bytes', IDNA_ERROR_DOMAIN_NAME_TOO_LONG => 'a domain name is longer than 255 bytes in its storage form', IDNA_ERROR_LEADING_HYPHEN => 'a label starts with a hyphen-minus ("-")', IDNA_ERROR_TRAILING_HYPHEN => 'a label ends with a hyphen-minus ("-")', IDNA_ERROR_HYPHEN_3_4 => 'a label contains hyphen-minus ("-") in the third and fourth positions', IDNA_ERROR_LEADING_COMBINING_MARK => 'a label starts with a combining mark', IDNA_ERROR_DISALLOWED => 'a label or domain name contains disallowed characters', IDNA_ERROR_PUNYCODE => 'a label starts with "xn--" but does not contain valid Punycode', IDNA_ERROR_LABEL_HAS_DOT => 'a label contains a dot=full stop', IDNA_ERROR_INVALID_ACE_LABEL => 'An ACE label does not contain a valid label string', IDNA_ERROR_BIDI => 'a label does not meet the IDNA BiDi requirements (for right-to-left characters)', IDNA_ERROR_CONTEXTJ => 'a label does not meet the IDNA CONTEXTJ requirements', ]; $res = []; foreach ($idn_errors as $error => $reason) { if ($error_byte & $error) { $res[] = $reason; } } return empty($res) ? 'Unknown IDNA conversion error.' : implode(', ', $res).'.'; } /** * Validate and Format the IPv6/IPvfuture host. * * @throws UriException if the submitted host is not a valid IPv6 */ private function formatIp(string $host): string { $ip = substr($host, 1, -1); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return $host; } static $ip_future = '/^ v(?<version>[A-F0-9])+\. (?: (?<unreserved>[a-z0-9_~\-\.])| (?<sub_delims>[!$&\'()*+,;=:]) # also include the : character )+ $/ix'; if (preg_match($ip_future, $ip, $matches) && !in_array($matches['version'], ['4', '6'], true)) { return $host; } if (false === ($pos = strpos($ip, '%'))) { throw new UriException(sprintf('Host `%s` is invalid : the IP host is malformed', $host)); } static $gen_delims = '/[:\/?#\[\]@ ]/'; // Also includes space. if (preg_match($gen_delims, rawurldecode(substr($ip, $pos)))) { throw new UriException(sprintf('Host `%s` is invalid : the IP host is malformed', $host)); } $ip = substr($ip, 0, $pos); if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { throw new UriException(sprintf('Host `%s` is invalid : the IP host is malformed', $host)); } //Only the address block fe80::/10 can have a Zone ID attach to //let's detect the link local significant 10 bits static $address_block = "\xfe\x80"; if (substr(inet_pton($ip) & $address_block, 0, 2) === $address_block) { return $host; } throw new UriException(sprintf('Host `%s` is invalid : the IP host is malformed', $host)); } /** * Format the Port component. * * @param int|null $port * * @return int|null */ protected function formatPort($port) { $port = $this->filterPort($port); if (isset(static::$supported_schemes[$this->scheme]) && static::$supported_schemes[$this->scheme] === $port) { return null; } return $port; } /** * Filter the Port component. * * @param int|null $port * * @throws UriException if the port is invalid * * @return int|null */ protected static function filterPort($port) { if (null === $port) { return $port; } if ($port < 0) { throw UriException::createFromInvalidPort($port); } return $port; } /** * Generate the URI authority part. * * @return string|null */ protected function setAuthority() { $authority = null; if (null !== $this->user_info) { $authority = $this->user_info.'@'; } if (null !== $this->host) { $authority .= $this->host; } if (null !== $this->port) { $authority .= ':'.$this->port; } return $authority; } /** * Filter the Path component. */ protected function filterPath(string $path): string { return $this->formatPath($path); } /** * Format the Path component. */ protected function formatPath(string $path): string { static $pattern = '/(?:[^'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.'%:@\/}{]++|%(?![A-Fa-f0-9]{2}))/'; return preg_replace_callback($pattern, [AbstractUri::class, 'urlEncodeMatch'], $path); } /** * Format the Query or the Fragment component. * * Returns a array containing: * <ul> * <li> the formatted component (a string or null)</li> * <li> a boolean flag telling wether the delimiter is to be added to the component * when building the URI string representation</li> * </ul> * * @param string|null $component * * @return string|null */ protected function formatQueryAndFragment($component) { if (null === $component || '' === $component) { return $component; } static $pattern = '/(?:[^'.self::REGEXP_CHARS_UNRESERVED.self::REGEXP_CHARS_SUBDELIM.'%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/'; return preg_replace_callback($pattern, [AbstractUri::class, 'urlEncodeMatch'], $component); } /** * assert the URI internal state is valid. * * @see https://tools.ietf.org/html/rfc3986#section-3 * @see https://tools.ietf.org/html/rfc3986#section-3.3 * * @throws UriException if the URI is in an invalid state according to RFC3986 * @throws UriException if the URI is in an invalid state according to scheme specific rules */ protected function assertValidState() { $this->uri = null; if (null !== $this->authority && ('' !== $this->path && '/' !== $this->path[0])) { throw new UriException( 'Invalid URI: if an authority is present the path must be empty or start with a `/`' ); } if (null === $this->authority && 0 === strpos($this->path, '//')) { throw new UriException( 'Invalid URI: if there is no authority the path `%s` can not start with a `//`' ); } if (null === $this->authority && null === $this->scheme && false !== ($pos = strpos($this->path, ':')) && false === strpos(substr($this->path, 0, $pos), '/') ) { throw new UriException( 'Invalid URI: in absence of a scheme and an authority the first path segment cannot contain a colon (":") character.' ); } if (!$this->isValidUri()) { throw new UriException(sprintf( 'Invalid URI: The submitted uri `%s` is invalid for the following scheme(s): `%s`', $this->getUriString($this->scheme, $this->authority, $this->path, $this->query, $this->fragment), implode(', ', array_keys(static::$supported_schemes)) )); } } /** * Tell whether the current URI is in valid state. * * The URI object validity depends on the scheme. This method * MUST be implemented on every URI object */ abstract protected function isValidUri(): bool; /** * Generate the URI string representation from its components. * * @see https://tools.ietf.org/html/rfc3986#section-5.3 */ protected function getUriString( string $scheme = null, string $authority = null, string $path = '', string $query = null, string $fragment = null ): string { if (null !== $scheme) { $scheme = $scheme.':'; } if (null !== $authority) { $authority = '//'.$authority; } if (null !== $query) { $query = '?'.$query; } if (null !== $fragment) { $fragment = '#'.$fragment; } return $scheme.$authority.$path.$query.$fragment; } /** * Return the string representation as a URI reference. * * Depending on which components of the URI are present, the resulting * string is either a full URI or relative reference according to RFC 3986, * Section 4.1. The method concatenates the various components of the URI, * using the appropriate delimiters: * * - If a scheme is present, it MUST be suffixed by ":". * - If an authority is present, it MUST be prefixed by "//". * - The path can be concatenated without delimiters. * - If a query is present, it MUST be prefixed by "?". * - If a fragment is present, it MUST be prefixed by "#". * * @see http://tools.ietf.org/html/rfc3986#section-4.1 */ public function __toString() { $this->uri = $this->uri ?? $this->getUriString( $this->scheme, $this->authority, $this->path, $this->query, $this->fragment ); return $this->uri; } /** * Retrieve the scheme component of the URI. * * If no scheme is present, this method MUST return an empty string. * * The value returned MUST be normalized to lowercase, per RFC 3986 * Section 3.1. * * The trailing ":" character is not part of the scheme and MUST NOT be * added. * * @see https://tools.ietf.org/html/rfc3986#section-3.1 */ public function getScheme(): string { return (string) $this->scheme; } /** * Retrieve the authority component of the URI. * * If no authority information is present, this method MUST return an empty * string. * * The authority syntax of the URI is: * * <pre> * [user-info@]host[:port] * </pre> * * If the port component is not set or is the standard port for the current * scheme, it SHOULD NOT be included. * * @see https://tools.ietf.org/html/rfc3986#section-3.2 */ public function getAuthority(): string { return (string) $this->authority; } /** * Retrieve the user information component of the URI. * * If no user information is present, this method MUST return an empty * string. * * The userinfo syntax of the URI is: * * <pre> * username[:password] * </pre> * * If a user is present in the URI, this will return that value; * additionally, if the password is also present, it will be appended to the * user value, with a colon (":") separating the values. * * The trailing "@" character is not part of the user information and MUST * NOT be added. */ public function getUserInfo(): string { return (string) $this->user_info; } /** * Retrieve the host component of the URI. * * If no host is present, this method MUST return an empty string. * * The value returned MUST be normalized to lowercase, per RFC 3986 * Section 3.2.2. * * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 */ public function getHost(): string { return (string) $this->host; } /** * Retrieve the port component of the URI. * * If a port is present, and it is non-standard for the current scheme, * this method MUST return it as an integer. If the port is the standard port * used with the current scheme, this method SHOULD return null. * * If no port is present, and no scheme is present, this method MUST return * a null value. * * If no port is present, but a scheme is present, this method MAY return * the standard port for that scheme, but SHOULD return null. * * @return null|int */ public function getPort() { return $this->port; } /** * Retrieve the path component of the URI. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * Normally, the empty path "" and absolute path "/" are considered equal as * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically * do this normalization because in contexts with a trimmed base path, e.g. * the front controller, this difference becomes significant. It's the task * of the user to handle both "" and "/". * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.3. * * As an example, if the value should include a slash ("/") not intended as * delimiter between path segments, that value MUST be passed in encoded * form (e.g., "%2F") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.3 */ public function getPath(): string { return $this->path; } /** * Retrieve the query string of the URI. * * If no query string is present, this method MUST return an empty string. * * The leading "?" character is not part of the query and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.4. * * As an example, if a value in a key/value pair of the query string should * include an ampersand ("&") not intended as a delimiter between values, * that value MUST be passed in encoded form (e.g., "%26") to the instance. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.4 */ public function getQuery(): string { return (string) $this->query; } /** * Retrieve the fragment component of the URI. * * If no fragment is present, this method MUST return an empty string. * * The leading "#" character is not part of the fragment and MUST NOT be * added. * * The value returned MUST be percent-encoded, but MUST NOT double-encode * any characters. To determine what characters to encode, please refer to * RFC 3986, Sections 2 and 3.5. * * @see https://tools.ietf.org/html/rfc3986#section-2 * @see https://tools.ietf.org/html/rfc3986#section-3.5 */ public function getFragment(): string { return (string) $this->fragment; } /** * Return an instance with the specified scheme. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified scheme. * * An empty scheme is equivalent to removing the scheme. * * @param string $scheme The scheme to use with the new instance. * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withScheme($scheme): self { $scheme = $this->formatScheme($this->filterString($scheme)); if ('' === $scheme) { $scheme = null; } if ($scheme === $this->scheme) { return $this; } $clone = clone $this; $clone->scheme = $scheme; $clone->port = $clone->formatPort($clone->port); $clone->authority = $clone->setAuthority(); $clone->assertValidState(); return $clone; } /** * Filter a string. * * * @throws UriException if the submitted data can not be converted to string */ protected static function filterString(string $str): string { static $pattern = '/[\x00-\x1f\x7f]/'; if (!preg_match($pattern, $str)) { return $str; } throw UriException::createFromInvalidCharacters($str); } /** * Return an instance with the specified user information. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified user information. * * Password is optional, but the user information MUST include the * user; an empty string for the user is equivalent to removing user * information. * * @param string $user * @param null|string $password * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withUserInfo($user, $password = null): self { $user_info = null; if ('' !== $user) { $user_info = $this->formatUserInfo($user, $password); } if ($user_info === $this->user_info) { return $this; } $clone = clone $this; $clone->user_info = $user_info; $clone->authority = $clone->setAuthority(); $clone->assertValidState(); return $clone; } /** * Return an instance with the specified host. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified host. * * An empty host value is equivalent to removing the host. * * @param string $host * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withHost($host): self { $host = $this->formatHost($this->filterString($host)); if ('' === $host) { $host = null; } if ($host === $this->host) { return $this; } $clone = clone $this; $clone->host = $host; $clone->authority = $clone->setAuthority(); $clone->assertValidState(); return $clone; } /** * Return an instance with the specified port. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified port. * * Implementations MUST raise an exception for ports outside the * established TCP and UDP port ranges. * * A null value provided for the port is equivalent to removing the port * information. * * @param null|int $port The port to use with the new instance; a null value * removes the port information. * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withPort($port): self { $port = $this->formatPort($port); if ($port === $this->port) { return $this; } $clone = clone $this; $clone->port = $port; $clone->authority = $clone->setAuthority(); $clone->assertValidState(); return $clone; } /** * Return an instance with the specified path. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified path. * * The path can either be empty or absolute (starting with a slash) or * rootless (not starting with a slash). Implementations MUST support all * three syntaxes. * * If the path is intended to be domain-relative rather than path relative then * it must begin with a slash ("/"). Paths not starting with a slash ("/") * are assumed to be relative to some base path known to the application or * consumer. * * Users can provide both encoded and decoded path characters. * Implementations ensure the correct encoding as outlined in getPath(). * * @param string $path * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withPath($path): self { $path = $this->filterPath($this->filterString($path)); if ($path === $this->path) { return $this; } $clone = clone $this; $clone->path = $path; $clone->assertValidState(); return $clone; } /** * Return an instance with the specified query string. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified query string. * * Users can provide both encoded and decoded query characters. * Implementations ensure the correct encoding as outlined in getQuery(). * * An empty query string value is equivalent to removing the query string. * * @param string $query * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withQuery($query): self { $query = $this->formatQueryAndFragment($this->filterString($query)); if ('' === $query) { $query = null; } if ($query === $this->query) { return $this; } $clone = clone $this; $clone->query = $query; $clone->assertValidState(); return $clone; } /** * Return an instance with the specified URI fragment. * * This method MUST retain the state of the current instance, and return * an instance that contains the specified URI fragment. * * Users can provide both encoded and decoded fragment characters. * Implementations ensure the correct encoding as outlined in getFragment(). * * An empty fragment value is equivalent to removing the fragment. * * @param string $fragment * * @throws UriException for transformations that would result in * a state that cannot be represented as a * valid URI reference. * @return static */ public function withFragment($fragment): self { $fragment = $this->formatQueryAndFragment($this->filterString($fragment)); if ('' === $fragment) { $fragment = null; } if ($fragment === $this->fragment) { return $this; } $clone = clone $this; $clone->fragment = $fragment; $clone->assertValidState(); return $clone; } /** * @inheritdoc */ public function __set(string $property, $value) { throw new BadMethodCallException(sprintf('"%s" is an undefined or inaccessible property', $property)); } /** * @inheritdoc */ public function __isset(string $property) { throw new BadMethodCallException(sprintf('"%s" is an undefined or inaccessible property', $property)); } /** * @inheritdoc */ public function __unset(string $property) { throw new BadMethodCallException(sprintf('"%s" is an undefined or inaccessible property', $property)); } /** * @inheritdoc */ public function __get(string $property) { throw new BadMethodCallException(sprintf('"%s" is an undefined or inaccessible property', $property)); } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use function array_map; use function explode; use function implode; use function in_array; use function preg_match; use function strlen; use function substr; /** * Immutable Value object representing a File Uri. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class File extends AbstractUri { /** * @inheritdoc */ protected static $supported_schemes = [ 'file' => null, ]; /** * Tell whether the File URI is in valid state. * * A valid Data URI: * * <ul> * <li>can not contain a userinfo component * <li>can not contain a port component * <li>can not contain a query component * <li>can not contain a fragment component * <li>only support the 'file' scheme or no scheme * <li>if the scheme is present, the host must be defined * </ul> * * @see https://tools.ietf.org/html/rfc2397#section-3 */ protected function isValidUri(): bool { return null === $this->user_info && null === $this->port && null === $this->query && null === $this->fragment && in_array($this->scheme, [null, 'file'], true) && !('' != $this->scheme && null === $this->host); } /** * Format the Host component. * * @see https://tools.ietf.org/html/rfc1738#section-3.10 * * As a special case, <host> can be the string "localhost" or the empty * string; this is interpreted as `the machine from which the URL is * being interpreted'. * * @param string|null $host * * @return string|null */ protected function formatHost($host) { if ('' === $host) { $host = 'localhost'; } return parent::formatHost($host); } /** * Create a new instance from a Unix path string. * * @return static */ public static function createFromUnixPath(string $uri = ''): self { $uri = implode('/', array_map('rawurlencode', explode('/', $uri))); if ('/' === ($uri[0] ?? '')) { return new static('file', null, null, 'localhost', null, $uri); } return new static(null, null, null, null, null, $uri); } /** * Create a new instance from a local Windows path string. * * @return static */ public static function createFromWindowsPath(string $uri = ''): self { $root = ''; static $pattern = ',^(?<root>[a-zA-Z][:|\|]),'; if (preg_match($pattern, $uri, $matches)) { $root = substr($matches['root'], 0, -1).':'; $uri = substr($uri, strlen($root)); } $uri = implode('/', array_map('rawurlencode', explode('\\', $uri))); //Local Windows absolute path if ('' !== $root) { return new static('file', null, null, 'localhost', null, '/'.$root.$uri); } //UNC Windows Path if ('//' === substr($uri, 0, 2)) { $parts = explode('/', substr($uri, 2), 2) + [1 => null]; return new static('file', null, null, $parts[0], null, '/'.$parts[1]); } return new static(null, null, null, null, null, $uri); } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\Ws::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri as LeagueUri; use function class_alias; use function class_exists; class_alias(LeagueUri\AbstractUri::class, AbstractUri::class); if (!class_exists(AbstractUri::class)) { /** * @deprecated use instead {@link LeagueUri\AbstractUri} */ class AbstractUri { } } class_alias(LeagueUri\Data::class, Data::class); if (!class_exists(Data::class)) { /** * @deprecated use instead {@link LeagueUri\Data} */ class Data { } } class_alias(LeagueUri\File::class, File::class); if (!class_exists(File::class)) { /** * @deprecated use instead {@link LeagueUri\File} */ class File { } } class_alias(LeagueUri\Ftp::class, Ftp::class); if (!class_exists(Ftp::class)) { /** * @deprecated use instead {@link LeagueUri\Ftp} */ class Ftp { } } class_alias(LeagueUri\Http::class, Http::class); if (!class_exists(Http::class)) { /** * @deprecated use instead {@link LeagueUri\Http} */ class Http { } } class_alias(LeagueUri\Uri::class, Uri::class); if (!class_exists(Uri::class)) { /** * @deprecated use instead {@link LeagueUri\Uri} */ class Uri { } } class_alias(LeagueUri\UriException::class, UriException::class); if (!class_exists(UriException::class)) { /** * @deprecated use instead {@link LeagueUri\UriException} */ class UriException { } } class_alias(LeagueUri\Ws::class, Ws::class); if (!class_exists(Ws::class)) { /** * @deprecated use instead {@link LeagueUri\Ws} */ class Ws { } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\Http::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use function class_exists; class_exists(\League\Uri\Uri::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\Data::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\Ftp::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\AbstractUri::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\File::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace League\Uri\Schemes; use League\Uri; use function class_exists; class_exists(Uri\UriException::class); <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; /** * Base Exception class for League Uri Schemes. * * @package League\Uri * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.1.0 */ class UriException extends Exception { } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Uri; use League\Uri\Interfaces\Uri as DeprecatedLeagueUriInterface; use Psr\Http\Message\UriInterface as Psr7UriInterface; use ReflectionClass; use function array_intersect; use function array_pop; use function array_reduce; use function explode; use function get_class; use function implode; use function in_array; use function sprintf; use function strpos; use function strtolower; /** * Factory class to ease loading URI object. * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @since 1.2.0 */ class Factory { /** * Supported schemes. * * @var string[] */ protected $map = [ 'http' => Http::class, 'https' => Http::class, 'ftp' => Ftp::class, 'ws' => Ws::class, 'wss' => Ws::class, 'data' => Data::class, 'file' => File::class, ]; /** * Dot segments. * * @var array */ protected static $dot_segments = ['.' => 1, '..' => 1]; /** * supported URI interfaces. * * @var array */ protected static $uri_interfaces = [ DeprecatedLeagueUriInterface::class, UriInterface::class, Psr7UriInterface::class, ]; /** * new instance. * * @param array $map An override map of URI classes indexed by their supported schemes. */ public function __construct($map = []) { foreach ($map as $scheme => $className) { $this->addMap(strtolower($scheme), $className); } } /** * Add a new classname for a given scheme URI. * * @throws Exception if the scheme is invalid * @throws Exception if the class does not implements a supported interface */ protected function addMap(string $scheme, string $className) { if (!is_scheme($scheme)) { throw new Exception(sprintf('Please verify the submitted scheme `%s`', $scheme)); } if (empty(array_intersect((new ReflectionClass($className))->getInterfaceNames(), self::$uri_interfaces))) { throw new Exception(sprintf('Please verify the submitted class `%s`', $className)); } $this->map[$scheme] = $className; } /** * Create a new absolute URI optionally according to another absolute base URI object. * * The base URI can be * <ul> * <li>UriInterface * <li>DeprecatedLeagueUriInterface * <li>a string * </ul> * * @param mixed $base_uri an optional base uri * * @throws Exception if there's no base URI and the submitted URI is not absolute * * @return DeprecatedLeagueUriInterface|UriInterface */ public function create(string $uri, $base_uri = null) { $components = parse($uri); if (null !== $base_uri) { $base_uri = $this->filterBaseUri($base_uri); $className = $this->getClassName($components['scheme'], $base_uri); return $this->resolve($this->newInstance($components, $className), $base_uri); } if (null == $components['scheme']) { throw new Exception(sprintf('the submitted URI `%s` must be an absolute URI', $uri)); } $className = $this->getClassName($components['scheme']); $uri = $this->newInstance($components, $className); if ('' === $uri->getAuthority()) { return $uri; } $path = $uri->getPath(); //@codeCoverageIgnoreStart //because some PSR-7 Uri implementations allow this RFC3986 forbidden construction if (0 !== strpos($path, '/')) { $path = '/'.$path; } //@codeCoverageIgnoreEnd return $uri->withPath($this->removeDotSegments($path)); } /** * Returns the Base URI. * * @param DeprecatedLeagueUriInterface|UriInterface|string $uri * * @throws Exception if the Base Uri is not an absolute URI * * @return DeprecatedLeagueUriInterface|UriInterface */ protected function filterBaseUri($uri) { if (!$uri instanceof Psr7UriInterface && !$uri instanceof UriInterface) { return $this->create($uri); } if ('' !== $uri->getScheme()) { return $uri; } throw new Exception(sprintf('The submitted URI `%s` must be an absolute URI', $uri)); } /** * Returns the className to use to instantiate the URI object. * * @param string|null $scheme * @param null|mixed $base_uri */ protected function getClassName($scheme, $base_uri = null): string { $scheme = strtolower($scheme ?? ''); if (isset($base_uri) && in_array($scheme, [$base_uri->getScheme(), ''], true)) { return get_class($base_uri); } return $this->map[$scheme] ?? Uri::class; } /** * Creates a new URI object from its name using Reflection. * * @return DeprecatedLeagueUriInterface|UriInterface */ protected function newInstance(array $components, string $className) { $uri = (new ReflectionClass($className)) ->newInstanceWithoutConstructor() ->withHost($components['host'] ?? '') ->withPort($components['port'] ?? null) ->withUserInfo($components['user'] ?? '', $components['pass'] ?? null) ->withScheme($components['scheme'] ?? '') ; $path = $components['path'] ?? ''; if ('' !== $uri->getAuthority() && '' !== $path && '/' !== $path[0]) { $path = '/'.$path; } return $uri ->withPath($path) ->withQuery($components['query'] ?? '') ->withFragment($components['fragment'] ?? '') ; } /** * Resolve an URI against a base URI. * * @param DeprecatedLeagueUriInterface|UriInterface $uri * @param DeprecatedLeagueUriInterface|UriInterface $base_uri * * @return DeprecatedLeagueUriInterface|UriInterface */ protected function resolve($uri, $base_uri) { if ('' !== $uri->getScheme()) { return $uri ->withPath($this->removeDotSegments($uri->getPath())); } if ('' !== $uri->getAuthority()) { return $uri ->withScheme($base_uri->getScheme()) ->withPath($this->removeDotSegments($uri->getPath())); } list($base_uri_user, $base_uri_pass) = explode(':', $base_uri->getUserInfo(), 2) + [1 => null]; list($uri_path, $uri_query) = $this->resolvePathAndQuery($uri, $base_uri); return $uri ->withPath($this->removeDotSegments($uri_path)) ->withQuery($uri_query) ->withHost($base_uri->getHost()) ->withPort($base_uri->getPort()) ->withUserInfo($base_uri_user, $base_uri_pass) ->withScheme($base_uri->getScheme()) ; } /** * Remove dot segments from the URI path. * * @internal used internally to create an URI object */ protected function removeDotSegments(string $path): string { if (false === strpos($path, '.')) { return $path; } $old_segments = explode('/', $path); $new_path = implode('/', array_reduce($old_segments, [$this, 'reducer'], [])); if (isset(self::$dot_segments[end($old_segments)])) { $new_path .= '/'; } if (strpos($path, '/') === 0 && strpos($new_path, '/') !== 0) { return '/'.$new_path; } return $new_path; } /** * Remove dot segments. * * @return array */ protected function reducer(array $carry, string $segment) { if ('..' === $segment) { array_pop($carry); return $carry; } if (!isset(self::$dot_segments[$segment])) { $carry[] = $segment; } return $carry; } /** * Resolve an URI path and query component. * * @internal used internally to create an URI object * * @param DeprecatedLeagueUriInterface|UriInterface $uri * @param DeprecatedLeagueUriInterface|UriInterface $base_uri * * @return string[] */ protected function resolvePathAndQuery($uri, $base_uri) { $target_path = $uri->getPath(); $target_query = $uri->getQuery(); if (0 === strpos($target_path, '/')) { return [$target_path, $target_query]; } if ('' === $target_path) { if ('' === $target_query) { $target_query = $base_uri->getQuery(); } $target_path = $base_uri->getPath(); //@codeCoverageIgnoreStart //because some PSR-7 Uri implementations allow this RFC3986 forbidden construction if ('' !== $base_uri->getAuthority() && 0 !== strpos($target_path, '/')) { $target_path = '/'.$target_path; } //@codeCoverageIgnoreEnd return [$target_path, $target_query]; } $base_path = $base_uri->getPath(); if ('' !== $base_uri->getAuthority() && '' === $base_path) { $target_path = '/'.$target_path; } if ('' !== $base_path) { $segments = explode('/', $base_path); array_pop($segments); if (!empty($segments)) { $target_path = implode('/', $segments).'/'.$target_path; } } return [$target_path, $target_query]; } } <?php /** * League.Uri (http://uri.thephpleague.com). * * @package League\Uri * @subpackage League\Uri\Schemes * @author Ignace Nyamagana Butera <nyamsprod@gmail.com> * @license https://github.com/thephpleague/uri-schemes/blob/master/LICENSE (MIT License) * @version 1.2.1 * @link https://github.com/thephpleague/uri-schemes * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (!function_exists('League\Uri\create')) { require __DIR__.'/functions.php'; require __DIR__.'/Schemes/deprecated.php'; } <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Ctype; /** * Ctype implementation through regex. * * @internal * * @author Gert de Pagter <BackEndTea@gmail.com> */ final class Ctype { /** * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. * * @see https://php.net/ctype-alnum * * @param string|int $text * * @return bool */ public static function ctype_alnum($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); } /** * Returns TRUE if every character in text is a letter, FALSE otherwise. * * @see https://php.net/ctype-alpha * * @param string|int $text * * @return bool */ public static function ctype_alpha($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); } /** * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. * * @see https://php.net/ctype-cntrl * * @param string|int $text * * @return bool */ public static function ctype_cntrl($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); } /** * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. * * @see https://php.net/ctype-digit * * @param string|int $text * * @return bool */ public static function ctype_digit($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); } /** * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. * * @see https://php.net/ctype-graph * * @param string|int $text * * @return bool */ public static function ctype_graph($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); } /** * Returns TRUE if every character in text is a lowercase letter. * * @see https://php.net/ctype-lower * * @param string|int $text * * @return bool */ public static function ctype_lower($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); } /** * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. * * @see https://php.net/ctype-print * * @param string|int $text * * @return bool */ public static function ctype_print($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); } /** * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. * * @see https://php.net/ctype-punct * * @param string|int $text * * @return bool */ public static function ctype_punct($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); } /** * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. * * @see https://php.net/ctype-space * * @param string|int $text * * @return bool */ public static function ctype_space($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); } /** * Returns TRUE if every character in text is an uppercase letter. * * @see https://php.net/ctype-upper * * @param string|int $text * * @return bool */ public static function ctype_upper($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); } /** * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. * * @see https://php.net/ctype-xdigit * * @param string|int $text * * @return bool */ public static function ctype_xdigit($text) { $text = self::convert_int_to_char_for_ctype($text); return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); } /** * Converts integers to their char versions according to normal ctype behaviour, if needed. * * If an integer between -128 and 255 inclusive is provided, * it is interpreted as the ASCII value of a single character * (negative values have 256 added in order to allow characters in the Extended ASCII range). * Any other integer is interpreted as a string containing the decimal digits of the integer. * * @param string|int $int * * @return mixed */ private static function convert_int_to_char_for_ctype($int) { if (!\is_int($int)) { return $int; } if ($int < -128 || $int > 255) { return (string) $int; } if ($int < 0) { $int += 256; } return \chr($int); } } { "name": "symfony/polyfill-ctype", "type": "library", "description": "Symfony polyfill for ctype functions", "keywords": ["polyfill", "compatibility", "portable", "ctype"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=5.3.3" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, "files": [ "bootstrap.php" ] }, "suggest": { "ext-ctype": "For best performance" }, "minimum-stability": "dev", "extra": { "branch-alias": { "dev-master": "1.11-dev" } } } <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Ctype as p; if (!function_exists('ctype_alnum')) { function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); } function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } function ctype_digit($text) { return p\Ctype::ctype_digit($text); } function ctype_graph($text) { return p\Ctype::ctype_graph($text); } function ctype_lower($text) { return p\Ctype::ctype_lower($text); } function ctype_print($text) { return p\Ctype::ctype_print($text); } function ctype_punct($text) { return p\Ctype::ctype_punct($text); } function ctype_space($text) { return p\Ctype::ctype_space($text); } function ctype_upper($text) { return p\Ctype::ctype_upper($text); } function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); } } { "name": "vlucas/phpdotenv", "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", "keywords": ["env", "dotenv", "environment"], "license" : "BSD-3-Clause", "authors" : [ { "name": "Vance Lucas", "email": "vance@vancelucas.com", "homepage": "http://www.vancelucas.com" } ], "require": { "php": "^5.4 || ^7.0", "phpoption/phpoption": "^1.5", "symfony/polyfill-ctype": "^1.9" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0" }, "autoload": { "psr-4": { "Dotenv\\": "src/" } }, "extra": { "branch-alias": { "dev-master": "3.4-dev" } } } <?php namespace Dotenv\Environment\Adapter; interface AdapterInterface { /** * Determines if the adapter is supported. * * @return bool */ public function isSupported(); /** * Get an environment variable, if it exists. * * @param string $name * * @return \PhpOption\Option */ public function get($name); /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ public function set($name, $value = null); /** * Clear an environment variable. * * @param string $name * * @return void */ public function clear($name); } <?php namespace Dotenv\Environment\Adapter; use PhpOption\None; class ApacheAdapter implements AdapterInterface { /** * Determines if the adapter is supported. * * This happens if PHP is running as an Apache module. * * @return bool */ public function isSupported() { return function_exists('apache_getenv') && function_exists('apache_setenv'); } /** * Get an environment variable, if it exists. * * This is intentionally not implemented, since this adapter exists only as * a means to overwrite existing apache environment variables. * * @param string $name * * @return \PhpOption\Option */ public function get($name) { return None::create(); } /** * Set an environment variable. * * Only if an existing apache variable exists do we overwrite it. * * @param string $name * @param string|null $value * * @return void */ public function set($name, $value = null) { if (apache_getenv($name) !== false) { apache_setenv($name, (string) $value); } } /** * Clear an environment variable. * * @param string $name * * @return void */ public function clear($name) { // Nothing to do here. } } <?php namespace Dotenv\Environment\Adapter; use PhpOption\None; use PhpOption\Some; class ArrayAdapter implements AdapterInterface { /** * The variables and their values. * * @return array<string|null> */ private $variables = []; /** * Determines if the adapter is supported. * * @return bool */ public function isSupported() { return true; } /** * Get an environment variable, if it exists. * * @param string $name * * @return \PhpOption\Option */ public function get($name) { if (array_key_exists($name, $this->variables)) { return Some::create($this->variables[$name]); } return None::create(); } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ public function set($name, $value = null) { $this->variables[$name] = $value; } /** * Clear an environment variable. * * @param string $name * * @return void */ public function clear($name) { unset($this->variables[$name]); } } <?php namespace Dotenv\Environment\Adapter; use PhpOption\None; use PhpOption\Some; class EnvConstAdapter implements AdapterInterface { /** * Determines if the adapter is supported. * * @return bool */ public function isSupported() { return true; } /** * Get an environment variable, if it exists. * * @param string $name * * @return \PhpOption\Option */ public function get($name) { if (array_key_exists($name, $_ENV)) { return Some::create($_ENV[$name]); } return None::create(); } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ public function set($name, $value = null) { $_ENV[$name] = $value; } /** * Clear an environment variable. * * @param string $name * * @return void */ public function clear($name) { unset($_ENV[$name]); } } <?php namespace Dotenv\Environment\Adapter; use PhpOption\None; use PhpOption\Some; class ServerConstAdapter implements AdapterInterface { /** * Determines if the adapter is supported. * * @return bool */ public function isSupported() { return true; } /** * Get an environment variable, if it exists. * * @param string $name * * @return \PhpOption\Option */ public function get($name) { if (array_key_exists($name, $_SERVER)) { return Some::create($_SERVER[$name]); } return None::create(); } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ public function set($name, $value = null) { $_SERVER[$name] = $value; } /** * Clear an environment variable. * * @param string $name * * @return void */ public function clear($name) { unset($_SERVER[$name]); } } <?php namespace Dotenv\Environment\Adapter; use PhpOption\Option; class PutenvAdapter implements AdapterInterface { /** * Determines if the adapter is supported. * * @return bool */ public function isSupported() { return function_exists('putenv'); } /** * Get an environment variable, if it exists. * * @param string $name * * @return \PhpOption\Option */ public function get($name) { return Option::fromValue(getenv($name), false); } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ public function set($name, $value = null) { putenv("$name=$value"); } /** * Clear an environment variable. * * @param string $name * * @return void */ public function clear($name) { putenv($name); } } <?php namespace Dotenv\Environment; use Dotenv\Environment\Adapter\AdapterInterface; use Dotenv\Environment\Adapter\ApacheAdapter; use Dotenv\Environment\Adapter\EnvConstAdapter; use Dotenv\Environment\Adapter\PutenvAdapter; use Dotenv\Environment\Adapter\ServerConstAdapter; /** * The default implementation of the environment factory interface. */ class DotenvFactory implements FactoryInterface { /** * The set of adapters to use. * * @var \Dotenv\Environment\Adapter\AdapterInterface[] */ protected $adapters; /** * Create a new dotenv environment factory instance. * * If no adapters are provided, then the defaults will be used. * * @param \Dotenv\Environment\Adapter\AdapterInterface[]|null $adapters * * @return void */ public function __construct(array $adapters = null) { $this->adapters = array_filter($adapters === null ? [new ApacheAdapter(), new EnvConstAdapter(), new ServerConstAdapter(), new PutenvAdapter()] : $adapters, function (AdapterInterface $adapter) { return $adapter->isSupported(); }); } /** * Creates a new mutable environment variables instance. * * @return \Dotenv\Environment\VariablesInterface */ public function create() { return new DotenvVariables($this->adapters, false); } /** * Creates a new immutable environment variables instance. * * @return \Dotenv\Environment\VariablesInterface */ public function createImmutable() { return new DotenvVariables($this->adapters, true); } } <?php namespace Dotenv\Environment; use Dotenv\Environment\Adapter\ArrayAdapter; use InvalidArgumentException; /** * This is the abstract variables implementation. * * Extend this as required, implementing "get", "set", and "clear". */ abstract class AbstractVariables implements VariablesInterface { /** * Are we immutable? * * @var bool */ private $immutable; /** * The record of loaded variables. * * @var \Dotenv\Environment\Adapter\ArrayAdapter */ private $loaded; /** * Create a new environment variables instance. * * @param bool $immutable * * @return void */ public function __construct($immutable) { $this->immutable = $immutable; $this->loaded = new ArrayAdapter(); } /** * Get an environment variable. * * @param string $name * * @throws \InvalidArgumentException * * @return string|null */ public function get($name) { if (!is_string($name)) { throw new InvalidArgumentException('Expected name to be a string.'); } return $this->getInternal($name); } /** * Get an environment variable. * * @param string $name * * @return string|null */ protected abstract function getInternal($name); /** * Set an environment variable. * * @param string $name * @param string|null $value * * @throws \InvalidArgumentException * * @return void */ public function set($name, $value = null) { if (!is_string($name)) { throw new InvalidArgumentException('Expected name to be a string.'); } // Don't overwrite existing environment variables if we're immutable // Ruby's dotenv does this with `ENV[key] ||= value`. if ($this->isImmutable() && $this->get($name) !== null && $this->loaded->get($name)->isEmpty()) { return; } $this->setInternal($name, $value); $this->loaded->set($name, ''); } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ protected abstract function setInternal($name, $value = null); /** * Clear an environment variable. * * @param string $name * * @throws \InvalidArgumentException * * @return void */ public function clear($name) { if (!is_string($name)) { throw new InvalidArgumentException('Expected name to be a string.'); } // Don't clear anything if we're immutable. if ($this->isImmutable()) { return; } $this->clearInternal($name); } /** * Clear an environment variable. * * @param string $name * * @return void */ protected abstract function clearInternal($name); /** * Determine if the environment is immutable. * * @return bool */ public function isImmutable() { return $this->immutable; } /** * Tells whether environment variable has been defined. * * @param string $name * * @return bool */ public function has($name) { return is_string($name) && $this->get($name) !== null; } /** * {@inheritdoc} */ public function offsetExists($offset) { return $this->has($offset); } /** * {@inheritdoc} */ public function offsetGet($offset) { return $this->get($offset); } /** * {@inheritdoc} */ public function offsetSet($offset, $value) { $this->set($offset, $value); } /** * {@inheritdoc} */ public function offsetUnset($offset) { $this->clear($offset); } } <?php namespace Dotenv\Environment; /** * This environment factory interface. * * If you need custom implementations of the variables interface, implement * this interface, and use your implementation in the loader. */ interface FactoryInterface { /** * Creates a new mutable environment variables instance. * * @return \Dotenv\Environment\VariablesInterface */ public function create(); /** * Creates a new immutable environment variables instance. * * @return \Dotenv\Environment\VariablesInterface */ public function createImmutable(); } <?php namespace Dotenv\Environment; use ArrayAccess; /** * This environment variables interface. */ interface VariablesInterface extends ArrayAccess { /** * Determine if the environment is immutable. * * @return bool */ public function isImmutable(); /** * Tells whether environment variable has been defined. * * @param string $name * * @return bool */ public function has($name); /** * Get an environment variable. * * @param string $name * * @throws \InvalidArgumentException * * @return string|null */ public function get($name); /** * Set an environment variable. * * @param string $name * @param string|null $value * * @throws \InvalidArgumentException * * @return void */ public function set($name, $value = null); /** * Clear an environment variable. * * @param string $name * * @throws \InvalidArgumentException * * @return void */ public function clear($name); } <?php namespace Dotenv\Environment; /** * The default implementation of the environment variables interface. */ class DotenvVariables extends AbstractVariables { /** * The set of adapters to use. * * @var \Dotenv\Environment\Adapter\AdapterInterface[] */ protected $adapters; /** * Create a new dotenv environment variables instance. * * @param \Dotenv\Environment\Adapter\AdapterInterface[] $adapters * @param bool $immutable * * @return void */ public function __construct(array $adapters, $immutable) { $this->adapters = $adapters; parent::__construct($immutable); } /** * Get an environment variable. * * We do this by querying our adapters sequentially. * * @param string $name * * @return string|null */ protected function getInternal($name) { foreach ($this->adapters as $adapter) { $result = $adapter->get($name); if ($result->isDefined()) { return $result->get(); } } } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ protected function setInternal($name, $value = null) { foreach ($this->adapters as $adapter) { $adapter->set($name, $value); } } /** * Clear an environment variable. * * @param string $name * * @return void */ protected function clearInternal($name) { foreach ($this->adapters as $adapter) { $adapter->clear($name); } } } <?php namespace Dotenv; class Lines { /** * Process the array of lines of environment variables. * * This will produce an array of entries, one per variable. * * @param string[] $lines * * @return string[] */ public static function process(array $lines) { $output = []; $multiline = false; $multilineBuffer = []; foreach ($lines as $line) { list($multiline, $line, $multilineBuffer) = self::multilineProcess($multiline, $line, $multilineBuffer); if (!$multiline && !self::isComment($line) && self::isSetter($line)) { $output[] = $line; } } return $output; } /** * Used to make all multiline variable process. * * @param bool $multiline * @param string $line * @param string[] $buffer * * @return array */ private static function multilineProcess($multiline, $line, array $buffer) { // check if $line can be multiline variable if ($started = self::looksLikeMultilineStart($line)) { $multiline = true; } if ($multiline) { array_push($buffer, $line); if (self::looksLikeMultilineStop($line, $started)) { $multiline = false; $line = implode("\n", $buffer); $buffer = []; } } return [$multiline, $line, $buffer]; } /** * Determine if the given line can be the start of a multiline variable. * * @param string $line * * @return bool */ private static function looksLikeMultilineStart($line) { if (strpos($line, '="') === false) { return false; } return self::looksLikeMultilineStop($line, true) === false; } /** * Determine if the given line can be the start of a multiline variable. * * @param string $line * @param bool $started * * @return bool */ private static function looksLikeMultilineStop($line, $started) { if ($line === '"') { return true; } $seen = $started ? 0 : 1; foreach (self::getCharPairs(str_replace('\\\\', '', $line)) as $pair) { if ($pair[0] !== '\\' && $pair[1] === '"') { $seen++; } } return $seen > 1; } /** * Get all pairs of adjacent characters within the line. * * @param string $line * * @return bool */ private static function getCharPairs($line) { $chars = str_split($line); return array_map(null, $chars, array_slice($chars, 1)); } /** * Determine if the line in the file is a comment, e.g. begins with a #. * * @param string $line * * @return bool */ private static function isComment($line) { $line = ltrim($line); return isset($line[0]) && $line[0] === '#'; } /** * Determine if the given line looks like it's setting a variable. * * @param string $line * * @return bool */ private static function isSetter($line) { return strpos($line, '=') !== false; } } <?php namespace Dotenv; use Dotenv\Exception\InvalidFileException; class Parser { const INITIAL_STATE = 0; const UNQUOTED_STATE = 1; const QUOTED_STATE = 2; const ESCAPE_STATE = 3; const WHITESPACE_STATE = 4; const COMMENT_STATE = 5; /** * Parse the given environment variable entry into a name and value. * * @param string $entry * * @throws \Dotenv\Exception\InvalidFileException * * @return array */ public static function parse($entry) { list($name, $value) = self::splitStringIntoParts($entry); return [self::parseName($name), self::parseValue($value)]; } /** * Split the compound string into parts. * * @param string $line * * @throws \Dotenv\Exception\InvalidFileException * * @return array */ private static function splitStringIntoParts($line) { $name = $line; $value = null; if (strpos($line, '=') !== false) { list($name, $value) = array_map('trim', explode('=', $line, 2)); } if ($name === '') { throw new InvalidFileException( self::getErrorMessage('an unexpected equals', $line) ); } return [$name, $value]; } /** * Strips quotes and the optional leading "export " from the variable name. * * @param string $name * * @throws \Dotenv\Exception\InvalidFileException * * @return string */ private static function parseName($name) { $name = trim(str_replace(['export ', '\'', '"'], '', $name)); if (!self::isValidName($name)) { throw new InvalidFileException( self::getErrorMessage('an invalid name', $name) ); } return $name; } /** * Is the given variable name valid? * * @param string $name * * @return bool */ private static function isValidName($name) { return preg_match('~\A[a-zA-Z0-9_.]+\z~', $name) === 1; } /** * Strips quotes and comments from the environment variable value. * * @param string|null $value * * @throws \Dotenv\Exception\InvalidFileException * * @return string|null */ private static function parseValue($value) { if ($value === null || trim($value) === '') { return $value; } return array_reduce(str_split($value), function ($data, $char) use ($value) { switch ($data[1]) { case self::INITIAL_STATE: if ($char === '"' || $char === '\'') { return [$data[0], self::QUOTED_STATE]; } elseif ($char === '#') { return [$data[0], self::COMMENT_STATE]; } else { return [$data[0].$char, self::UNQUOTED_STATE]; } case self::UNQUOTED_STATE: if ($char === '#') { return [$data[0], self::COMMENT_STATE]; } elseif (ctype_space($char)) { return [$data[0], self::WHITESPACE_STATE]; } else { return [$data[0].$char, self::UNQUOTED_STATE]; } case self::QUOTED_STATE: if ($char === $value[0]) { return [$data[0], self::WHITESPACE_STATE]; } elseif ($char === '\\') { return [$data[0], self::ESCAPE_STATE]; } else { return [$data[0].$char, self::QUOTED_STATE]; } case self::ESCAPE_STATE: if ($char === $value[0] || $char === '\\') { return [$data[0].$char, self::QUOTED_STATE]; } else { throw new InvalidFileException( self::getErrorMessage('an unexpected escape sequence', $value) ); } case self::WHITESPACE_STATE: if ($char === '#') { return [$data[0], self::COMMENT_STATE]; } elseif (!ctype_space($char)) { throw new InvalidFileException( self::getErrorMessage('unexpected whitespace', $value) ); } else { return [$data[0], self::WHITESPACE_STATE]; } case self::COMMENT_STATE: return [$data[0], self::COMMENT_STATE]; } }, ['', self::INITIAL_STATE])[0]; } /** * Generate a friendly error message. * * @param string $cause * @param string $subject * * @return string */ private static function getErrorMessage($cause, $subject) { return sprintf( 'Failed to parse dotenv file due to %s. Failed at [%s].', $cause, strtok($subject, "\n") ); } } <?php namespace Dotenv; use Dotenv\Exception\ValidationException; /** * This is the validator class. * * It's responsible for applying validations against a number of variables. */ class Validator { /** * The variables to validate. * * @var string[] */ protected $variables; /** * The loader instance. * * @var \Dotenv\Loader */ protected $loader; /** * Create a new validator instance. * * @param string[] $variables * @param \Dotenv\Loader $loader * * @throws \Dotenv\Exception\ValidationException * * @return void */ public function __construct(array $variables, Loader $loader) { $this->variables = $variables; $this->loader = $loader; $this->assertCallback( function ($value) { return $value !== null; }, 'is missing' ); } /** * Assert that each variable is not empty. * * @throws \Dotenv\Exception\ValidationException * * @return \Dotenv\Validator */ public function notEmpty() { return $this->assertCallback( function ($value) { return strlen(trim($value)) > 0; }, 'is empty' ); } /** * Assert that each specified variable is an integer. * * @throws \Dotenv\Exception\ValidationException * * @return \Dotenv\Validator */ public function isInteger() { return $this->assertCallback( function ($value) { return ctype_digit($value); }, 'is not an integer' ); } /** * Assert that each specified variable is a boolean. * * @throws \Dotenv\Exception\ValidationException * * @return \Dotenv\Validator */ public function isBoolean() { return $this->assertCallback( function ($value) { if ($value === '') { return false; } return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null; }, 'is not a boolean' ); } /** * Assert that each variable is amongst the given choices. * * @param string[] $choices * * @throws \Dotenv\Exception\ValidationException * * @return \Dotenv\Validator */ public function allowedValues(array $choices) { return $this->assertCallback( function ($value) use ($choices) { return in_array($value, $choices, true); }, sprintf('is not one of [%s]', implode(', ', $choices)) ); } /** * Assert that the callback returns true for each variable. * * @param callable $callback * @param string $message * * @throws \Dotenv\Exception\ValidationException * * @return \Dotenv\Validator */ protected function assertCallback(callable $callback, $message = 'failed callback assertion') { $failing = []; foreach ($this->variables as $variable) { if ($callback($this->loader->getEnvironmentVariable($variable)) === false) { $failing[] = sprintf('%s %s', $variable, $message); } } if (count($failing) > 0) { throw new ValidationException(sprintf( 'One or more environment variables failed assertions: %s.', implode(', ', $failing) )); } return $this; } } <?php namespace Dotenv\Regex; use PhpOption\None; use PhpOption\Some; class Error extends Result { /** * @var string */ private $value; /** * Internal constructor for an error value. * * @param string $value * * @return void */ private function __construct($value) { $this->value = $value; } /** * Create a new error value. * * @param string $value * * @return \Dotenv\Regex\Result */ public static function create($value) { return new self($value); } /** * Get the success option value. * * @return \PhpOption\Option */ public function success() { return None::create(); } /** * Map over the success value. * * @param callable $f * * @return \Dotenv\Regex\Result */ public function mapSuccess(callable $f) { return self::create($this->value); } /** * Get the error option value. * * @return \PhpOption\Option */ public function error() { return Some::create($this->value); } /** * Map over the error value. * * @param callable $f * * @return \Dotenv\Regex\Result */ public function mapError(callable $f) { return self::create($f($this->value)); } } <?php namespace Dotenv\Regex; use PhpOption\None; use PhpOption\Some; class Success extends Result { /** * @var string */ private $value; /** * Internal constructor for a success value. * * @param string $value * * @return void */ private function __construct($value) { $this->value = $value; } /** * Create a new success value. * * @param string $value * * @return \Dotenv\Regex\Result */ public static function create($value) { return new self($value); } /** * Get the success option value. * * @return \PhpOption\Option */ public function success() { return Some::create($this->value); } /** * Map over the success value. * * @param callable $f * * @return \Dotenv\Regex\Result */ public function mapSuccess(callable $f) { return self::create($f($this->value)); } /** * Get the error option value. * * @return \PhpOption\Option */ public function error() { return None::create(); } /** * Map over the error value. * * @param callable $f * * @return \Dotenv\Regex\Result */ public function mapError(callable $f) { return self::create($this->value); } } <?php namespace Dotenv\Regex; abstract class Result { /** * Get the success option value. * * @return \PhpOption\Option */ abstract public function success(); /** * Get the error value, if possible. * * @return string */ public function getSuccess() { return $this->success()->get(); } /** * Map over the success value. * * @param callable $f * * @return \Dotenv\Regex\Result */ abstract public function mapSuccess(callable $f); /** * Get the error option value. * * @return \PhpOption\Option */ abstract public function error(); /** * Get the error value, if possible. * * @return string */ public function getError() { return $this->error()->get(); } /** * Map over the error value. * * @param callable $f * * @return \Dotenv\Regex\Result */ abstract public function mapError(callable $f); } <?php namespace Dotenv\Regex; use PhpOption\Option; class Regex { /** * Perform a preg replace, wrapping up the result. * * @param string $pattern * @param string $replacement * @param string $subject * * @return \Dotenv\Regex\Result */ public static function replace($pattern, $replacement, $subject) { return self::pregAndWrap(function ($subject) use ($pattern, $replacement) { return preg_replace($pattern, $replacement, $subject); }, $subject); } /** * Perform a preg replace callback, wrapping up the result. * * @param string $pattern * @param callable $callback * @param string $subject * * @return \Dotenv\Regex\Result */ public static function replaceCallback($pattern, callable $callback, $subject) { return self::pregAndWrap(function ($subject) use ($pattern, $callback) { return preg_replace_callback($pattern, $callback, $subject); }, $subject); } /** * Perform a preg operation, wrapping up the result. * * @param callable $operation * @param string $subject * * @return \Dotenv\Regex\Result */ private static function pregAndWrap(callable $operation, $subject) { $result = (string) @$operation($subject); if (($e = preg_last_error()) !== PREG_NO_ERROR) { return Error::create(self::lookupError($e)); } return Success::create($result); } /** * Lookup the preg error code. * * @param int $code * * @return string */ private static function lookupError($code) { return Option::fromValue(get_defined_constants(true)) ->filter(function (array $consts) { return isset($consts['pcre']) && defined('ARRAY_FILTER_USE_KEY'); }) ->map(function (array $consts) { return array_filter($consts['pcre'], function ($msg) { return substr($msg, -6) === '_ERROR'; }, ARRAY_FILTER_USE_KEY); }) ->flatMap(function (array $errors) use ($code) { return Option::fromValue( array_search($code, $errors, true) ); }) ->getOrElse('PREG_ERROR'); } } <?php namespace Dotenv; use Dotenv\Environment\FactoryInterface; use Dotenv\Exception\InvalidPathException; use Dotenv\Regex\Regex; use PhpOption\Option; /** * This is the loader class. * * It's responsible for loading variables by reading a file from disk and: * - stripping comments beginning with a `#`, * - parsing lines that look shell variable setters, e.g `export key = value`, `key="value"`. * - multiline variable look always start with a " and end with it, e.g: `key="value * value"` */ class Loader { /** * The file paths. * * @var string[] */ protected $filePaths; /** * The environment factory instance. * * @var \Dotenv\Environment\FactoryInterface */ protected $envFactory; /** * The environment variables instance. * * @var \Dotenv\Environment\VariablesInterface */ protected $envVariables; /** * The list of environment variables declared inside the 'env' file. * * @var string[] */ protected $variableNames = []; /** * Create a new loader instance. * * @param string[] $filePaths * @param \Dotenv\Environment\FactoryInterface $envFactory * @param bool $immutable * * @return void */ public function __construct(array $filePaths, FactoryInterface $envFactory, $immutable = false) { $this->filePaths = $filePaths; $this->envFactory = $envFactory; $this->setImmutable($immutable); } /** * Set immutable value. * * @param bool $immutable * * @return $this */ public function setImmutable($immutable = false) { $this->envVariables = $immutable ? $this->envFactory->createImmutable() : $this->envFactory->create(); return $this; } /** * Load the environment file from disk. * * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException * * @return array<string|null> */ public function load() { return $this->loadDirect( self::findAndRead($this->filePaths) ); } /** * Directly load the given string. * * @param string $content * * @throws \Dotenv\Exception\InvalidFileException * * @return array<string|null> */ public function loadDirect($content) { return $this->processEntries( Lines::process(preg_split("/(\r\n|\n|\r)/", $content)) ); } /** * Attempt to read the files in order. * * @param string[] $filePaths * * @throws \Dotenv\Exception\InvalidPathException * * @return string[] */ private static function findAndRead(array $filePaths) { if ($filePaths === []) { throw new InvalidPathException('At least one environment file path must be provided.'); } foreach ($filePaths as $filePath) { $lines = self::readFromFile($filePath); if ($lines->isDefined()) { return $lines->get(); } } throw new InvalidPathException( sprintf('Unable to read any of the environment file(s) at [%s].', implode(', ', $filePaths)) ); } /** * Read the given file. * * @param string $filePath * * @return \PhpOption\Option */ private static function readFromFile($filePath) { $content = @file_get_contents($filePath); return Option::fromValue($content, false); } /** * Process the environment variable entries. * * We'll fill out any nested variables, and acually set the variable using * the underlying environment variables instance. * * @param string[] $entries * * @throws \Dotenv\Exception\InvalidFileException * * @return array<string|null> */ private function processEntries(array $entries) { $vars = []; foreach ($entries as $entry) { list($name, $value) = Parser::parse($entry); $vars[$name] = $this->resolveNestedVariables($value); $this->setEnvironmentVariable($name, $vars[$name]); } return $vars; } /** * Resolve the nested variables. * * Look for ${varname} patterns in the variable value and replace with an * existing environment variable. * * @param string|null $value * * @return string|null */ private function resolveNestedVariables($value = null) { return Option::fromValue($value) ->filter(function ($str) { return strpos($str, '$') !== false; }) ->flatMap(function ($str) { return Regex::replaceCallback( '/\${([a-zA-Z0-9_.]+)}/', function (array $matches) { return Option::fromValue($this->getEnvironmentVariable($matches[1])) ->getOrElse($matches[0]); }, $str )->success(); }) ->getOrElse($value); } /** * Search the different places for environment variables and return first value found. * * @param string $name * * @return string|null */ public function getEnvironmentVariable($name) { return $this->envVariables->get($name); } /** * Set an environment variable. * * @param string $name * @param string|null $value * * @return void */ public function setEnvironmentVariable($name, $value = null) { $this->variableNames[] = $name; $this->envVariables->set($name, $value); } /** * Clear an environment variable. * * This method only expects names in normal form. * * @param string $name * * @return void */ public function clearEnvironmentVariable($name) { $this->envVariables->clear($name); } /** * Get the list of environment variables names. * * @return string[] */ public function getEnvironmentVariableNames() { return $this->variableNames; } } <?php namespace Dotenv; use Dotenv\Environment\DotenvFactory; use Dotenv\Environment\FactoryInterface; use Dotenv\Exception\InvalidPathException; /** * This is the dotenv class. * * It's responsible for loading a `.env` file in the given directory and * setting the environment variables. */ class Dotenv { /** * The loader instance. * * @var \Dotenv\Loader */ protected $loader; /** * Create a new dotenv instance. * * @param \Dotenv\Loader $loader * * @return void */ public function __construct(Loader $loader) { $this->loader = $loader; } /** * Create a new dotenv instance. * * @param string|string[] $paths * @param string|null $file * @param \Dotenv\Environment\FactoryInterface|null $envFactory * * @return \Dotenv\Dotenv */ public static function create($paths, $file = null, FactoryInterface $envFactory = null) { $loader = new Loader( self::getFilePaths((array) $paths, $file ?: '.env'), $envFactory ?: new DotenvFactory(), true ); return new self($loader); } /** * Returns the full paths to the files. * * @param string[] $paths * @param string $file * * @return string[] */ private static function getFilePaths(array $paths, $file) { return array_map(function ($path) use ($file) { return rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file; }, $paths); } /** * Load environment file in given directory. * * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException * * @return array<string|null> */ public function load() { return $this->loadData(); } /** * Load environment file in given directory, silently failing if it doesn't exist. * * @throws \Dotenv\Exception\InvalidFileException * * @return array<string|null> */ public function safeLoad() { try { return $this->loadData(); } catch (InvalidPathException $e) { // suppressing exception return []; } } /** * Load environment file in given directory. * * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException * * @return array<string|null> */ public function overload() { return $this->loadData(true); } /** * Actually load the data. * * @param bool $overload * * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException * * @return array<string|null> */ protected function loadData($overload = false) { return $this->loader->setImmutable(!$overload)->load(); } /** * Required ensures that the specified variables exist, and returns a new validator object. * * @param string|string[] $variables * * @return \Dotenv\Validator */ public function required($variables) { return new Validator((array) $variables, $this->loader); } /** * Get the list of environment variables declared inside the 'env' file. * * @return string[] */ public function getEnvironmentVariableNames() { return $this->loader->getEnvironmentVariableNames(); } } <?php namespace Dotenv\Exception; /** * This is the exception interface. */ interface ExceptionInterface { // } <?php namespace Dotenv\Exception; use InvalidArgumentException; /** * This is the invalid file exception class. */ class InvalidFileException extends InvalidArgumentException implements ExceptionInterface { // } <?php namespace Dotenv\Exception; use InvalidArgumentException; /** * This is the invalid path exception class. */ class InvalidPathException extends InvalidArgumentException implements ExceptionInterface { // } <?php namespace Dotenv\Exception; use RuntimeException; /** * This is the validation exception class. */ class ValidationException extends RuntimeException implements ExceptionInterface { // } { "name": "phpoption/phpoption", "description": "Option Type for PHP", "keywords": ["php","option","language","type"], "type": "library", "license": "Apache2", "authors": [ { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" } ], "require": { "php": ">=5.3.0" }, "require-dev": { "phpunit/phpunit": "4.7.*" }, "autoload": { "psr-0": { "PhpOption\\": "src/" } }, "extra": { "branch-alias": { "dev-master": "1.3-dev" } } } <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpOption; final class LazyOption extends Option { /** @var callable */ private $callback; /** @var array */ private $arguments; /** @var Option|null */ private $option; /** * Helper Constructor. * * @param callable $callback * @param array $arguments * * @return LazyOption */ public static function create($callback, array $arguments = array()) { return new self($callback, $arguments); } /** * Constructor. * * @param callable $callback * @param array $arguments */ public function __construct($callback, array $arguments = array()) { if (!is_callable($callback)) { throw new \InvalidArgumentException('Invalid callback given'); } $this->callback = $callback; $this->arguments = $arguments; } public function isDefined() { return $this->option()->isDefined(); } public function isEmpty() { return $this->option()->isEmpty(); } public function get() { return $this->option()->get(); } public function getOrElse($default) { return $this->option()->getOrElse($default); } public function getOrCall($callable) { return $this->option()->getOrCall($callable); } public function getOrThrow(\Exception $ex) { return $this->option()->getOrThrow($ex); } public function orElse(Option $else) { return $this->option()->orElse($else); } /** * @deprecated Use forAll() instead. */ public function ifDefined($callable) { $this->option()->ifDefined($callable); } public function forAll($callable) { return $this->option()->forAll($callable); } public function map($callable) { return $this->option()->map($callable); } public function flatMap($callable) { return $this->option()->flatMap($callable); } public function filter($callable) { return $this->option()->filter($callable); } public function filterNot($callable) { return $this->option()->filterNot($callable); } public function select($value) { return $this->option()->select($value); } public function reject($value) { return $this->option()->reject($value); } public function getIterator() { return $this->option()->getIterator(); } public function foldLeft($initialValue, $callable) { return $this->option()->foldLeft($initialValue, $callable); } public function foldRight($initialValue, $callable) { return $this->option()->foldRight($initialValue, $callable); } /** * @return Option */ private function option() { if (null === $this->option) { $this->option = call_user_func_array($this->callback, $this->arguments); if (!$this->option instanceof Option) { $this->option = null; throw new \RuntimeException('Expected instance of \PhpOption\Option'); } } return $this->option; } } <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpOption; use IteratorAggregate; /** * Base Option Class. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ abstract class Option implements IteratorAggregate { /** * Creates an option given a return value. * * This is intended for consuming existing APIs and allows you to easily * convert them to an option. By default, we treat ``null`` as the None case, * and everything else as Some. * * @param mixed $value The actual return value. * @param mixed $noneValue The value which should be considered "None"; null * by default. * * @return Option */ public static function fromValue($value, $noneValue = null) { if ($value === $noneValue) { return None::create(); } return new Some($value); } /** * Creates an option from an array's value. * * If the key does not exist in the array, the array is not actually an array, or the * array's value at the given key is null, None is returned. * * Otherwise, Some is returned wrapping the value at the given key. * * @param mixed $array a potential array value * @param string $key the key to check * * @return Option */ public static function fromArraysValue($array, $key) { if ( ! isset($array[$key])) { return None::create(); } return new Some($array[$key]); } /** * Creates a lazy-option with the given callback. * * This is also a helper constructor for lazy-consuming existing APIs where * the return value is not yet an option. By default, we treat ``null`` as * None case, and everything else as Some. * * @param callable $callback The callback to evaluate. * @param array $arguments * @param mixed $noneValue The value which should be considered "None"; null * by default. * * @return Option */ public static function fromReturn($callback, array $arguments = array(), $noneValue = null) { return new LazyOption(function() use ($callback, $arguments, $noneValue) { $return = call_user_func_array($callback, $arguments); if ($return === $noneValue) { return None::create(); } return new Some($return); }); } /** * Option factory, which creates new option based on passed value. * If value is already an option, it simply returns * If value is a \Closure, LazyOption with passed callback created and returned. If Option returned from callback, * it returns directly (flatMap-like behaviour) * On other case value passed to Option::fromValue() method * * @param Option|\Closure|mixed $value * @param null $noneValue used when $value is mixed or Closure, for None-check * * @return Option */ public static function ensure($value, $noneValue = null) { if ($value instanceof Option) { return $value; } elseif ($value instanceof \Closure) { return new LazyOption(function() use ($value, $noneValue) { $return = $value(); if ($return instanceof Option) { return $return; } else { return Option::fromValue($return, $noneValue); } }); } else { return Option::fromValue($value, $noneValue); } } /** * Returns the value if available, or throws an exception otherwise. * * @throws \RuntimeException if value is not available * * @return mixed */ abstract public function get(); /** * Returns the value if available, or the default value if not. * * @param mixed $default * * @return mixed */ abstract public function getOrElse($default); /** * Returns the value if available, or the results of the callable. * * This is preferable over ``getOrElse`` if the computation of the default * value is expensive. * * @param callable $callable * * @return mixed */ abstract public function getOrCall($callable); /** * Returns the value if available, or throws the passed exception. * * @param \Exception $ex * * @return mixed */ abstract public function getOrThrow(\Exception $ex); /** * Returns true if no value is available, false otherwise. * * @return boolean */ abstract public function isEmpty(); /** * Returns true if a value is available, false otherwise. * * @return boolean */ abstract public function isDefined(); /** * Returns this option if non-empty, or the passed option otherwise. * * This can be used to try multiple alternatives, and is especially useful * with lazy evaluating options: * * ```php * $repo->findSomething() * ->orElse(new LazyOption(array($repo, 'findSomethingElse'))) * ->orElse(new LazyOption(array($repo, 'createSomething'))); * ``` * * @param Option $else * * @return Option */ abstract public function orElse(Option $else); /** * This is similar to map() below except that the return value has no meaning; * the passed callable is simply executed if the option is non-empty, and * ignored if the option is empty. * * In all cases, the return value of the callable is discarded. * * ```php * $comment->getMaybeFile()->ifDefined(function($file) { * // Do something with $file here. * }); * ``` * * If you're looking for something like ``ifEmpty``, you can use ``getOrCall`` * and ``getOrElse`` in these cases. * * @deprecated Use forAll() instead. * * @param callable $callable * * @return void */ abstract public function ifDefined($callable); /** * This is similar to map() except that the return value of the callable has no meaning. * * The passed callable is simply executed if the option is non-empty, and ignored if the * option is empty. This method is preferred for callables with side-effects, while map() * is intended for callables without side-effects. * * @param callable $callable * * @return Option */ abstract public function forAll($callable); /** * Applies the callable to the value of the option if it is non-empty, * and returns the return value of the callable wrapped in Some(). * * If the option is empty, then the callable is not applied. * * ```php * (new Some("foo"))->map('strtoupper')->get(); // "FOO" * ``` * * @param callable $callable * * @return Option */ abstract public function map($callable); /** * Applies the callable to the value of the option if it is non-empty, and * returns the return value of the callable directly. * * In contrast to ``map``, the return value of the callable is expected to * be an Option itself; it is not automatically wrapped in Some(). * * @param callable $callable must return an Option * * @return Option */ abstract public function flatMap($callable); /** * If the option is empty, it is returned immediately without applying the callable. * * If the option is non-empty, the callable is applied, and if it returns true, * the option itself is returned; otherwise, None is returned. * * @param callable $callable * * @return Option */ abstract public function filter($callable); /** * If the option is empty, it is returned immediately without applying the callable. * * If the option is non-empty, the callable is applied, and if it returns false, * the option itself is returned; otherwise, None is returned. * * @param callable $callable * * @return Option */ abstract public function filterNot($callable); /** * If the option is empty, it is returned immediately. * * If the option is non-empty, and its value does not equal the passed value * (via a shallow comparison ===), then None is returned. Otherwise, the * Option is returned. * * In other words, this will filter all but the passed value. * * @param mixed $value * * @return Option */ abstract public function select($value); /** * If the option is empty, it is returned immediately. * * If the option is non-empty, and its value does equal the passed value (via * a shallow comparison ===), then None is returned; otherwise, the Option is * returned. * * In other words, this will let all values through except the passed value. * * @param mixed $value * * @return Option */ abstract public function reject($value); /** * Binary operator for the initial value and the option's value. * * If empty, the initial value is returned. * If non-empty, the callable receives the initial value and the option's value as arguments * * ```php * * $some = new Some(5); * $none = None::create(); * $result = $some->foldLeft(1, function($a, $b) { return $a + $b; }); // int(6) * $result = $none->foldLeft(1, function($a, $b) { return $a + $b; }); // int(1) * * // This can be used instead of something like the following: * $option = Option::fromValue($integerOrNull); * $result = 1; * if ( ! $option->isEmpty()) { * $result += $option->get(); * } * ``` * * @param mixed $initialValue * @param callable $callable function(initialValue, callable): result * * @return mixed */ abstract public function foldLeft($initialValue, $callable); /** * foldLeft() but with reversed arguments for the callable. * * @param mixed $initialValue * @param callable $callable function(callable, initialValue): result * * @return mixed */ abstract public function foldRight($initialValue, $callable); } <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpOption; use ArrayIterator; final class Some extends Option { private $value; public function __construct($value) { $this->value = $value; } public static function create($value) { return new self($value); } public function isDefined() { return true; } public function isEmpty() { return false; } public function get() { return $this->value; } public function getOrElse($default) { return $this->value; } public function getOrCall($callable) { return $this->value; } public function getOrThrow(\Exception $ex) { return $this->value; } public function orElse(Option $else) { return $this; } /** * @deprecated Use forAll() instead. */ public function ifDefined($callable) { call_user_func($callable, $this->value); } public function forAll($callable) { call_user_func($callable, $this->value); return $this; } public function map($callable) { return new self(call_user_func($callable, $this->value)); } public function flatMap($callable) { $rs = call_user_func($callable, $this->value); if ( ! $rs instanceof Option) { throw new \RuntimeException('Callables passed to flatMap() must return an Option. Maybe you should use map() instead?'); } return $rs; } public function filter($callable) { if (true === call_user_func($callable, $this->value)) { return $this; } return None::create(); } public function filterNot($callable) { if (false === call_user_func($callable, $this->value)) { return $this; } return None::create(); } public function select($value) { if ($this->value === $value) { return $this; } return None::create(); } public function reject($value) { if ($this->value === $value) { return None::create(); } return $this; } public function getIterator() { return new ArrayIterator(array($this->value)); } public function foldLeft($initialValue, $callable) { return call_user_func($callable, $initialValue, $this->value); } public function foldRight($initialValue, $callable) { return call_user_func($callable, $this->value, $initialValue); } } <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace PhpOption; use EmptyIterator; final class None extends Option { private static $instance; public static function create() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } public function get() { throw new \RuntimeException('None has no value.'); } public function getOrCall($callable) { return call_user_func($callable); } public function getOrElse($default) { return $default; } public function getOrThrow(\Exception $ex) { throw $ex; } public function isEmpty() { return true; } public function isDefined() { return false; } public function orElse(Option $else) { return $else; } /** * @deprecated Use forAll() instead. */ public function ifDefined($callable) { // Just do nothing in that case. } public function forAll($callable) { return $this; } public function map($callable) { return $this; } public function flatMap($callable) { return $this; } public function filter($callable) { return $this; } public function filterNot($callable) { return $this; } public function select($value) { return $this; } public function reject($value) { return $this; } public function getIterator() { return new EmptyIterator(); } public function foldLeft($initialValue, $callable) { return $initialValue; } public function foldRight($initialValue, $callable) { return $initialValue; } private function __construct() { } } { "name": "paragonie/random_compat", "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ "csprng", "random", "polyfill", "pseudorandom" ], "license": "MIT", "type": "library", "authors": [ { "name": "Paragon Initiative Enterprises", "email": "security@paragonie.com", "homepage": "https://paragonie.com" } ], "support": { "issues": "https://github.com/paragonie/random_compat/issues", "email": "info@paragonie.com", "source": "https://github.com/paragonie/random_compat" }, "require": { "php": ">=5.2.0" }, "require-dev": { "phpunit/phpunit": "4.*|5.*" }, "suggest": { "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." }, "autoload": { "files": [ "lib/random.php" ] } } <?php if (!is_callable('random_int')) { /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Fetch a random integer between $min and $max inclusive * * @param int $min * @param int $max * * @throws Exception * * @return int */ function random_int($min, $max) { /** * Type and input logic checks * * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX) * (non-inclusive), it will sanely cast it to an int. If you it's equal to * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats * lose precision, so the <= and => operators might accidentally let a float * through. */ try { /** @var int $min */ $min = RandomCompat_intval($min); } catch (TypeError $ex) { throw new TypeError( 'random_int(): $min must be an integer' ); } try { /** @var int $max */ $max = RandomCompat_intval($max); } catch (TypeError $ex) { throw new TypeError( 'random_int(): $max must be an integer' ); } /** * Now that we've verified our weak typing system has given us an integer, * let's validate the logic then we can move forward with generating random * integers along a given range. */ if ($min > $max) { throw new Error( 'Minimum value must be less than or equal to the maximum value' ); } if ($max === $min) { return (int) $min; } /** * Initialize variables to 0 * * We want to store: * $bytes => the number of random bytes we need * $mask => an integer bitmask (for use with the &) operator * so we can minimize the number of discards */ $attempts = $bits = $bytes = $mask = $valueShift = 0; /** @var int $attempts */ /** @var int $bits */ /** @var int $bytes */ /** @var int $mask */ /** @var int $valueShift */ /** * At this point, $range is a positive number greater than 0. It might * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to * a float and we will lose some precision. * * @var int|float $range */ $range = $max - $min; /** * Test for integer overflow: */ if (!is_int($range)) { /** * Still safely calculate wider ranges. * Provided by @CodesInChaos, @oittaa * * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 * * We use ~0 as a mask in this case because it generates all 1s * * @ref https://eval.in/400356 (32-bit) * @ref http://3v4l.org/XX9r5 (64-bit) */ $bytes = PHP_INT_SIZE; /** @var int $mask */ $mask = ~0; } else { /** * $bits is effectively ceil(log($range, 2)) without dealing with * type juggling */ while ($range > 0) { if ($bits % 8 === 0) { ++$bytes; } ++$bits; $range >>= 1; /** @var int $mask */ $mask = $mask << 1 | 1; } $valueShift = $min; } /** @var int $val */ $val = 0; /** * Now that we have our parameters set up, let's begin generating * random integers until one falls between $min and $max */ /** @psalm-suppress RedundantCondition */ do { /** * The rejection probability is at most 0.5, so this corresponds * to a failure probability of 2^-128 for a working RNG */ if ($attempts > 128) { throw new Exception( 'random_int: RNG is broken - too many rejections' ); } /** * Let's grab the necessary number of random bytes */ $randomByteString = random_bytes($bytes); /** * Let's turn $randomByteString into an integer * * This uses bitwise operators (<< and |) to build an integer * out of the values extracted from ord() * * Example: [9F] | [6D] | [32] | [0C] => * 159 + 27904 + 3276800 + 201326592 => * 204631455 */ $val &= 0; for ($i = 0; $i < $bytes; ++$i) { $val |= ord($randomByteString[$i]) << ($i * 8); } /** @var int $val */ /** * Apply mask */ $val &= $mask; $val += $valueShift; ++$attempts; /** * If $val overflows to a floating point number, *... or is larger than $max, *... or smaller than $min, * then try again. */ } while (!is_int($val) || $val > $max || $val < $min); return (int) $val; } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!is_callable('random_bytes')) { /** * If the libsodium PHP extension is loaded, we'll use it above any other * solution. * * libsodium-php project: * @ref https://github.com/jedisct1/libsodium-php * * @param int $bytes * * @throws Exception * * @return string */ function random_bytes($bytes) { try { /** @var int $bytes */ $bytes = RandomCompat_intval($bytes); } catch (TypeError $ex) { throw new TypeError( 'random_bytes(): $bytes must be an integer' ); } if ($bytes < 1) { throw new Error( 'Length must be greater than 0' ); } /** * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be * generated in one invocation. */ /** @var string|bool $buf */ if ($bytes > 2147483647) { $buf = ''; for ($i = 0; $i < $bytes; $i += 1073741824) { $n = ($bytes - $i) > 1073741824 ? 1073741824 : $bytes - $i; $buf .= \Sodium\randombytes_buf($n); } } else { /** @var string|bool $buf */ $buf = \Sodium\randombytes_buf($bytes); } if (is_string($buf)) { if (RandomCompat_strlen($buf) === $bytes) { return $buf; } } /** * If we reach here, PHP has failed us. */ throw new Exception( 'Could not gather sufficient random data' ); } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!is_callable('random_bytes')) { /** * If the libsodium PHP extension is loaded, we'll use it above any other * solution. * * libsodium-php project: * @ref https://github.com/jedisct1/libsodium-php * * @param int $bytes * * @throws Exception * * @return string */ function random_bytes($bytes) { try { /** @var int $bytes */ $bytes = RandomCompat_intval($bytes); } catch (TypeError $ex) { throw new TypeError( 'random_bytes(): $bytes must be an integer' ); } if ($bytes < 1) { throw new Error( 'Length must be greater than 0' ); } /** * @var string */ $buf = ''; /** * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be * generated in one invocation. */ if ($bytes > 2147483647) { for ($i = 0; $i < $bytes; $i += 1073741824) { $n = ($bytes - $i) > 1073741824 ? 1073741824 : $bytes - $i; $buf .= Sodium::randombytes_buf((int) $n); } } else { $buf .= Sodium::randombytes_buf((int) $bytes); } if (is_string($buf)) { if (RandomCompat_strlen($buf) === $bytes) { return $buf; } } /** * If we reach here, PHP has failed us. */ throw new Exception( 'Could not gather sufficient random data' ); } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!is_callable('random_bytes')) { /** * Windows with PHP < 5.3.0 will not have the function * openssl_random_pseudo_bytes() available, so let's use * CAPICOM to work around this deficiency. * * @param int $bytes * * @throws Exception * * @return string */ function random_bytes($bytes) { try { /** @var int $bytes */ $bytes = RandomCompat_intval($bytes); } catch (TypeError $ex) { throw new TypeError( 'random_bytes(): $bytes must be an integer' ); } if ($bytes < 1) { throw new Error( 'Length must be greater than 0' ); } /** @var string $buf */ $buf = ''; if (!class_exists('COM')) { throw new Error( 'COM does not exist' ); } /** @var COM $util */ $util = new COM('CAPICOM.Utilities.1'); $execCount = 0; /** * Let's not let it loop forever. If we run N times and fail to * get N bytes of random data, then CAPICOM has failed us. */ do { $buf .= base64_decode((string) $util->GetRandom($bytes, 0)); if (RandomCompat_strlen($buf) >= $bytes) { /** * Return our random entropy buffer here: */ return (string) RandomCompat_substr($buf, 0, $bytes); } ++$execCount; } while ($execCount < $bytes); /** * If we reach here, PHP has failed us. */ throw new Exception( 'Could not gather sufficient random data' ); } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!defined('RANDOM_COMPAT_READ_BUFFER')) { define('RANDOM_COMPAT_READ_BUFFER', 8); } if (!is_callable('random_bytes')) { /** * Unless open_basedir is enabled, use /dev/urandom for * random numbers in accordance with best practices * * Why we use /dev/urandom and not /dev/random * @ref https://www.2uo.de/myths-about-urandom * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers * * @param int $bytes * * @throws Exception * * @return string */ function random_bytes($bytes) { /** @var resource $fp */ static $fp = null; /** * This block should only be run once */ if (empty($fp)) { /** * We don't want to ever read C:\dev\random, only /dev/urandom on * Unix-like operating systems. While we guard against this * condition in random.php, it doesn't hurt to be defensive in depth * here. * * To that end, we only try to open /dev/urandom if we're on a Unix- * like operating system (which means the directory separator is set * to "/" not "\". */ if (DIRECTORY_SEPARATOR === '/') { if (!is_readable('/dev/urandom')) { throw new Exception( 'Environment misconfiguration: ' . '/dev/urandom cannot be read.' ); } /** * We use /dev/urandom if it is a char device. * We never fall back to /dev/random */ /** @var resource|bool $fp */ $fp = fopen('/dev/urandom', 'rb'); if (is_resource($fp)) { /** @var array<string, int> $st */ $st = fstat($fp); if (($st['mode'] & 0170000) !== 020000) { fclose($fp); $fp = false; } } } if (is_resource($fp)) { /** * stream_set_read_buffer() does not exist in HHVM * * If we don't set the stream's read buffer to 0, PHP will * internally buffer 8192 bytes, which can waste entropy * * stream_set_read_buffer returns 0 on success */ if (is_callable('stream_set_read_buffer')) { stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER); } if (is_callable('stream_set_chunk_size')) { stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER); } } } try { /** @var int $bytes */ $bytes = RandomCompat_intval($bytes); } catch (TypeError $ex) { throw new TypeError( 'random_bytes(): $bytes must be an integer' ); } if ($bytes < 1) { throw new Error( 'Length must be greater than 0' ); } /** * This if() block only runs if we managed to open a file handle * * It does not belong in an else {} block, because the above * if (empty($fp)) line is logic that should only be run once per * page load. */ if (is_resource($fp)) { /** * @var int */ $remaining = $bytes; /** * @var string|bool */ $buf = ''; /** * We use fread() in a loop to protect against partial reads */ do { /** * @var string|bool */ $read = fread($fp, $remaining); if (!is_string($read)) { /** * We cannot safely read from the file. Exit the * do-while loop and trigger the exception condition * * @var string|bool */ $buf = false; break; } /** * Decrease the number of bytes returned from remaining */ $remaining -= RandomCompat_strlen($read); /** * @var string $buf */ $buf .= $read; } while ($remaining > 0); /** * Is our result valid? * @var string|bool $buf */ if (is_string($buf)) { if (RandomCompat_strlen($buf) === $bytes) { /** * Return our random entropy buffer here: */ return $buf; } } } /** * If we reach here, PHP has failed us. */ throw new Exception( 'Error reading from source device' ); } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * @version 2.0.17 * @released 2018-07-04 * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!defined('PHP_VERSION_ID')) { // This constant was introduced in PHP 5.2.7 $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION)); define( 'PHP_VERSION_ID', $RandomCompatversion[0] * 10000 + $RandomCompatversion[1] * 100 + $RandomCompatversion[2] ); $RandomCompatversion = null; } /** * PHP 7.0.0 and newer have these functions natively. */ if (PHP_VERSION_ID >= 70000) { return; } if (!defined('RANDOM_COMPAT_READ_BUFFER')) { define('RANDOM_COMPAT_READ_BUFFER', 8); } $RandomCompatDIR = dirname(__FILE__); require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php'; require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php'; require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php'; if (!is_callable('random_bytes')) { /** * PHP 5.2.0 - 5.6.x way to implement random_bytes() * * We use conditional statements here to define the function in accordance * to the operating environment. It's a micro-optimization. * * In order of preference: * 1. Use libsodium if available. * 2. fread() /dev/urandom if available (never on Windows) * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) * 4. COM('CAPICOM.Utilities.1')->GetRandom() * * See RATIONALE.md for our reasoning behind this particular order */ if (extension_loaded('libsodium')) { // See random_bytes_libsodium.php if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php'; } elseif (method_exists('Sodium', 'randombytes_buf')) { require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php'; } } /** * Reading directly from /dev/urandom: */ if (DIRECTORY_SEPARATOR === '/') { // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast // way to exclude Windows. $RandomCompatUrandom = true; $RandomCompat_basedir = ini_get('open_basedir'); if (!empty($RandomCompat_basedir)) { $RandomCompat_open_basedir = explode( PATH_SEPARATOR, strtolower($RandomCompat_basedir) ); $RandomCompatUrandom = (array() !== array_intersect( array('/dev', '/dev/', '/dev/urandom'), $RandomCompat_open_basedir )); $RandomCompat_open_basedir = null; } if ( !is_callable('random_bytes') && $RandomCompatUrandom && @is_readable('/dev/urandom') ) { // Error suppression on is_readable() in case of an open_basedir // or safe_mode failure. All we care about is whether or not we // can read it at this point. If the PHP environment is going to // panic over trying to see if the file can be read in the first // place, that is not helpful to us here. // See random_bytes_dev_urandom.php require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php'; } // Unset variables after use $RandomCompat_basedir = null; } else { $RandomCompatUrandom = false; } /** * mcrypt_create_iv() * * We only want to use mcypt_create_iv() if: * * - random_bytes() hasn't already been defined * - the mcrypt extensions is loaded * - One of these two conditions is true: * - We're on Windows (DIRECTORY_SEPARATOR !== '/') * - We're not on Windows and /dev/urandom is readabale * (i.e. we're not in a chroot jail) * - Special case: * - If we're not on Windows, but the PHP version is between * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will * hang indefinitely. This is bad. * - If we're on Windows, we want to use PHP >= 5.3.7 or else * we get insufficient entropy errors. */ if ( !is_callable('random_bytes') && // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) && // Prevent this code from hanging indefinitely on non-Windows; // see https://bugs.php.net/bug.php?id=69833 ( DIRECTORY_SEPARATOR !== '/' || (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) ) && extension_loaded('mcrypt') ) { // See random_bytes_mcrypt.php require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php'; } $RandomCompatUrandom = null; /** * This is a Windows-specific fallback, for when the mcrypt extension * isn't loaded. */ if ( !is_callable('random_bytes') && extension_loaded('com_dotnet') && class_exists('COM') ) { $RandomCompat_disabled_classes = preg_split( '#\s*,\s*#', strtolower(ini_get('disable_classes')) ); if (!in_array('com', $RandomCompat_disabled_classes)) { try { $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); if (method_exists($RandomCompatCOMtest, 'GetRandom')) { // See random_bytes_com_dotnet.php require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php'; } } catch (com_exception $e) { // Don't try to use it. } } $RandomCompat_disabled_classes = null; $RandomCompatCOMtest = null; } /** * throw new Exception */ if (!is_callable('random_bytes')) { /** * We don't have any more options, so let's throw an exception right now * and hope the developer won't let it fail silently. * * @param mixed $length * @psalm-suppress InvalidReturnType * @throws Exception * @return string */ function random_bytes($length) { unset($length); // Suppress "variable not used" warnings. throw new Exception( 'There is no suitable CSPRNG installed on your system' ); return ''; } } } if (!is_callable('random_int')) { require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php'; } $RandomCompatDIR = null; <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!class_exists('Error', false)) { // We can't really avoid making this extend Exception in PHP 5. class Error extends Exception { } } if (!class_exists('TypeError', false)) { if (is_subclass_of('Error', 'Exception')) { class TypeError extends Error { } } else { class TypeError extends Exception { } } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!is_callable('random_bytes')) { /** * Powered by ext/mcrypt (and thankfully NOT libmcrypt) * * @ref https://bugs.php.net/bug.php?id=55169 * @ref https://github.com/php/php-src/blob/c568ffe5171d942161fc8dda066bce844bdef676/ext/mcrypt/mcrypt.c#L1321-L1386 * * @param int $bytes * * @throws Exception * * @return string */ function random_bytes($bytes) { try { /** @var int $bytes */ $bytes = RandomCompat_intval($bytes); } catch (TypeError $ex) { throw new TypeError( 'random_bytes(): $bytes must be an integer' ); } if ($bytes < 1) { throw new Error( 'Length must be greater than 0' ); } /** @var string|bool $buf */ $buf = @mcrypt_create_iv((int) $bytes, (int) MCRYPT_DEV_URANDOM); if ( is_string($buf) && RandomCompat_strlen($buf) === $bytes ) { /** * Return our random entropy buffer here: */ return $buf; } /** * If we reach here, PHP has failed us. */ throw new Exception( 'Could not gather sufficient random data' ); } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!is_callable('RandomCompat_intval')) { /** * Cast to an integer if we can, safely. * * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX) * (non-inclusive), it will sanely cast it to an int. If you it's equal to * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats * lose precision, so the <= and => operators might accidentally let a float * through. * * @param int|float $number The number we want to convert to an int * @param bool $fail_open Set to true to not throw an exception * * @return float|int * @psalm-suppress InvalidReturnType * * @throws TypeError */ function RandomCompat_intval($number, $fail_open = false) { if (is_int($number) || is_float($number)) { $number += 0; } elseif (is_numeric($number)) { /** @psalm-suppress InvalidOperand */ $number += 0; } /** @var int|float $number */ if ( is_float($number) && $number > ~PHP_INT_MAX && $number < PHP_INT_MAX ) { $number = (int) $number; } if (is_int($number)) { return (int) $number; } elseif (!$fail_open) { throw new TypeError( 'Expected an integer.' ); } return $number; } } <?php /** * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * * The MIT License (MIT) * * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ if (!is_callable('RandomCompat_strlen')) { if ( defined('MB_OVERLOAD_STRING') && ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING ) { /** * strlen() implementation that isn't brittle to mbstring.func_overload * * This version uses mb_strlen() in '8bit' mode to treat strings as raw * binary rather than UTF-8, ISO-8859-1, etc * * @param string $binary_string * * @throws TypeError * * @return int */ function RandomCompat_strlen($binary_string) { if (!is_string($binary_string)) { throw new TypeError( 'RandomCompat_strlen() expects a string' ); } return (int) mb_strlen($binary_string, '8bit'); } } else { /** * strlen() implementation that isn't brittle to mbstring.func_overload * * This version just used the default strlen() * * @param string $binary_string * * @throws TypeError * * @return int */ function RandomCompat_strlen($binary_string) { if (!is_string($binary_string)) { throw new TypeError( 'RandomCompat_strlen() expects a string' ); } return (int) strlen($binary_string); } } } if (!is_callable('RandomCompat_substr')) { if ( defined('MB_OVERLOAD_STRING') && ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING ) { /** * substr() implementation that isn't brittle to mbstring.func_overload * * This version uses mb_substr() in '8bit' mode to treat strings as raw * binary rather than UTF-8, ISO-8859-1, etc * * @param string $binary_string * @param int $start * @param int|null $length (optional) * * @throws TypeError * * @return string */ function RandomCompat_substr($binary_string, $start, $length = null) { if (!is_string($binary_string)) { throw new TypeError( 'RandomCompat_substr(): First argument should be a string' ); } if (!is_int($start)) { throw new TypeError( 'RandomCompat_substr(): Second argument should be an integer' ); } if ($length === null) { /** * mb_substr($str, 0, NULL, '8bit') returns an empty string on * PHP 5.3, so we have to find the length ourselves. */ /** @var int $length */ $length = RandomCompat_strlen($binary_string) - $start; } elseif (!is_int($length)) { throw new TypeError( 'RandomCompat_substr(): Third argument should be an integer, or omitted' ); } // Consistency with PHP's behavior if ($start === RandomCompat_strlen($binary_string) && $length === 0) { return ''; } if ($start > RandomCompat_strlen($binary_string)) { return ''; } return (string) mb_substr( (string) $binary_string, (int) $start, (int) $length, '8bit' ); } } else { /** * substr() implementation that isn't brittle to mbstring.func_overload * * This version just uses the default substr() * * @param string $binary_string * @param int $start * @param int|null $length (optional) * * @throws TypeError * * @return string */ function RandomCompat_substr($binary_string, $start, $length = null) { if (!is_string($binary_string)) { throw new TypeError( 'RandomCompat_substr(): First argument should be a string' ); } if (!is_int($start)) { throw new TypeError( 'RandomCompat_substr(): Second argument should be an integer' ); } if ($length !== null) { if (!is_int($length)) { throw new TypeError( 'RandomCompat_substr(): Third argument should be an integer, or omitted' ); } return (string) substr( (string )$binary_string, (int) $start, (int) $length ); } return (string) substr( (string) $binary_string, (int) $start ); } } } { "name": "paragonie/constant_time_encoding", "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", "keywords": [ "base64", "encoding", "rfc4648", "base32", "base16", "hex", "bin2hex", "hex2bin", "base64_encode", "base64_decode", "base32_encode", "base32_decode" ], "license": "MIT", "type": "library", "authors": [ { "name": "Paragon Initiative Enterprises", "email": "security@paragonie.com", "homepage": "https://paragonie.com", "role": "Maintainer" }, { "name": "Steve 'Sc00bz' Thomas", "email": "steve@tobtu.com", "homepage": "https://www.tobtu.com", "role": "Original Developer" } ], "support": { "issues": "https://github.com/paragonie/constant_time_encoding/issues", "email": "info@paragonie.com", "source": "https://github.com/paragonie/constant_time_encoding" }, "require": { "php": "^5.3|^7" }, "require-dev": { "phpunit/phpunit": "4.*|5.*", "paragonie/random_compat": "^1.4|^2", "vimeo/psalm": "^0.3|^1" }, "autoload": { "psr-4": { "ParagonIE\\ConstantTime\\": "src/" } } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Encoding * @package ParagonIE\ConstantTime */ abstract class Encoding { /** * RFC 4648 Base32 encoding * * @param string $str * @return string */ public static function base32Encode($str) { return Base32::encode($str); } /** * RFC 4648 Base32 encoding * * @param string $str * @return string */ public static function base32EncodeUpper($str) { return Base32::encodeUpper($str); } /** * RFC 4648 Base32 decoding * * @param string $str * @return string */ public static function base32Decode($str) { return Base32::decode($str); } /** * RFC 4648 Base32 decoding * * @param string $str * @return string */ public static function base32DecodeUpper($str) { return Base32::decodeUpper($str); } /** * RFC 4648 Base32 encoding * * @param string $str * @return string */ public static function base32HexEncode($str) { return Base32Hex::encode($str); } /** * RFC 4648 Base32 encoding * * @param string $str * @return string */ public static function base32HexEncodeUpper($str) { return Base32Hex::encodeUpper($str); } /** * RFC 4648 Base32 decoding * * @param string $str * @return string */ public static function base32HexDecode($str) { return Base32Hex::decode($str); } /** * RFC 4648 Base32 decoding * * @param string $str * @return string */ public static function base32HexDecodeUpper($str) { return Base32Hex::decodeUpper($str); } /** * RFC 4648 Base64 encoding * * @param string $str * @return string */ public static function base64Encode($str) { return Base64::encode($str); } /** * RFC 4648 Base32 decoding * * @param string $str * @return string */ public static function base64Decode($str) { return Base64::decode($str); } /** * Encode into Base64 * * Base64 character set "./[A-Z][a-z][0-9]" * @param string $src * @return string */ public static function base64EncodeDotSlash($src) { return Base64DotSlash::encode($src); } /** * Decode from base64 to raw binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @return string * @throws \RangeException */ public static function base64DecodeDotSlash($src) { return Base64DotSlash::decode($src); } /** * Encode into Base64 * * Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]" * @param string $src * @return string */ public static function base64EncodeDotSlashOrdered($src) { return Base64DotSlashOrdered::encode($src); } /** * Decode from base64 to raw binary * * Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]" * * @param string $src * @return string * @throws \RangeException */ public static function base64DecodeDotSlashOrdered($src) { return Base64DotSlashOrdered::decode($src); } /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @param string $bin_string (raw binary) * @return string */ public static function hexEncode($bin_string) { return Hex::encode($bin_string); } /** * Convert a hexadecimal string into a binary string without cache-timing * leaks * * @param string $hex_string * @return string (raw binary) * @throws \RangeException */ public static function hexDecode($hex_string) { return Hex::decode($hex_string); } /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @param string $bin_string (raw binary) * @return string */ public static function hexEncodeUpper($bin_string) { return Hex::encodeUpper($bin_string); } /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @param string $bin_string (raw binary) * @return string */ public static function hexDecodeUpper($bin_string) { return Hex::decode($bin_string); } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Interface EncoderInterface * @package ParagonIE\ConstantTime */ interface EncoderInterface { /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @param string $bin_string (raw binary) * @return string */ public static function encode($bin_string); /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @param string $encoded_string * @return string (raw binary) */ public static function decode($encoded_string); } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Binary * * Binary string operators that don't choke on * mbstring.func_overload * * @package ParagonIE\ConstantTime */ abstract class Binary { /** * Safe string length * * @ref mbstring.func_overload * * @param string $str * @return int */ public static function safeStrlen($str) { if (\function_exists('mb_strlen')) { return (int) \mb_strlen($str, '8bit'); } else { return (int) \strlen($str); } } /** * Safe substring * * @ref mbstring.func_overload * * @staticvar boolean $exists * @param string $str * @param int $start * @param int $length * @return string * @throws \TypeError */ public static function safeSubstr( $str, $start = 0, $length = \null ) { if (\function_exists('mb_substr')) { // mb_substr($str, 0, null, '8bit') returns an empty string on PHP // 5.3, so we have to find the length ourselves. if (\is_null($length)) { if ($start >= 0) { $length = self::safeStrlen($str) - $start; } else { $length = -$start; } } // $length calculation above might result in a 0-length string if ($length === 0) { return ''; } return \mb_substr($str, $start, $length, '8bit'); } if ($length === 0) { return ''; } // Unlike mb_substr(), substr() doesn't accept null for length if (!is_null($length)) { return \substr($str, $start, $length); } else { return \substr($str, $start); } } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Hex * @package ParagonIE\ConstantTime */ abstract class Hex implements EncoderInterface { /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @param string $bin_string (raw binary) * @return string */ public static function encode($bin_string) { $hex = ''; $len = Binary::safeStrlen($bin_string); for ($i = 0; $i < $len; ++$i) { $chunk = \unpack('C', Binary::safeSubstr($bin_string, $i, 2)); $c = $chunk[1] & 0xf; $b = $chunk[1] >> 4; $hex .= pack( 'CC', (87 + $b + ((($b - 10) >> 8) & ~38)), (87 + $c + ((($c - 10) >> 8) & ~38)) ); } return $hex; } /** * Convert a binary string into a hexadecimal string without cache-timing * leaks, returning uppercase letters (as per RFC 4648) * * @param string $bin_string (raw binary) * @return string */ public static function encodeUpper($bin_string) { $hex = ''; $len = Binary::safeStrlen($bin_string); for ($i = 0; $i < $len; ++$i) { $chunk = \unpack('C', Binary::safeSubstr($bin_string, $i, 2)); $c = $chunk[1] & 0xf; $b = $chunk[1] >> 4; $hex .= pack( 'CC', (55 + $b + ((($b - 10) >> 8) & ~6)), (55 + $c + ((($c - 10) >> 8) & ~6)) ); } return $hex; } /** * Convert a hexadecimal string into a binary string without cache-timing * leaks * * @param string $hex_string * @return string (raw binary) * @throws \RangeException */ public static function decode($hex_string) { $hex_pos = 0; $bin = ''; $c_acc = 0; $hex_len = Binary::safeStrlen($hex_string); $state = 0; if (($hex_len & 1) !== 0) { throw new \RangeException( 'Expected an even number of hexadecimal characters' ); } $chunk = \unpack('C*', $hex_string); while ($hex_pos < $hex_len) { ++$hex_pos; $c = $chunk[$hex_pos]; $c_num = $c ^ 48; $c_num0 = ($c_num - 10) >> 8; $c_alpha = ($c & ~32) - 55; $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; if (($c_num0 | $c_alpha0) === 0) { throw new \RangeException( 'hexEncode() only expects hexadecimal characters' ); } $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); if ($state === 0) { $c_acc = $c_val * 16; } else { $bin .= \pack('C', $c_acc | $c_val); } $state ^= 1; } return $bin; } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Base64DotSlash * ./[A-Z][a-z][0-9] * * @package ParagonIE\ConstantTime */ abstract class Base64UrlSafe extends Base64 { /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] - _ * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2d, 0x5f * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); // if ($src == 0x2c) $ret += 62 + 1; $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63; // if ($src == 0x5f) ret += 63 + 1; $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64; return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $diff = 0x41; // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 $diff += ((25 - $src) >> 8) & 6; // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 $diff -= ((51 - $src) >> 8) & 75; // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13 $diff -= ((61 - $src) >> 8) & 13; // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3 $diff += ((62 - $src) >> 8) & 49; return \pack('C', $src + $diff); } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class RFC4648 * * This class conforms strictly to the RFC * * @package ParagonIE\ConstantTime */ abstract class RFC4648 { /** * RFC 4648 Base64 encoding * * "foo" -> "Zm9v" * * @param string $str * @return string */ public function base64Encode($str) { return Base64::encode($str); } /** * RFC 4648 Base64 decoding * * "Zm9v" -> "foo" * * @param string $str * @return string */ public function base64Decode($str) { return Base64::decode($str); } /** * RFC 4648 Base64 (URL Safe) encoding * * "foo" -> "Zm9v" * * @param string $str * @return string */ public function base64UrlSafeEncode($str) { return Base64UrlSafe::encode($str); } /** * RFC 4648 Base64 (URL Safe) decoding * * "Zm9v" -> "foo" * * @param string $str * @return string */ public function base64UrlSafeDecode($str) { return Base64UrlSafe::decode($str); } /** * RFC 4648 Base32 encoding * * "foo" -> "MZXW6===" * * @param string $str * @return string */ public function base32Encode($str) { return Base32::encodeUpper($str); } /** * RFC 4648 Base32 encoding * * "MZXW6===" -> "foo" * * @param string $str * @return string */ public function base32Decode($str) { return Base32::decodeUpper($str); } /** * RFC 4648 Base32-Hex encoding * * "foo" -> "CPNMU===" * * @param string $str * @return string */ public function base32HexEncode($str) { return Base32::encodeUpper($str); } /** * RFC 4648 Base32-Hex decoding * * "CPNMU===" -> "foo" * * @param string $str * @return string */ public function base32HexDecode($str) { return Base32::decodeUpper($str); } /** * RFC 4648 Base16 decoding * * "foo" -> "666F6F" * * @param string $str * @return string */ public function base16Encode($str) { return Hex::encodeUpper($str); } /** * RFC 4648 Base16 decoding * * "666F6F" -> "foo" * * @param string $str * @return string */ public function base16Decode($str) { return Hex::decode($str); } }<?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Base64DotSlash * ./[A-Z][a-z][0-9] * * @package ParagonIE\ConstantTime */ abstract class Base64DotSlash extends Base64 { /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * ./ [A-Z] [a-z] [0-9] * 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39 * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x2d && $src < 0x30) ret += $src - 0x2e + 1; // -45 $ret += (((0x2d - $src) & ($src - 0x30)) >> 8) & ($src - 45); // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 2 + 1; // -62 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 62); // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 28 + 1; // -68 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 68); // if ($src > 0x2f && $src < 0x3a) ret += $src - 0x30 + 54 + 1; // 7 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 7); return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $src += 0x2e; // if ($src > 0x2f) $src += 0x41 - 0x30; // 17 $src += ((0x2f - $src) >> 8) & 17; // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6 $src += ((0x5a - $src) >> 8) & 6; // if ($src > 0x7a) $src += 0x30 - 0x7b; // -75 $src -= ((0x7a - $src) >> 8) & 75; return \pack('C', $src); } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Base32Hex * [0-9][A-V] * * @package ParagonIE\ConstantTime */ abstract class Base32Hex extends Base32 { /** * Uses bitwise operators instead of table-lookups to turn 5-bit integers * into 8-bit integers. * * @param int $src * @return int */ protected static function decode5Bits($src) { $ret = -1; // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47); // if ($src > 0x60 && $src < 0x77) ret += $src - 0x61 + 10 + 1; // -86 $ret += (((0x60 - $src) & ($src - 0x77)) >> 8) & ($src - 86); return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 5-bit integers * into 8-bit integers. * * @param int $src * @return int */ protected static function decode5BitsUpper($src) { $ret = -1; // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47); // if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54 $ret += (((0x40 - $src) & ($src - 0x57)) >> 8) & ($src - 54); return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 5-bit integers. * * @param int $src * @return string */ protected static function encode5Bits($src) { $src += 0x30; // if ($src > 0x39) $src += 0x61 - 0x3a; // 39 $src += ((0x39 - $src) >> 8) & 39; return \pack('C', $src); } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 5-bit integers. * * Uppercase variant. * * @param int $src * @return string */ protected static function encode5BitsUpper($src) { $src += 0x30; // if ($src > 0x39) $src += 0x41 - 0x3a; // 7 $src += ((0x39 - $src) >> 8) & 7; return \pack('C', $src); } }<?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Base32 * [A-Z][2-7] * * @package ParagonIE\ConstantTime */ abstract class Base32 implements EncoderInterface { /** * Decode a Base32-encoded string into raw binary * * @param string $src * @param bool $strictPadding * @return string */ public static function decode($src, $strictPadding = \false) { return static::doDecode($src, \false, $strictPadding); } /** * Decode an uppercase Base32-encoded string into raw binary * * @param string $src * @param bool $strictPadding * @return string */ public static function decodeUpper($src, $strictPadding = \false) { return static::doDecode($src, \true, $strictPadding); } /** * Encode into Base32 (RFC 4648) * * @param string $src * @return string */ public static function encode($src) { return static::doEncode($src, \false); } /** * Encode into Base32 (RFC 4648) * * @param string $src * @return string * @throws \TypeError */ public static function encodeUnpadded($src) { return static::doEncode($src, false, false); } /** * Encode into uppercase Base32 (RFC 4648) * * @param string $src * @return string */ public static function encodeUpper($src) { return static::doEncode($src, \true); } /** * Encode into uppercase Base32 (RFC 4648) * * @param string $src * @return string * @throws \TypeError */ public static function encodeUpperUnpadded($src) { return static::doEncode($src, true, false); } /** * Uses bitwise operators instead of table-lookups to turn 5-bit integers * into 8-bit integers. * * @param int $src * @return int */ protected static function decode5Bits($src) { $ret = -1; // if ($src > 96 && $src < 123) $ret += $src - 97 + 1; // -64 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 96); // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23 $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23); return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 5-bit integers * into 8-bit integers. * * Uppercase variant. * * @param int $src * @return int */ protected static function decode5BitsUpper($src) { $ret = -1; // if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23 $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23); return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 5-bit integers. * * @param int $src * @return string */ protected static function encode5Bits($src) { $diff = 0x61; // if ($src > 25) $ret -= 72; $diff -= ((25 - $src) >> 8) & 73; return \pack('C', $src + $diff); } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 5-bit integers. * * Uppercase variant. * * @param int $src * @return string */ protected static function encode5BitsUpper($src) { $diff = 0x41; // if ($src > 25) $ret -= 40; $diff -= ((25 - $src) >> 8) & 41; return \pack('C', $src + $diff); } /** * Base32 decoding * * @param string $src * @param bool $upper * @param bool $strictPadding * @return string */ protected static function doDecode($src, $upper = \false, $strictPadding = \true) { // We do this to reduce code duplication: $method = $upper ? 'decode5BitsUpper' : 'decode5Bits'; // Remove padding $srcLen = Binary::safeStrlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 7) === 0) { for ($j = 0; $j < 7; ++$j) { if ($src[$srcLen - 1] === '=') { $srcLen--; } else { break; } } } if (($srcLen & 7) === 1) { throw new \RangeException( 'Incorrect padding' ); } } else { $src = \rtrim($src, '='); $srcLen = Binary::safeStrlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 8 <= $srcLen; $i += 8) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8)); $c0 = static::$method($chunk[1]); $c1 = static::$method($chunk[2]); $c2 = static::$method($chunk[3]); $c3 = static::$method($chunk[4]); $c4 = static::$method($chunk[5]); $c5 = static::$method($chunk[6]); $c6 = static::$method($chunk[7]); $c7 = static::$method($chunk[8]); $dest .= \pack( 'CCCCC', (($c0 << 3) | ($c1 >> 2) ) & 0xff, (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, (($c3 << 4) | ($c4 >> 1) ) & 0xff, (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff, (($c6 << 5) | ($c7 ) ) & 0xff ); $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); $c0 = static::$method($chunk[1]); if ($i + 6 < $srcLen) { $c1 = static::$method($chunk[2]); $c2 = static::$method($chunk[3]); $c3 = static::$method($chunk[4]); $c4 = static::$method($chunk[5]); $c5 = static::$method($chunk[6]); $c6 = static::$method($chunk[7]); $dest .= \pack( 'CCCC', (($c0 << 3) | ($c1 >> 2) ) & 0xff, (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, (($c3 << 4) | ($c4 >> 1) ) & 0xff, (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff ); $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8; } elseif ($i + 5 < $srcLen) { $c1 = static::$method($chunk[2]); $c2 = static::$method($chunk[3]); $c3 = static::$method($chunk[4]); $c4 = static::$method($chunk[5]); $c5 = static::$method($chunk[6]); $dest .= \pack( 'CCCC', (($c0 << 3) | ($c1 >> 2) ) & 0xff, (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, (($c3 << 4) | ($c4 >> 1) ) & 0xff, (($c4 << 7) | ($c5 << 2) ) & 0xff ); $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8; } elseif ($i + 4 < $srcLen) { $c1 = static::$method($chunk[2]); $c2 = static::$method($chunk[3]); $c3 = static::$method($chunk[4]); $c4 = static::$method($chunk[5]); $dest .= \pack( 'CCC', (($c0 << 3) | ($c1 >> 2) ) & 0xff, (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff, (($c3 << 4) | ($c4 >> 1) ) & 0xff ); $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8; } elseif ($i + 3 < $srcLen) { $c1 = static::$method($chunk[2]); $c2 = static::$method($chunk[3]); $c3 = static::$method($chunk[4]); $dest .= \pack( 'CC', (($c0 << 3) | ($c1 >> 2) ) & 0xff, (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } elseif ($i + 2 < $srcLen) { $c1 = static::$method($chunk[2]); $c2 = static::$method($chunk[3]); $dest .= \pack( 'CC', (($c0 << 3) | ($c1 >> 2) ) & 0xff, (($c1 << 6) | ($c2 << 1) ) & 0xff ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif ($i + 1 < $srcLen) { $c1 = static::$method($chunk[2]); $dest .= \pack( 'C', (($c0 << 3) | ($c1 >> 2) ) & 0xff ); $err |= ($c0 | $c1) >> 8; } else { $dest .= \pack( 'C', (($c0 << 3) ) & 0xff ); $err |= ($c0) >> 8; } } if ($err !== 0) { throw new \RangeException( 'Base32::doDecode() only expects characters in the correct base32 alphabet' ); } return $dest; } /** * Base32 Decoding * * @param string $src * @param bool $upper * @param bool $pad * @return string */ protected static function doEncode($src, $upper = \false, $pad = \true) { // We do this to reduce code duplication: $method = $upper ? 'encode5BitsUpper' : 'encode5Bits'; $dest = ''; $srcLen = Binary::safeStrlen($src); // Main loop (no padding): for ($i = 0; $i + 5 <= $srcLen; $i += 5) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $b3 = $chunk[4]; $b4 = $chunk[5]; $dest .= static::$method( ($b0 >> 3) & 31) . static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . static::$method((($b1 >> 1) ) & 31) . static::$method((($b1 << 4) | ($b2 >> 4)) & 31) . static::$method((($b2 << 1) | ($b3 >> 7)) & 31) . static::$method((($b3 >> 2) ) & 31) . static::$method((($b3 << 3) | ($b4 >> 5)) & 31) . static::$method( $b4 & 31); } // The last chunk, which may have padding: if ($i < $srcLen) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 3 < $srcLen) { $b1 = $chunk[2]; $b2 = $chunk[3]; $b3 = $chunk[4]; $dest .= static::$method( ($b0 >> 3) & 31) . static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . static::$method((($b1 >> 1) ) & 31) . static::$method((($b1 << 4) | ($b2 >> 4)) & 31) . static::$method((($b2 << 1) | ($b3 >> 7)) & 31) . static::$method((($b3 >> 2) ) & 31) . static::$method((($b3 << 3) ) & 31); if ($pad) { $dest .= '='; } } elseif ($i + 2 < $srcLen) { $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= static::$method( ($b0 >> 3) & 31) . static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . static::$method((($b1 >> 1) ) & 31) . static::$method((($b1 << 4) | ($b2 >> 4)) & 31) . static::$method((($b2 << 1) ) & 31); if ($pad) { $dest .= '==='; } } elseif ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= static::$method( ($b0 >> 3) & 31) . static::$method((($b0 << 2) | ($b1 >> 6)) & 31) . static::$method((($b1 >> 1) ) & 31) . static::$method((($b1 << 4) ) & 31); if ($pad) { $dest .= '===='; } } else { $dest .= static::$method( ($b0 >> 3) & 31) . static::$method( ($b0 << 2) & 31); if ($pad) { $dest .= '======'; } } } return $dest; } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Base64 * [A-Z][a-z][0-9]+/ * * @package ParagonIE\ConstantTime */ abstract class Base64 implements EncoderInterface { /** * Encode into Base64 * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string */ public static function encode($src) { return static::doEncode($src, \true); } /** * Encode into Base64, no = padding * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string */ public static function encodeUnpadded($src) { return static::doEncode($src, \false); } /** * @param string $src * @param bool $pad Include = padding? * @return string */ protected static function doEncode($src, $pad = \true) { $dest = ''; $srcLen = Binary::safeStrlen($src); // Main loop (no padding): for ($i = 0; $i + 3 <= $srcLen; $i += 3) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 3)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= static::encode6Bits( $b0 >> 2 ) . static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . static::encode6Bits( $b2 & 63); } // The last chunk, which may have padding: if ($i < $srcLen) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= static::encode6Bits( $b0 >> 2 ) . static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . static::encode6Bits( ($b1 << 2) & 63); if ($pad) { $dest .= '='; } } else { $dest .= static::encode6Bits( $b0 >> 2) . static::encode6Bits(($b0 << 4) & 63); if ($pad) { $dest .= '=='; } } } return $dest; } /** * decode from base64 into binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @param bool $strictPadding * @return string * @throws \RangeException */ public static function decode($src, $strictPadding = \false) { // Remove padding $srcLen = Binary::safeStrlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 3) === 0) { if ($src[$srcLen - 1] === '=') { $srcLen--; if ($src[$srcLen - 1] === '=') { $srcLen--; } } } if (($srcLen & 3) === 1) { throw new \RangeException( 'Incorrect padding' ); } } else { $src = \rtrim($src, '='); $srcLen = Binary::safeStrlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 4 <= $srcLen; $i += 4) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 4)); $c0 = static::decode6Bits($chunk[1]); $c1 = static::decode6Bits($chunk[2]); $c2 = static::decode6Bits($chunk[3]); $c3 = static::decode6Bits($chunk[4]); $dest .= \pack( 'CCC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff), ((($c2 << 6) | $c3 ) & 0xff) ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i)); $c0 = static::decode6Bits($chunk[1]); if ($i + 2 < $srcLen) { $c1 = static::decode6Bits($chunk[2]); $c2 = static::decode6Bits($chunk[3]); $dest .= \pack( 'CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff) ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif($i + 1 < $srcLen) { $c1 = static::decode6Bits($chunk[2]); $dest .= \pack( 'C', ((($c0 << 2) | ($c1 >> 4)) & 0xff) ); $err |= ($c0 | $c1) >> 8; } elseif ($i < $srcLen && $strictPadding) { $err |= 1; } } if ($err !== 0) { throw new \RangeException( 'Base64::decode() only expects characters in the correct base64 alphabet' ); } return $dest; } /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] + / * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); // if ($src == 0x2b) $ret += 62 + 1; $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63; // if ($src == 0x2f) ret += 63 + 1; $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64; return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $diff = 0x41; // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 $diff += ((25 - $src) >> 8) & 6; // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 $diff -= ((51 - $src) >> 8) & 75; // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15 $diff -= ((61 - $src) >> 8) & 15; // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3 $diff += ((62 - $src) >> 8) & 3; return \pack('C', $src + $diff); } } <?php namespace ParagonIE\ConstantTime; /** * Copyright (c) 2016 - 2017 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Class Base64DotSlashOrdered * ./[0-9][A-Z][a-z] * * @package ParagonIE\ConstantTime */ abstract class Base64DotSlashOrdered extends Base64 { /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [.-9] [A-Z] [a-z] * 0x2e-0x39, 0x41-0x5a, 0x61-0x7a * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x2d && $src < 0x3a) ret += $src - 0x2e + 1; // -45 $ret += (((0x2d - $src) & ($src - 0x3a)) >> 8) & ($src - 45); // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 12 + 1; // -52 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 52); // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 38 + 1; // -58 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 58); return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $src += 0x2e; // if ($src > 0x39) $src += 0x41 - 0x3a; // 7 $src += ((0x39 - $src) >> 8) & 7; // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6 $src += ((0x5a - $src) >> 8) & 6; return \pack('C', $src); } } { "name": "kelunik/certificate", "description": "Access certificate details and transform between different formats.", "type": "library", "minimum-stability": "dev", "prefer-stable": true, "license": "MIT", "authors": [ { "name": "Niklas Keller", "email": "me@kelunik.com" } ], "keywords": [ "certificate", "certificates", "openssl", "x509", "pem", "der" ], "support": { "issues": "https://github.com/kelunik/certificate/issues" }, "require": { "php": ">=5.4", "ext-openssl": "*" }, "require-dev": { "phpunit/phpunit": "^4.8", "fabpot/php-cs-fixer": "^1.9" }, "autoload": { "psr-4": { "Kelunik\\Certificate\\": "lib" } } } <?php namespace Kelunik\Certificate; class FieldNotSupportedException extends \Exception { } <?php namespace Kelunik\Certificate; class Profile { private $commonName; private $organizationName; private $country; public function __construct($commonName, $organizationName, $country) { $this->commonName = $commonName; $this->organizationName = $organizationName; $this->country = $country; } public function getCommonName() { return $this->commonName; } public function getOrganizationName() { return $this->organizationName; } public function getCountry() { return $this->country; } } <?php namespace Kelunik\Certificate; class InvalidCertificateException extends \Exception { } <?php namespace Kelunik\Certificate; class Certificate { private $pem; private $info; private $issuer; private $subject; public function __construct($pem) { if (is_string($pem)) { if (!$cert = @openssl_x509_read($pem)) { throw new InvalidCertificateException("Invalid PEM encoded certificate!"); } } else if (\is_resource($pem)) { if (\get_resource_type($pem) !== "OpenSSL X.509") { throw new InvalidCertificateException("Invalid resource of type other than 'OpenSSL X.509'!"); } $cert = $pem; } else { throw new \InvalidArgumentException("Invalid variable type, expected string|resource, got " . gettype($pem)); } if (\openssl_x509_export($pem, $this->pem) === false) { throw new InvalidCertificateException("Could not convert 'OpenSSL X.509' resource to PEM!"); } if (!$this->info = openssl_x509_parse($cert)) { throw new InvalidCertificateException("Invalid PEM encoded certificate!"); } } public function getNames() { $san = isset($this->info["extensions"]["subjectAltName"]) ? $this->info["extensions"]["subjectAltName"] : ""; $names = []; $parts = array_map("trim", explode(",", $san)); foreach ($parts as $part) { if (stripos($part, "dns:") === 0) { $names[] = substr($part, 4); } } $names = array_map("strtolower", $names); $names = array_unique($names); sort($names); return $names; } public function getSubject() { if ($this->subject === null) { $this->subject = new Profile( isset($this->info["subject"]["CN"]) ? $this->info["subject"]["CN"] : null, isset($this->info["subject"]["O"]) ? $this->info["subject"]["O"] : null, isset($this->info["subject"]["C"]) ? $this->info["subject"]["C"] : null ); } return $this->subject; } public function getIssuer() { if ($this->issuer === null) { $this->issuer = new Profile( isset($this->info["issuer"]["CN"]) ? $this->info["issuer"]["CN"] : null, isset($this->info["issuer"]["O"]) ? $this->info["issuer"]["O"] : null, isset($this->info["issuer"]["C"]) ? $this->info["issuer"]["C"] : null ); } return $this->issuer; } public function getSerialNumber() { return $this->info["serialNumber"]; } public function getValidFrom() { return $this->info["validFrom_time_t"]; } public function getValidTo() { return $this->info["validTo_time_t"]; } public function getSignatureType() { // https://3v4l.org/Iu3T2 if (!isset($this->info["signatureTypeSN"])) { throw new FieldNotSupportedException("Signature type is not supported in this version of PHP. Please update your version to a higher bugfix version. See: https://3v4l.org/Iu3T2"); } return $this->info["signatureTypeSN"]; } public function isSelfSigned() { return $this->info["subject"] === $this->info["issuer"]; } public function toPem() { return $this->pem; } public function toDer() { return self::pemToDer($this->pem); } public function __toString() { return $this->pem; } public function __debugInfo() { return [ "commonName" => $this->getSubject()->getCommonName(), "names" => $this->getNames(), "issuedBy" => $this->getIssuer()->getCommonName(), "validFrom" => date("d.m.Y", $this->getValidFrom()), "validTo" => date("d.m.Y", $this->getValidTo()), ]; } public static function derToPem($der) { if (!is_string($der)) { throw new \InvalidArgumentException("\$der must be a string, " . gettype($der) . " given."); } return sprintf( "-----BEGIN CERTIFICATE-----\n%s-----END CERTIFICATE-----\n", chunk_split(base64_encode($der), 64, "\n") ); } public static function pemToDer($pem) { if (!is_string($pem)) { throw new \InvalidArgumentException("\$pem must be a string, " . gettype($pem) . " given."); } $pattern = "@-----BEGIN CERTIFICATE-----\n([a-zA-Z0-9+/=\n]+)-----END CERTIFICATE-----@"; if (!preg_match($pattern, $pem, $match)) { throw new InvalidCertificateException("Invalid PEM could not be converted to DER format."); } return base64_decode(str_replace(["\n", "\r"], "", trim($match[1]))); } } { "name": "cash/lrucache", "type": "library", "description": "An efficient memory-based Least Recently Used (LRU) cache", "keywords": ["cache", "lru"], "homepage": "https://github.com/cash/LRUCache", "license": "MIT", "authors": [ { "name": "Cash Costello", "email": "cash.costello@gmail.com" } ], "minimum-stability": "stable", "require": { "php": ">=5.3.0" }, "autoload": { "psr-0": { "cash": "src/" } } } <?php namespace cash; /** * Least Recently Used Cache * * A fixed sized cache that removes the element used last when it reaches its * size limit. */ class LRUCache { /** @var int */ protected $maximumSize; /** * The front of the array contains the LRU element * * @var array */ protected $data = array(); /** * Create a LRU Cache * * @param int $size * @throws \InvalidArgumentException */ public function __construct($size) { if (!is_int($size) || $size <= 0) { throw new \InvalidArgumentException(); } $this->maximumSize = $size; } /** * Get the value cached with this key * * @param int|string $key The key. Strings that are ints are cast to ints. * @param mixed $default The value to be returned if key not found. (Optional) * @return mixed */ public function get($key, $default = null) { if (isset($this->data[$key])) { $this->recordAccess($key); return $this->data[$key]; } else { return $default; } } /** * Put something in the cache * * @param int|string $key The key. Strings that are ints are cast to ints. * @param mixed $value The value to cache */ public function put($key, $value) { if (isset($this->data[$key])) { $this->data[$key] = $value; $this->recordAccess($key); } else { $this->data[$key] = $value; if ($this->size() > $this->maximumSize) { // remove least recently used element (front of array) reset($this->data); unset($this->data[key($this->data)]); } } } /** * Get the number of elements in the cache * * @return int */ public function size() { return count($this->data); } /** * Does the cache contain an element with this key * * @param int|string $key The key * @return boolean */ public function containsKey($key) { return isset($this->data[$key]); } /** * Remove the element with this key. * * @param int|string $key The key * @return mixed Value or null if not set */ public function remove($key) { if (isset($this->data[$key])) { $value = $this->data[$key]; unset($this->data[$key]); return $value; } else { return null; } } /** * Clear the cache */ public function clear() { $this->data = array(); } /** * Moves the element from current position to end of array * * @param int|string $key The key */ protected function recordAccess($key) { $value = $this->data[$key]; unset($this->data[$key]); $this->data[$key] = $value; } }<?php // autoload.php @generated by Composer require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit60e6f00cae484812f6daa343f9cc612e::getLoader(); { "name": "danog/madelineprototests", "minimum-stability":"dev", "require": { "danog/madelineproto": "dev-master", "amphp/dns": "dev-master#aa1892bd as 0.9" }, "repositories": [ { "type": "git", "url": "https://github.com/danog/phpseclib" }, { "type": "path", "url": "/home/travis/build/danog/MadelineProto", "options": { "symlink": false } } ], "authors": [ { "name": "Daniil Gentili", "email": "daniil@daniil.it" } ] } 31fb37d39cdd07972879ee085aaeb70dae65568631fb37d39cdd07972879ee085aaeb70dae65568651V@ؗs8���GBMB