from www import bp, csrf, app
from requests import get
from flask import render_template, Blueprint, request, jsonify
from json import loads
import hashlib
from bot import db
import hmac
from operator import itemgetter
from urllib.parse import parse_qsl
from os import getenv
from dotenv import load_dotenv
import datetime
from time import time
import jwt
from functools import wraps
load_dotenv()
SECRET_KEY = getenv('SECRET_KEY')
BOT_TOKEN = getenv('BOT_TOKEN')
def generate_token(user_id):
payload = {
'user_id': user_id,
'exp': datetime.datetime.now() + datetime.timedelta(hours=1)
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return token
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token or not token.startswith('Bearer '):
return jsonify({'message': 'Token is missing or invalid!'}), 403
try:
token = token.split('Bearer ')[1]
data = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
current_user_id = data['user_id']
except jwt.ExpiredSignatureError:
return jsonify({'message': 'Token has expired!'}), 403
except jwt.InvalidTokenError:
return jsonify({'message': 'Invalid token!'}), 403
return f(current_user_id, *args, **kwargs)
return decorated
def check_webapp_signature(token: str, init_data: str):
try:
parsed_data = dict(parse_qsl(init_data))
except ValueError:
return False
if "hash" not in parsed_data:
return False
hash_ = parsed_data.pop('hash')
data_check_string = "\n".join(
f"{k}={v}" for k, v in sorted(parsed_data.items(), key=itemgetter(0))
)
secret_key = hmac.new(
key=b"WebAppData", msg=token.encode(), digestmod=hashlib.sha256
)
calculated_hash = hmac.new(
key=secret_key.digest(), msg=data_check_string.encode(), digestmod=hashlib.sha256
).hexdigest()
if calculated_hash == hash_:
pairs = data_check_string.split('\n')
data_dict = dict(pair.split('=') for pair in pairs)
user_data = loads(data_dict['user'])
return user_data
@app.route('/', methods=['POST', 'GET'])
def init():
if request.method == 'GET':
print('g')
return render_template('init.html')
elif request.method == 'POST':
print('s')
auth_header = request.headers.get('Authorization')
print(auth_header)
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({'error': 'Authorization header missing or invalid'}), 400
init_data = auth_header.split('Bearer ')[1]
if not init_data:
return jsonify({'error': 'No initData provided'}), 400
res = check_webapp_signature(BOT_TOKEN, init_data)
if res is not False:
user = db.Users.query.filter_by(tg_id=int(res['id'])).first()
if user:
token = generate_token(res['id'])
html = render_template('index.html', user=user)
return jsonify({'html': html, 'token': token})
else:
return jsonify({'error': 'User not found'}), 404
else:
return jsonify({'error': 'Invalid init data'}), 400
это бэкэнд сервера, вкратце там настроен один марштрутизатор на адрес, при переходе на коренной адрес человеку возвращает такой шаблон init.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Market</title>
</head>
<body>
<div class="loading-container">
<div class="loader"></div>
<div class="loading-text">Loading, please wait...</div>
</div>
<style>
body, html {
height: 100%;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: #1e1f24;
font-family: Arial, sans-serif;
}
.loading-container {
text-align: center;
}
.loader {
border: 16px solid #f3f3f3;
border-top: 16px solid #f3ca47;
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
margin-top: 20px;
font-size: 18px;
color: #555;
}
</style>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<script src="../static/js/auth.js"></script>
</body>
</html>
также вот файл auth.js
var tg = window.Telegram.WebApp;
tg.expand();
tg.ready();
//const initData = tg.initData;
const initData = 'query_id=AAGZHZtrAAAAAJkdm2srP0rs&user=%7B%22id%22%3A1805327769%2C%22first_name%22%3A%22Valentin%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22psh_valentin%22%2C%22language_code%22%3A%22ru%22%2C%22allows_write_to_pm%22%3Atrue%7D&auth_date=1721550259&hash=8449f7f7e6b9be063aeade1b0b9f95f1d310ff97e4e44787835220a21e45ecdc'
document.addEventListener('DOMContentLoaded', function() {
if (initData) {
fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + initData
},
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
return response.json();
})
.then(data => {
const html = data.html;
localStorage.setItem('token', data.token);
document.open();
document.write(html);
document.close();
})
.catch((error) => {
console.error('Error:', error);
});
} else {
console.error('Not auth');
}
});
в этом файле и заключается вся проблема, как вы можете заметить, берётся инитдата от телеграма ( щас там для дебага используется заготовленная инитдата ), она отправляется на сервер, где создаётся токен и возвращается обратно человеку, но проблема в том, что пост запрос не выполняется и я получаю ошибку 400
auth.js:10
POST
127.0.0.1:5000 400 (BAD REQUEST)
(anonymous) @ auth.js:10
auth.js:31 Error: Error: Network response was not ok BAD REQUEST
at auth.js:19:23
(anonymous) @ auth.js:31
Promise.catch
(anonymous) @ auth.js:30
сижу и не могу понять, в чём проблема и почему запрос не получается отправить, просто всё бы нечего, но пост запрос воощбе не обрабатывается на сервере, гет запрос обрабатывается, человеку возвращает шаблон init.html, а пост запрос вообще не обрабатівается потому что как вы можете заметить первая строка там print('s') и она также не выводится, заранее спасибо за ответ