Files

289 lines
11 KiB
PHP
Executable File

<?php
require_once 'config.php';
$webhook_hash = hash_hmac('sha256', BOT_TOKEN, HMAC_SECRET);
if ($_GET['_set_webhook']) {
// Open webhook.php?_set_webhook=1 to set up webhook
$webhook_url = BASE_URL.'webhook.php?hash='.$webhook_hash;
$result = botApiInvoke('setWebhook', [
'url' => $webhook_url,
]);
echo $result['ok'] ? 'Success' : 'Fail';
exit;
}
if ($_GET['hash'] !== $webhook_hash) {
// Invalid webhook url
exit;
}
$raw_post_data = file_get_contents('php://input');
$update = json_decode($raw_post_data, true);
if (!isset($update['message']['passport_data'])) {
// Supports passport_data update only
exit;
}
$passport_data = $update['message']['passport_data'];
$credentials = $passport_data['credentials'];
$secret_encrypted = base64_decode($credentials['secret']);
$result = openssl_private_decrypt($secret_encrypted, $credentials_secret, BOT_PRIVATE_KEY, OPENSSL_PKCS1_OAEP_PADDING);
if (!$result) {
// Credential secret decryption failed
exit;
}
try {
$credentials_data_encrypted = base64_decode($credentials['data']);
$credentials_hash = base64_decode($credentials['hash']);
$credentials_data_json = decryptData($credentials_data_encrypted, $credentials_secret, $credentials_hash);
$credentials_data = json_decode($credentials_data_json, true);
if (!isset($credentials_data['secure_data']) ||
!isset($credentials_data['nonce'])) {
throw new Exception('CREDENTIALS_FORMAT_INVALID');
}
$secure_data = $credentials_data['secure_data'];
$nonce = $credentials_data['nonce'];
if (!preg_match('/^[0-9a-f]{64}$/', $nonce)) {
throw new Exception('NONCE_INVALID');
}
foreach ($passport_data['data'] as &$passport_data_item) {
$field_name = $passport_data_item['type'];
if (isset($secure_data[$field_name])) {
$secure_data_item = $secure_data[$field_name];
if (isset($secure_data_item['data']) &&
isset($passport_data_item['data'])) {
$value_credentials = $secure_data_item['data'];
$value_hash = base64_decode($value_credentials['data_hash']);
$value_secret = base64_decode($value_credentials['secret']);
$data_encrypted = base64_decode($passport_data_item['data']);
$value_data = decryptData($data_encrypted, $value_secret, $value_hash);
$value_data_json = json_decode($value_data, true);
$passport_data_item['data'] = $value_data_json;
}
if (isset($secure_data[$field_name]['front_side']) &&
isset($passport_data_item['front_side'])) {
$file_data = $passport_data_item['front_side'];
$file_id = $file_data['file_id'];
$file_encrypted = botApiGetFileContentsByFileId($file_id);
if ($file_encrypted !== false) {
$file_credentials = $secure_data[$field_name]['front_side'];
$file_hash = base64_decode($file_credentials['file_hash']);
$file_secret = base64_decode($file_credentials['secret']);
$file_content = decryptData($file_encrypted, $file_secret, $file_hash);
$file_local_path = md5($file_id).'.jpg';
unset($file_data['file_path']);
if (file_put_contents(FILES_DIR.$file_local_path, $file_content)) {
$file_data['file_url'] = FILES_BASE_URL.$file_local_path;
}
$file_data['file_hash'] = $file_credentials['file_hash'];
$passport_data_item['front_side'] = $file_data;
}
}
if (isset($secure_data[$field_name]['reverse_side']) &&
isset($passport_data_item['reverse_side'])) {
$file_data = $passport_data_item['reverse_side'];
$file_id = $file_data['file_id'];
$file_encrypted = botApiGetFileContentsByFileId($file_id);
if ($file_encrypted !== false) {
$file_credentials = $secure_data[$field_name]['reverse_side'];
$file_hash = base64_decode($file_credentials['file_hash']);
$file_secret = base64_decode($file_credentials['secret']);
$file_content = decryptData($file_encrypted, $file_secret, $file_hash);
$file_local_path = md5($file_id).'.jpg';
unset($file_data['file_path']);
if (file_put_contents(FILES_DIR.$file_local_path, $file_content)) {
$file_data['file_url'] = FILES_BASE_URL.$file_local_path;
}
$file_data['file_hash'] = $file_credentials['file_hash'];
$passport_data_item['reverse_side'] = $file_data;
}
}
if (isset($secure_data[$field_name]['selfie']) &&
isset($passport_data_item['selfie'])) {
$file_data = $passport_data_item['selfie'];
$file_id = $file_data['file_id'];
$file_encrypted = botApiGetFileContentsByFileId($file_id);
if ($file_encrypted !== false) {
$file_credentials = $secure_data[$field_name]['selfie'];
$file_hash = base64_decode($file_credentials['file_hash']);
$file_secret = base64_decode($file_credentials['secret']);
$file_content = decryptData($file_encrypted, $file_secret, $file_hash);
$file_local_path = md5($file_id).'.jpg';
unset($file_data['file_path']);
if (file_put_contents(FILES_DIR.$file_local_path, $file_content)) {
$file_data['file_url'] = FILES_BASE_URL.$file_local_path;
}
$file_data['file_hash'] = $file_credentials['file_hash'];
$passport_data_item['selfie'] = $file_data;
}
}
if (isset($secure_data_item['files']) &&
isset($passport_data_item['files'])) {
foreach ($passport_data_item['files'] as $i => $file_data) {
$file_id = $file_data['file_id'];
$file_encrypted = botApiGetFileContentsByFileId($file_id);
if ($file_encrypted !== false) {
$file_credentials = $secure_data_item['files'][$i];
$file_hash = base64_decode($file_credentials['file_hash']);
$file_secret = base64_decode($file_credentials['secret']);
$file_content = decryptData($file_encrypted, $file_secret, $file_hash);
$file_local_path = md5($file_id).'.jpg';
unset($file_data['file_path']);
if (file_put_contents(FILES_DIR.$file_local_path, $file_content)) {
$file_data['file_url'] = FILES_BASE_URL.$file_local_path;
}
$file_data['file_hash'] = $file_credentials['file_hash'];
$passport_data_item['files'][$i] = $file_data;
}
}
}
if (isset($secure_data_item['translation']) &&
isset($passport_data_item['translation'])) {
foreach ($passport_data_item['translation'] as $i => $file_data) {
$file_id = $file_data['file_id'];
$file_encrypted = botApiGetFileContentsByFileId($file_id);
if ($file_encrypted !== false) {
$file_credentials = $secure_data_item['translation'][$i];
$file_hash = base64_decode($file_credentials['file_hash']);
$file_secret = base64_decode($file_credentials['secret']);
$file_content = decryptData($file_encrypted, $file_secret, $file_hash);
$file_local_path = md5($file_id).'.jpg';
unset($file_data['file_path']);
if (file_put_contents(FILES_DIR.$file_local_path, $file_content)) {
$file_data['file_url'] = FILES_BASE_URL.$file_local_path;
}
$file_data['file_hash'] = $file_credentials['file_hash'];
$passport_data_item['translation'][$i] = $file_data;
}
}
}
}
}
} catch (Exception $e) {
if (!isset($credentials_data['nonce']) ||
!preg_match('/^[0-9a-f]{64}$/', $credentials_data['nonce'])) {
// Nonce invalid
exit;
}
$nonce = $credentials_data['nonce'];
$passport_data = [
'error' => $e->getMessage(),
];
}
$passport_data['user'] = $update['message']['from'];
$passport_data['nonce'] = $nonce;
$MC->set('passport_data_'.$nonce, $passport_data);
exit;
// Functions
function decryptData($data_encrypted, $data_secret, $data_hash) {
$data_secret_hash = hash('sha512', $data_secret.$data_hash, true);
$data_key = substr($data_secret_hash, 0, 32);
$data_iv = substr($data_secret_hash, 32, 16);
$options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
$data_decrypted = openssl_decrypt($data_encrypted, 'aes-256-cbc', $data_key, $options, $data_iv);
if (!$data_decrypted) {
throw new Exception('DECRYPT_FAILED');
}
$data_decrypted_hash = hash('sha256', $data_decrypted, true);
if (strcmp($data_hash, $data_decrypted_hash)) {
throw new Exception('HASH_INVALID');
}
$padding_len = ord($data_decrypted[0]);
$data_decrypted = substr($data_decrypted, $padding_len);
return $data_decrypted;
}
function botApiInvoke($method, $params) {
$api_url = 'https://api.telegram.org/bot'.BOT_TOKEN;
$params_arr = [];
foreach ($params as $key => $val) {
if (!is_numeric($val) && !is_string($val)) {
$val = json_encode($val);
}
$params_arr[] = rawurlencode($key).'='.rawurlencode($val);
}
$query_string = implode('&', $params_arr);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $api_url.'/'.$method);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $query_string);
curl_setopt($curl, CURLOPT_VERBOSE, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
$response = curl_exec($curl);
$errno = curl_errno($curl);
$http_code = intval(curl_getinfo($curl, CURLINFO_HTTP_CODE));
if ($http_code >= 400) {
if ($http_code == 401) {
throw new Exception('ACCESS_TOKEN_INVALID');
}
throw new Exception('HTTP_ERROR_'.$http_code);
}
if ($errno) {
$error = curl_error($curl);
throw new Exception('CURL_ERROR: '.$error);
}
$result = json_decode($response, true);
if (!$result) {
throw new Exception('RESPONSE_JSON_INVALID');
}
return $result;
}
function botApiGetFileContents($file) {
$api_url = 'https://api.telegram.org/file/bot'.BOT_TOKEN;
$file_path = $file['file_path'];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $api_url.'/'.$file_path);
curl_setopt($curl, CURLOPT_HTTPGET, true);
curl_setopt($curl, CURLOPT_VERBOSE, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
$response = curl_exec($curl);
$errno = curl_errno($curl);
$http_code = intval(curl_getinfo($curl, CURLINFO_HTTP_CODE));
if ($http_code >= 400) {
if ($http_code == 401) {
throw new Exception('ACCESS_TOKEN_INVALID');
}
throw new Exception('HTTP_ERROR_'.$http_code);
}
if ($errno) {
$error = curl_error($curl);
throw new Exception('CURL_ERROR: '.$error);
}
return $response;
}
function botApiGetFileContentsByFileId($file_id) {
$response = botApiInvoke('getFile', ['file_id' => $file_id]);
if (!$response['ok']) {
return false;
}
$file = $response['result'];
$file_bytes = botApiGetFileContents($file);
return $file_bytes;
}
?>