Started to reorganize class

This commit is contained in:
danogentili 2016-08-07 23:23:10 +02:00
parent 09951563c1
commit 4a8826bdad
53 changed files with 250 additions and 152 deletions

View File

@ -1,5 +0,0 @@
localhost:80 {
fastcgi / 127.0.0.1:9001 {
index index.php
}
}

View File

@ -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/"
}
}
} }

View 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);
}
}

View 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);
}
}

View File

View 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)

View 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;
}
}
}

View 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;
}
}

View File

@ -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);

View 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;
}
}

View File

@ -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);