|
|
|
@ -20,83 +20,108 @@ namespace danog\MadelineProto\VoIP;
|
|
|
|
|
*/
|
|
|
|
|
trait AuthKeyHandler
|
|
|
|
|
{
|
|
|
|
|
private $temp_requested_calls = [];
|
|
|
|
|
private $calls = [];
|
|
|
|
|
|
|
|
|
|
public function accept_call($params)
|
|
|
|
|
{
|
|
|
|
|
$dh_config = $this->get_dh_config();
|
|
|
|
|
$phone_config = $this->method_call('phone.getCallConfig');
|
|
|
|
|
$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'] = substr(sha1($key['auth_key'], true), 16);
|
|
|
|
|
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
|
|
|
|
|
$this->calls[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => 65, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'protocol' => $params['protocol'], 'connection' => $params['connection'], 'alternative_connections' => $params['alternative_connections']];
|
|
|
|
|
//$this->calls[$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, 'layer' => 8, 'ttl' => PHP_INT_MAX, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0]];
|
|
|
|
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
|
|
|
|
$this->check_G($g_b, $dh_config['p']);
|
|
|
|
|
$this->handle_pending_updates();
|
|
|
|
|
}
|
|
|
|
|
public $REQUESTED = 0;
|
|
|
|
|
public $ACCEPTED = 1;
|
|
|
|
|
public $CONFIRMED = 2;
|
|
|
|
|
public $READY = 3;
|
|
|
|
|
private $emojis = ['😉', '😍', '😛', '😭', '😱', '😡', '😎', '😴', '😵', '😈', '😬', '😇', '😏', '👮', '👷', '💂', '👶', '👨', '👩', '👴', '👵', '😻', '😽', '🙀', '👺', '🙈', '🙉', '🙊', '💀', '👽', '💩', '🔥', '💥', '💤', '👂', '👀', '👃', '👅', '👄', '👍', '👎', '👌', '👊', '✌', '✋', '👐', '👆', '👇', '👉', '👈', '🙏', '👏', '💪', '🚶', '🏃', '💃', '👫', '👪', '👬', '👭', '💅', '🎩', '👑', '👒', '👟', '👞', '👠', '👕', '👗', '👖', '👙', '👜', '👓', '🎀', '💄', '💛', '💙', '💜', '💚', '💍', '💎', '🐶', '🐺', '🐱', '🐭', '🐹', '🐰', '🐸', '🐯', '🐨', '🐻', '🐷', '🐮', '🐗', '🐴', '🐑', '🐘', '🐼', '🐧', '🐥', '🐔', '🐍', '🐢', '🐛', '🐝', '🐜', '🐞', '🐌', '🐙', '🐚', '🐟', '🐬', '🐋', '🐐', '🐊', '🐫', '🍀', '🌹', '🌻', '🍁', '🌾', '🍄', '🌵', '🌴', '🌳', '🌞', '🌚', '🌙', '🌎', '🌋', '⚡', '☔', '❄', '⛄', '🌀', '🌈', '🌊', '🎓', '🎆', '🎃', '👻', '🎅', '🎄', '🎁', '🎈', '🔮', '🎥', '📷', '💿', '💻', '☎', '📡', '📺', '📻', '🔉', '🔔', '⏳', '⏰', '⌚', '🔒', '🔑', '🔎', '💡', '🔦', '🔌', '🔋', '🚿', '🚽', '🔧', '🔨', '🚪', '🚬', '💣', '🔫', '🔪', '💊', '💉', '💰', '💵', '💳', '✉', '📫', '📦', '📅', '📁', '✂', '📌', '📎', '✒', '✏', '📐', '📚', '🔬', '🔭', '🎨', '🎬', '🎤', '🎧', '🎵', '🎹', '🎻', '🎺', '🎸', '👾', '🎮', '🃏', '🎲', '🎯', '🏈', '🏀', '⚽', '⚾', '🎾', '🎱', '🏉', '🎳', '🏁', '🏇', '🏆', '🏊', '🏄', '☕', '🍼', '🍺', '🍷', '🍴', '🍕', '🍔', '🍟', '🍗', '🍱', '🍚', '🍜', '🍡', '🍳', '🍞', '🍩', '🍦', '🎂', '🍰', '🍪', '🍫', '🍭', '🍯', '🍎', '🍏', '🍊', '🍋', '🍒', '🍇', '🍉', '🍓', '🍑', '🍌', '🍐', '🍍', '🍆', '🍅', '🌽', '🏡', '🏥', '🏦', '⛪', '🏰', '⛺', '🏭', '🗻', '🗽', '🎠', '🎡', '⛲', '🎢', '🚢', '🚤', '⚓', '🚀', '✈', '🚁', '🚂', '🚋', '🚎', '🚌', '🚙', '🚗', '🚕', '🚛', '🚨', '🚔', '🚒', '🚑', '🚲', '🚠', '🚜', '🚦', '⚠', '🚧', '⛽', '🎰', '🗿', '🎪', '🎭', '🇯🇵', '🇰🇷', '🇩🇪', '🇨🇳', '🇺🇸', '🇫🇷', '🇪🇸', '🇮🇹', '🇷🇺', '🇬🇧', '1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '0⃣', '🔟', '❗', '❓', '♥', '♦', '💯', '🔗', '🔱', '🔴', '🔵', '🔶', '🔷'];
|
|
|
|
|
|
|
|
|
|
public function request_call($user)
|
|
|
|
|
{
|
|
|
|
|
$user = $this->get_info($user)['InputUser'];
|
|
|
|
|
\danog\MadelineProto\Logger::log(['Calling '.$user['user_id'].'...'], \danog\MadelineProto\Logger::VERBOSE);
|
|
|
|
|
$dh_config = $this->get_dh_config();
|
|
|
|
|
$phone_config = $this->method_call('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]);
|
|
|
|
|
\danog\MadelineProto\Logger::log(['Generating a...'], \danog\MadelineProto\Logger::VERBOSE);
|
|
|
|
|
$a = new \phpseclib\Math\BigInteger($this->random(256), 256);
|
|
|
|
|
$a = \phpseclib\Math\BigInteger::randomRange($this->two, $dh_config['p']->subtract($this->two));
|
|
|
|
|
\danog\MadelineProto\Logger::log(['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 = $this->method_call('phone.requestCall', ['user_id' => $user, 'g_a_hash' => hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => $this->settings['tl_schema']['layer'], 'max_layer' => $this->settings['tl_schema']['layer']]], ['datacenter' => $this->datacenter->curdc]);
|
|
|
|
|
$this->temp_requested_calls[$res['phone_call']['id']] = $a;
|
|
|
|
|
$this->calls[$res['phone_call']['id']] = ['status' => $this->REQUESTED, 'a' => $a, 'g_a' => $g_a];
|
|
|
|
|
$this->handle_pending_updates();
|
|
|
|
|
$this->get_updates_difference();
|
|
|
|
|
|
|
|
|
|
return $res['phone_call']['id'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function complete_call($params)
|
|
|
|
|
public function accept_call($params)
|
|
|
|
|
{
|
|
|
|
|
if ($this->call_status($params['id']) !== 1) {
|
|
|
|
|
\danog\MadelineProto\Logger::log(['Could not find and complete secret chat '.$params['id']]);
|
|
|
|
|
if ($this->settings['calls']['accept_calls'] === false) return false;
|
|
|
|
|
if (is_array($this->settings['calls']['accept_calls']) && !in_array($this->settings['calls']['accept_calls'])) return false;
|
|
|
|
|
if ($params['protocol']['udp_p2p'] && !$this->settings['calls']['allow_p2p']) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$dh_config = $this->get_dh_config();
|
|
|
|
|
\danog\MadelineProto\Logger::log(['Generating b...'], \danog\MadelineProto\Logger::VERBOSE);
|
|
|
|
|
$b = \phpseclib\Math\BigInteger::randomRange($this->two, $dh_config['p']->subtract($this->two));
|
|
|
|
|
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
|
|
|
|
$this->check_G($g_b, $dh_config['p']);
|
|
|
|
|
$this->calls[$res['phone_call']['id']] = ['status' => $this->ACCEPTED, 'b' => $b, 'g_a_hash' => $params['g_a_hash']];
|
|
|
|
|
$res = $this->method_call('phone.acceptCall', ['user_id' => $user, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => $this->settings['tl_schema']['layer'], 'max_layer' => $this->settings['tl_schema']['layer']]], ['datacenter' => $this->datacenter->curdc]);
|
|
|
|
|
$this->handle_pending_updates();
|
|
|
|
|
$this->get_updates_difference();
|
|
|
|
|
}
|
|
|
|
|
public function confirm_call($params)
|
|
|
|
|
{
|
|
|
|
|
if ($this->call_status($params['id']) !== $this->REQUESTED) {
|
|
|
|
|
\danog\MadelineProto\Logger::log(['Could not find and confirm call '.$params['id']]);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$dh_config = $this->get_dh_config();
|
|
|
|
|
$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->calls[$params['id']]['a'], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
|
|
|
|
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
|
|
|
|
|
$res = $this->method_call('phone.confirmCall', ['user_id' => $user, 'g_a' => $this->calls[$params['id']]['g_a']->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => $this->settings['tl_schema']['layer'], 'max_layer' => $this->settings['tl_schema']['layer']]], ['datacenter' => $this->datacenter->curdc]);
|
|
|
|
|
$key['visualization'] = '';
|
|
|
|
|
$length = new \phpseclib\Math\BigInteger(count($this->emojis));
|
|
|
|
|
foreach (str_split(strrev(substr(hash('sha256', $this->calls[$params['id']]['g_a']->toBytes().$key['auth_key'], true), 20)), 8) as $number) {
|
|
|
|
|
$key['visualization'] .= $this->emojis[(int)((new \phpseclib\Math\BigInteger($number, -256))->divide($length)[1]->toString())];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->calls[$params['id']] = ['status' => $this->READY, 'key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => $this->settings['tl_scheme']['layer'], 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'protocol' => $params['protocol']];
|
|
|
|
|
$this->handle_pending_updates();
|
|
|
|
|
}
|
|
|
|
|
public function complete_call($params) {
|
|
|
|
|
if ($this->call_status($params['id']) !== $this->ACCEPTED) {
|
|
|
|
|
\danog\MadelineProto\Logger::log(['Could not find and confirm call '.$params['id']]);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$dh_config = $this->get_dh_config();
|
|
|
|
|
if (hash('sha256', $key['g_a_or_b'], true) !== $this->calls[$params['id']]['g_a_hash']) {
|
|
|
|
|
throw new \danog\MadelineProto\SecurityException('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 = ['auth_key' => str_pad($params['g_a_or_b']->powMod($this->temp_requested_calls[$params['id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
|
|
|
|
|
unset($this->temp_requested_calls[$params['id']]);
|
|
|
|
|
$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);
|
|
|
|
|
if ($key['fingerprint'] !== $params['key_fingerprint']) {
|
|
|
|
|
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->calls[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => 65, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'protocol' => $params['protocol'], 'connection' => $params['connection'], 'alternative_connections' => $params['alternative_connections']];
|
|
|
|
|
$this->handle_pending_updates();
|
|
|
|
|
$key['visualization'] = '';
|
|
|
|
|
$length = new \phpseclib\Math\BigInteger(count($this->emojis));
|
|
|
|
|
foreach (str_split(strrev(substr(hash('sha256', $params['g_a_or_b']->toBytes().$key['auth_key'], true), 20)), 8) as $number) {
|
|
|
|
|
$key['visualization'] .= $this->emojis[(int)((new \phpseclib\Math\BigInteger($number, -256))->divide($length)[1]->toString())];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->calls[$params['id']] = ['status' => $this->READY, 'key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'layer' => $this->settings['tl_scheme']['layer'], 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'protocol' => $params['protocol']];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function call_status($id)
|
|
|
|
|
{
|
|
|
|
|
if (isset($this->calls[$id])) {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (isset($this->temp_requested_calls[$id])) {
|
|
|
|
|
return 1;
|
|
|
|
|
return $this->calls[$id]['status'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function get_secret_chat($chat)
|
|
|
|
|
public function get_call($chat)
|
|
|
|
|
{
|
|
|
|
|
return $this->calls[$chat];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|