0

I have problem with this method in my telegram mini app: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app

When client trying to log in into my mini app frontend sends check string like in article, i'm generating hash string on backend to check client log in with this function

import json
import urllib.parse
import hmac
import hashlib

def verify_telegram_webapp_data(telegram_init_data: str, bot_token: str) -> bool:
    init_data = json.loads(urllib.parse.unquote(telegram_init_data))
    if "hash" not in init_data:
        return False

    hash_ = init_data.pop('hash')

    data_to_check_parts = []
    for key, value in sorted(init_data.items()):
        if isinstance(value, dict):
            value = json.dumps(value, separators=(',', ':'), ensure_ascii=False)
        data_to_check_parts.append(f"{key}={value}")
    
    data_to_check = "\n".join(data_to_check_parts)

    secret_key = hmac.new(bot_token.encode(), 'WebAppData'.encode(), hashlib.sha256).digest()
    computed_hash = hmac.new(data_to_check.encode(), secret_key, hashlib.sha256).hexdigest()

    print('Data to check:', data_to_check)
    print('Computed hash:', computed_hash)
    print('Provided hash:', hash_)
    
    return computed_hash == hash_

Before telegram added photo_url into their data - this code worked fine, but now it doesn't work - provided hash and computed hash are different

I've tryed to change photo_url, deletу it, but the result is the same...

3 Answers 3

0

I ran into the same issue, here’s my code in JS:

 const verifyDataIntegrity = (object, { key, hash }) => {
    // Проверяем, что object является объектом, и что key и hash не пустые
    if (typeof object !== "object" || object === null || !key || !hash)
        throw new Error("Invalid arguments for data integrity verification");

    // Сортируем ключи объекта и преобразуем его в строку в формате ключ=значение, разделенные символом новой строки
    const dataCheckString = Object.entries(object).sort().map(([k, v]) => {
        // Если значение является объектом, преобразуем его в строку JSON
        if (typeof v === "object" && v !== null) {
            v = JSON.stringify(v);
        }

        // Возвращаем строку в формате ключ=значение
        return `${k}=${v}`;
    }).join("\n");

    // Создаем хеш из строки для проверки
    const calculatedHash = crypto.createHmac("sha256", key).update(dataCheckString).digest("hex");

    // Сравниваем полученный хеш с хешем из данных
    return cryptoUtils.timingSafeEqual(calculatedHash, hash);
};
Sign up to request clarification or add additional context in comments.

Comments

0

did you guys fix that?

const secretKey = Hmac256Util.generateHmac(
  process.env.key,
  'WebAppData',
);
const dataHex = Hmac256Util.generateHmac(dataCheckString, secretKey);

Comments

0

The solution was really simple - you just need to replace "/" symbol in photo_url to "/" Python:

data_check_string = data_check_string.replace("/", "\/")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.