Started to reorganize class
This commit is contained in:
parent
09951563c1
commit
4a8826bdad
@ -2,18 +2,26 @@
|
|||||||
"name": "danog/madelineproto",
|
"name": "danog/madelineproto",
|
||||||
"description": "PHP implementation of telegram's MTProto protocol.",
|
"description": "PHP implementation of telegram's MTProto protocol.",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
|
"license": "MIT",
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"homepage": "https://daniil.it/MadelineProto",
|
||||||
|
"keywords": ["telegram", "mtproto", "protocol", "bytes", "telegram", "client", "PHP"],
|
||||||
"require": {
|
"require": {
|
||||||
"danog/phpstruct": "^1.1",
|
"danog/phpstruct": "^1.1",
|
||||||
"phpseclib/phpseclib": "^2.0",
|
"phpseclib/phpseclib": "^2.0",
|
||||||
"paragonie/constant_time_encoding": "^2.0",
|
"paragonie/constant_time_encoding": "^2.0",
|
||||||
"paragonie/random_compat": "^2.0"
|
"paragonie/random_compat": "^2.0",
|
||||||
|
"php": ">=5.6.0"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Daniil Gentili",
|
"name": "Daniil Gentili",
|
||||||
"email": "daniil@daniil.it"
|
"email": "daniil@daniil.it"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"minimum-stability": "stable"
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"danog\\MadelineProto\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
20
src/danog/MadelineProto/API.php
Normal file
20
src/danog/MadelineProto/API.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
|
class API {
|
||||||
|
public $session;
|
||||||
|
public function __construct($login, $params = []) {
|
||||||
|
$this->session = new Session($params);
|
||||||
|
$this->session->create_auth_key();
|
||||||
|
$future_salts = $this->session->method_call('get_future_salts', 3);
|
||||||
|
pyjslib_printnl($future_salts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
unset($this->session);
|
||||||
|
}
|
||||||
|
public function __call($name, $arguments) {
|
||||||
|
return $session->method_call($name, $arguments);
|
||||||
|
}
|
||||||
|
}
|
14
src/danog/MadelineProto/Exception.php
Normal file
14
src/danog/MadelineProto/Exception.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
|
class Exception extends \Exception {
|
||||||
|
public function __construct($message, $code = 0, Exception $previous = null)
|
||||||
|
{
|
||||||
|
// some code
|
||||||
|
if (isset($GLOBALS['doingphptests']) && $GLOBALS['doingphptests']) {
|
||||||
|
var_dump($message);
|
||||||
|
}
|
||||||
|
// make sure everything is assigned properly
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
0
src/danog/MadelineProto/RSA.php
Normal file
0
src/danog/MadelineProto/RSA.php
Normal file
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
||||||
require_once 'libpy2php.php';
|
require_once 'libpy2php.php';
|
||||||
$__author__ = 'agrigoryev';
|
|
||||||
require_once 'os.php';
|
require_once 'os.php';
|
||||||
|
namespace danog\MadelineProto;
|
||||||
class TlConstructor
|
class TlConstructor
|
||||||
{
|
{
|
||||||
public function __construct($json_dict)
|
public function __construct($json_dict)
|
63
src/danog/MadelineProto/connection.php
Normal file
63
src/danog/MadelineProto/connection.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
namespace danog\MadelineProto;
|
||||||
|
/**
|
||||||
|
* Manages connection to telegram servers.
|
||||||
|
*/
|
||||||
|
class Connection
|
||||||
|
{
|
||||||
|
private $sock = null;
|
||||||
|
private $protocol = null;
|
||||||
|
public function __construct($ip, $port, $protocol = 'tcp') {
|
||||||
|
switch ($protocol) {
|
||||||
|
case 'tcp':
|
||||||
|
$this->sock = fsockopen('tcp://'.$ip.':'.$port);
|
||||||
|
$this->protocol = "tcp";
|
||||||
|
stream_set_timeout($this->sock, 5);
|
||||||
|
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
|
||||||
|
throw new Exception("Connection: couldn't connect to socket.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Connection: invalid protocol specified.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function __destruct() {
|
||||||
|
switch ($this->protocol) {
|
||||||
|
case 'tcp':
|
||||||
|
fclose($this->sock);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Connection: invalid protocol specified.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public function write($what, $length = null) {
|
||||||
|
$what = substr($what, 0, $length);
|
||||||
|
switch ($this->protocol) {
|
||||||
|
case 'tcp':
|
||||||
|
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
|
||||||
|
throw new Exception("Connection: couldn't connect to socket.");
|
||||||
|
}
|
||||||
|
return fwrite($this->sock, $what);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Connection: invalid protocol specified.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function read($length) {
|
||||||
|
switch ($this->protocol) {
|
||||||
|
case 'tcp':
|
||||||
|
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
|
||||||
|
throw new Exception("Connection: couldn't connect to socket.");
|
||||||
|
}
|
||||||
|
return fread($this->sock, $length);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Connection: invalid protocol specified.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/danog/MadelineProto/debug_functions.php
Normal file
39
src/danog/MadelineProto/debug_functions.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to dump the hex version of a string.
|
||||||
|
*
|
||||||
|
* @param $what What to dump.
|
||||||
|
*/
|
||||||
|
function hex_dump(...$what)
|
||||||
|
{
|
||||||
|
foreach ($what as $w) {
|
||||||
|
var_dump(bin2hex($w));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to visualize byte streams. Split into bytes, print to console.
|
||||||
|
* :param bs: BYTE STRING.
|
||||||
|
*/
|
||||||
|
function vis($bs)
|
||||||
|
{
|
||||||
|
$bs = str_split($bs);
|
||||||
|
$symbols_in_one_line = 8;
|
||||||
|
$n = floor(len($bs) / $symbols_in_one_line);
|
||||||
|
$i = 0;
|
||||||
|
foreach (pyjslib_range($n) as $i) {
|
||||||
|
echo $i * $symbols_in_one_line.' | '.implode(' ',
|
||||||
|
array_map(function ($el) {
|
||||||
|
return bin2hex($el);
|
||||||
|
}, array_slice($bs, $i * $symbols_in_one_line, ($i + 1) * $symbols_in_one_line))
|
||||||
|
).PHP_EOL;
|
||||||
|
}
|
||||||
|
if (len($bs) % $symbols_in_one_line != 0) {
|
||||||
|
echo($i + 1) * $symbols_in_one_line.' | '.implode(' ',
|
||||||
|
array_map(function ($el) {
|
||||||
|
return bin2hex($el);
|
||||||
|
}, array_slice($bs, ($i + 1) * $symbols_in_one_line))
|
||||||
|
).PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
@ -3,147 +3,62 @@
|
|||||||
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
||||||
require_once 'libpy2php.php';
|
require_once 'libpy2php.php';
|
||||||
require_once 'os_path.php';
|
require_once 'os_path.php';
|
||||||
require_once 'crypt.php';
|
|
||||||
require_once 'prime.php';
|
namespace danog\MadelineProto;
|
||||||
require_once 'TL.php';
|
|
||||||
require_once 'vendor/autoload.php';
|
|
||||||
$struct = new \danog\PHP\StructClass();
|
|
||||||
/**
|
/**
|
||||||
* Function to get hex crc32
|
* Manages encryption and message frames.
|
||||||
* :param data: Data to encode.
|
|
||||||
*/
|
*/
|
||||||
function newcrc32($data)
|
class Session extends Tools
|
||||||
{
|
{
|
||||||
return hexdec(hash('crc32b', $data));
|
public $settings = [];
|
||||||
}
|
public function __construct($settings)
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to dump the hex version of a string.
|
|
||||||
*
|
|
||||||
* @param $what What to dump.
|
|
||||||
*/
|
|
||||||
function hex_dump(...$what)
|
|
||||||
{
|
|
||||||
foreach ($what as $w) {
|
|
||||||
var_dump(bin2hex($w));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* len.
|
|
||||||
*
|
|
||||||
* Get the length of a string or of an array
|
|
||||||
*
|
|
||||||
* @param $input String or array to parse
|
|
||||||
*
|
|
||||||
* @return int with the length
|
|
||||||
**/
|
|
||||||
function len($input)
|
|
||||||
{
|
|
||||||
if (is_array($input)) {
|
|
||||||
return count($input);
|
|
||||||
}
|
|
||||||
|
|
||||||
return strlen($input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to visualize byte streams. Split into bytes, print to console.
|
|
||||||
* :param bs: BYTE STRING.
|
|
||||||
*/
|
|
||||||
function vis($bs)
|
|
||||||
{
|
|
||||||
$bs = str_split($bs);
|
|
||||||
$symbols_in_one_line = 8;
|
|
||||||
$n = floor(len($bs) / $symbols_in_one_line);
|
|
||||||
$i = 0;
|
|
||||||
foreach (pyjslib_range($n) as $i) {
|
|
||||||
echo $i * $symbols_in_one_line.' | '.implode(' ',
|
|
||||||
array_map(function ($el) {
|
|
||||||
return bin2hex($el);
|
|
||||||
}, array_slice($bs, $i * $symbols_in_one_line, ($i + 1) * $symbols_in_one_line))
|
|
||||||
).PHP_EOL;
|
|
||||||
}
|
|
||||||
if (len($bs) % $symbols_in_one_line != 0) {
|
|
||||||
echo($i + 1) * $symbols_in_one_line.' | '.implode(' ',
|
|
||||||
array_map(function ($el) {
|
|
||||||
return bin2hex($el);
|
|
||||||
}, array_slice($bs, ($i + 1) * $symbols_in_one_line))
|
|
||||||
).PHP_EOL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* posmod(numeric,numeric) : numeric
|
|
||||||
* Works just like the % (modulus) operator, only returns always a postive number.
|
|
||||||
*/
|
|
||||||
function posmod($a, $b)
|
|
||||||
{
|
|
||||||
$resto = $a % $b;
|
|
||||||
if ($resto < 0) {
|
|
||||||
$resto += abs($b);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $resto;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fread_all($handle)
|
|
||||||
{
|
|
||||||
$pos = ftell($handle);
|
|
||||||
fseek($handle, 0);
|
|
||||||
$content = fread($handle, fstat($handle)['size']);
|
|
||||||
fseek($handle, $pos);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
function fopen_and_write($filename, $mode, $data)
|
|
||||||
{
|
|
||||||
$handle = fopen($filename, $mode);
|
|
||||||
fwrite($handle, $data);
|
|
||||||
rewind($handle);
|
|
||||||
|
|
||||||
return $handle;
|
|
||||||
}
|
|
||||||
function string2bin($string)
|
|
||||||
{
|
|
||||||
$res = null;
|
|
||||||
foreach (explode('\\', $string) as $s) {
|
|
||||||
if ($s != null && strlen($s) == 3) {
|
|
||||||
$res .= hex2bin(substr($s, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Manages TCP Transport. encryption and message frames.
|
|
||||||
*/
|
|
||||||
class Session
|
|
||||||
{
|
|
||||||
public function __construct($ip, $port, $auth_key = null, $server_salt = null)
|
|
||||||
{
|
{
|
||||||
$this->sock = fsockopen('tcp://'.$ip.':'.$port);
|
// Set default settings
|
||||||
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
|
$default_settings = ["ip" => "149.154.167.50", "port" => "443", "protocol" => "tcp", "auth_key" => null, "server_salt" => null, "api_id" => 25628, "api_hash" => "1fe17cda7d355166cdaa71f04122873c", "tl_schema" => 'https://core.telegram.org/schema/mtproto-json', "rsa_pub" => __DIR__.'/rsa.pub'];
|
||||||
throw new Exception("Couldn't connect to socket.");
|
foreach ($default_settings as $key => $param) {
|
||||||
|
if(!isset($settings[$key])) {
|
||||||
|
$settings[$key] = $param;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$this->number = 0;
|
$this->settings = $settings;
|
||||||
$this->timedelta = 0;
|
|
||||||
$this->session_id = \phpseclib\Crypt\Random::string(8);
|
// Connect to servers
|
||||||
$this->auth_key = $auth_key;
|
$this->sock = new Connection($this->settings["ip_address"], $this->settings["ip_address"], $this->settings["protocol"]);
|
||||||
$this->auth_key_id = $this->auth_key ? substr(sha1($this->auth_key, true), -8) : null;
|
|
||||||
stream_set_timeout($this->sock, 5);
|
// Istantiate struct class
|
||||||
$this->MAX_RETRY = 5;
|
|
||||||
$this->AUTH_MAX_RETRY = 5;
|
|
||||||
$this->struct = new \danog\PHP\Struct();
|
$this->struct = new \danog\PHP\Struct();
|
||||||
|
// Istantiate prime class
|
||||||
$this->PrimeModule = new PrimeModule();
|
$this->PrimeModule = new PrimeModule();
|
||||||
|
// Istantiate TL class
|
||||||
try {
|
try {
|
||||||
$this->tl = new TL('https://core.telegram.org/schema/mtproto-json');
|
$this->tl = new TL($this->settings["tl_schema"]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->tl = new TL(__DIR__.'/TL_schema.JSON');
|
$this->tl = new TL(__DIR__.'/TL_schema.JSON');
|
||||||
}
|
}
|
||||||
|
// Load rsa key
|
||||||
|
$this->settings["rsa_content"] = file_get_contents($this->rsa_pub);
|
||||||
|
|
||||||
|
// Set some defaults
|
||||||
|
$this->number = 0;
|
||||||
|
$this->timedelta = 0;
|
||||||
|
$this->session_id = \phpseclib\Crypt\Random::string(8);
|
||||||
|
if(isset($this->settings["auth_key"])) $this->auth_key = $this->settings["auth_key"];
|
||||||
|
$this->auth_key_id = $this->auth_key ? substr(sha1($this->auth_key, true), -8) : null;
|
||||||
|
$this->MAX_RETRY = 5;
|
||||||
|
$this->AUTH_MAX_RETRY = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
fclose($this->sock);
|
unset($this->sock);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Function to get hex crc32
|
||||||
|
* @param $data Data to encode.
|
||||||
|
*/
|
||||||
|
function newcrc32($data)
|
||||||
|
{
|
||||||
|
return hexdec(hash('crc32b', $data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +81,7 @@ class Session
|
|||||||
$message = $this->auth_key_id.$message_key.crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
$message = $this->auth_key_id.$message_key.crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
||||||
}
|
}
|
||||||
$step1 = $this->struct->pack('<II', (strlen($message) + 12), $this->number).$message;
|
$step1 = $this->struct->pack('<II', (strlen($message) + 12), $this->number).$message;
|
||||||
$step2 = $step1.$this->struct->pack('<I', newcrc32($step1));
|
$step2 = $step1.$this->struct->pack('<I', $this->newcrc32($step1));
|
||||||
fwrite($this->sock, $step2);
|
fwrite($this->sock, $step2);
|
||||||
$this->number += 1;
|
$this->number += 1;
|
||||||
}
|
}
|
||||||
@ -177,13 +92,13 @@ class Session
|
|||||||
public function recv_message()
|
public function recv_message()
|
||||||
{
|
{
|
||||||
$packet_length_data = fread($this->sock, 4);
|
$packet_length_data = fread($this->sock, 4);
|
||||||
if (len($packet_length_data) < 4) {
|
if (strlen($packet_length_data) < 4) {
|
||||||
throw new Exception('Nothing in the socket!');
|
throw new Exception('Nothing in the socket!');
|
||||||
}
|
}
|
||||||
$packet_length = $this->struct->unpack('<I', $packet_length_data)[0];
|
$packet_length = $this->struct->unpack('<I', $packet_length_data)[0];
|
||||||
var_dump($packet_length);
|
var_dump($packet_length);
|
||||||
$packet = fread($this->sock, ($packet_length - 4));
|
$packet = fread($this->sock, ($packet_length - 4));
|
||||||
if (!(newcrc32($packet_length_data.substr($packet, 0, -4)) == $this->struct->unpack('<I', substr($packet, -4))[0])) {
|
if (!($this->newcrc32($packet_length_data.substr($packet, 0, -4)) == $this->struct->unpack('<I', substr($packet, -4))[0])) {
|
||||||
throw new Exception('CRC32 was not correct!');
|
throw new Exception('CRC32 was not correct!');
|
||||||
}
|
}
|
||||||
$x = $this->struct->unpack('<I', substr($packet, 0, 4));
|
$x = $this->struct->unpack('<I', substr($packet, 0, 4));
|
||||||
@ -236,9 +151,8 @@ class Session
|
|||||||
public function create_auth_key()
|
public function create_auth_key()
|
||||||
{
|
{
|
||||||
// Load the RSA key
|
// Load the RSA key
|
||||||
$f = file_get_contents(__DIR__.'/rsa.pub');
|
|
||||||
$key = new \phpseclib\Crypt\RSA();
|
$key = new \phpseclib\Crypt\RSA();
|
||||||
$key->load($f);
|
$key->load($settings["rsa_content"]);
|
||||||
|
|
||||||
// Make pq request
|
// Make pq request
|
||||||
$nonce = \phpseclib\Crypt\Random::string(16);
|
$nonce = \phpseclib\Crypt\Random::string(16);
|
52
src/danog/MadelineProto/tools.php
Normal file
52
src/danog/MadelineProto/tools.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some tools
|
||||||
|
*/
|
||||||
|
class Tools {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* posmod(numeric,numeric) : numeric
|
||||||
|
* Works just like the % (modulus) operator, only returns always a postive number.
|
||||||
|
*/
|
||||||
|
function posmod($a, $b)
|
||||||
|
{
|
||||||
|
$resto = $a % $b;
|
||||||
|
if ($resto < 0) {
|
||||||
|
$resto += abs($b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $resto;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fread_all($handle)
|
||||||
|
{
|
||||||
|
$pos = ftell($handle);
|
||||||
|
fseek($handle, 0);
|
||||||
|
$content = fread($handle, fstat($handle)['size']);
|
||||||
|
fseek($handle, $pos);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
function fopen_and_write($filename, $mode, $data)
|
||||||
|
{
|
||||||
|
$handle = fopen($filename, $mode);
|
||||||
|
fwrite($handle, $data);
|
||||||
|
rewind($handle);
|
||||||
|
|
||||||
|
return $handle;
|
||||||
|
}
|
||||||
|
function string2bin($string)
|
||||||
|
{
|
||||||
|
$res = null;
|
||||||
|
foreach (explode('\\', $string) as $s) {
|
||||||
|
if ($s != null && strlen($s) == 3) {
|
||||||
|
$res .= hex2bin(substr($s, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
16
testing.php
16
testing.php
@ -1,17 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
require_once 'vendor/autoload.php';
|
||||||
require_once 'libpy2php.php';
|
|
||||||
require_once 'os.php';
|
|
||||||
require_once 'mtproto.php';
|
|
||||||
$config = parse_ini_file('credentials', true);
|
$config = parse_ini_file('credentials', true);
|
||||||
if (!$config) {
|
if (!$config) {
|
||||||
pyjslib_printnl('File \'credentials\' seems to not exist.');
|
pyjslib_printnl("File 'credentials' seems to not exist.");
|
||||||
$exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
$ip = $config['App data']['ip_address'];
|
$MadelineProto = new \danog\MadelineProto\API("393888288264", $config);
|
||||||
$port = $config['App data']['port'];
|
|
||||||
$Session = new Session($ip, $port);
|
|
||||||
$Session->create_auth_key();
|
|
||||||
$future_salts = $Session->method_call('get_future_salts', 3);
|
|
||||||
pyjslib_printnl($future_salts);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user