Skip to content

Instantly share code, notes, and snippets.

@FabianPastor
Last active February 10, 2023 22:20
Show Gist options
  • Save FabianPastor/2f33e8512ae2e28975fc5f08e2b30e35 to your computer and use it in GitHub Desktop.
Save FabianPastor/2f33e8512ae2e28975fc5f08e2b30e35 to your computer and use it in GitHub Desktop.
Just a small Telegram Auth Data validator class for PHP.
<?php
// GET checkdata.php?auth_data={{string_auth_data}}
// POST checkdata.php -> DATA auth_data={{string_auth_data}}
// auth_data has to be the same string received by the javascript client.
require_once "TelegramWebValidator.php";
$data = $_GET["auth_data"] ?? $_POST["auth_data"] ?? null;
define('BOT_TOKEN', 'XXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXX'); // place bot token of your bot here
$telegramValidator = new SFPL\Telegram\WebValidator(BOT_TOKEN);
$returnValue = new \stdClass;
$returnValue->ok = false;
try {
if (empty($data)) {
throw new \Exception("Auth Data not found.");
}
$returnValue->data = $telegramValidator->checkWebappData($data);
//OR for login auth data
// $returnValue->data = $telegramValidator->checkLoginAuthData($data);
$returnValue->ok = true;
} catch (\Throwable $e) {
$returnValue->errorType = get_class($e);
$returnValue->error = $e->getCode();
$returnValue->description = $e->getMessage();
}
// header("Access-Control-Allow-Methods: GET");
// header("Access-Control-Allow-Origin: *");
header('Content-type: application/javascript;charset=utf-8');
echo json_encode($returnValue);
<?php
// TelegramWebValidator.php
namespace SFPL\Telegram;
class WebDataException extends \Exception{};
class WebValidator
{
private string $bottoken;
private int $time_to_expire = 86400;
public function __construct(string $bottoken, int $time_to_expire = null)
{
$this->bottoken = $bottoken;
if (!empty($time_to_expire)) {
$this->time_to_expire = $time_to_expire;
}
}
public function checkLoginAuthData(string $data): array
{
return $this->checkData($data, $this->secretKeyLogin());
}
public function checkWebappData(string $data): array
{
return $this->checkData($data, $this->secretKeyWebapp());
}
public function generateLoginAuthDataHash(array $data): string
{
return $this->generateHash($data, $this->secretKeyLogin());
}
public function generateWebAppDataHash(array $data): string
{
return $this->generateHash($data, $this->secretKeyWebapp());
}
public function generateHash(array $data, $secret_key){
$data_check_string = $this->dataSorting($data);
return hash_hmac('sha256', $data_check_string, $secret_key);
}
private function checkData(string $data, $secret_key): array
{
parse_str($data, $auth_data);
if (!isset($auth_data["hash"])) {
throw new WebDataException('Data hash not defined', 1);
}
if ($secret_key === false) {
throw new WebDataException('Invalid Secret key', 2);
}
$hash = $this->generateHash($auth_data, $secret_key);
if (!$this->validHashes($hash, $auth_data["hash"])) {
throw new WebDataException('Received data is not valid', 3);
}
if (!$this->validAuthDate($auth_data['auth_date'])) {
throw new WebDataException('Data is outdated', 4);
}
return $auth_data;
}
public function dataSorting(array $data): string
{
unset($data['hash']);
$data_check_arr = [];
foreach ($data as $key => $value) {
$data_check_arr[] = $key . '=' . $value;
}
sort($data_check_arr);
$data_check_string = implode("\n", $data_check_arr);
return $data_check_string;
}
private function secretKeyLogin()
{
return hash('sha256', $this->bottoken, true);
}
private function secretKeyWebapp()
{
return hash_hmac('sha256', $this->bottoken, "WebAppData", true);
}
public function validHashes($computed_hash, $provided_hash): bool
{
return (strcmp($computed_hash, $provided_hash) === 0);
}
public function validAuthDate($date): bool
{
return ((time() - $date) <= $this->time_to_expire);
}
public function sendMethod($object)
{
$response = json_decode(file_get_contents("https://api.telegram.org/bot{$this->bottoken}/", false, stream_context_create([
"http" => [
'method' => 'POST',
'header' => [
'Content-type: application/json',
],
'content' => json_encode($object),
"ignore_errors" => true,
]
])));
$response->query = $object;
return $response;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment