127 lines
4.8 KiB
Python
127 lines
4.8 KiB
Python
import base64
|
|
import hashlib
|
|
import json
|
|
|
|
from aiohttp import web
|
|
|
|
from config import HELEKET_API_KEY, HELEKET_CURRENCY_RATE
|
|
from database import add_payment, async_session_maker, update_balance
|
|
from handlers.payments.utils import send_payment_success_notification
|
|
from logger import logger
|
|
|
|
|
|
processed_payments = set()
|
|
|
|
|
|
async def heleket_payment_webhook(request: web.Request):
|
|
"""
|
|
Обработчик вебхука от Heleket для подтверждения оплаты
|
|
"""
|
|
try:
|
|
data = await request.json()
|
|
|
|
logger.info(f"Heleket webhook received from {request.remote}")
|
|
logger.info(f"Heleket webhook data: {data}")
|
|
|
|
signature = data.get("sign", "")
|
|
if not verify_heleket_webhook_signature(data, signature):
|
|
logger.error("Heleket: Invalid signature")
|
|
return web.Response(status=400, text="Invalid signature")
|
|
|
|
uuid = data.get("uuid")
|
|
order_id = data.get("order_id")
|
|
payment_status = data.get("status")
|
|
amount = data.get("amount")
|
|
payment_amount = data.get("payment_amount")
|
|
additional_data = data.get("additional_data", "")
|
|
|
|
logger.info(
|
|
f"Heleket payment: uuid={uuid}, order_id={order_id}, status={payment_status}, amount={amount}, payment_amount={payment_amount}"
|
|
)
|
|
|
|
if payment_status != "paid":
|
|
logger.info(f"Heleket: Payment not completed, status={payment_status}")
|
|
return web.Response(status=200, text="OK")
|
|
|
|
if not amount or not uuid:
|
|
logger.error("Heleket: Missing amount or uuid")
|
|
return web.Response(status=400, text="Missing required fields")
|
|
|
|
if uuid in processed_payments:
|
|
logger.warning(f"Heleket: Duplicate payment uuid={uuid}")
|
|
return web.Response(status=200, text="OK")
|
|
|
|
if order_id and order_id in processed_payments:
|
|
logger.warning(f"Heleket: Duplicate payment order_id={order_id}")
|
|
return web.Response(status=200, text="OK")
|
|
|
|
tg_id = None
|
|
rub_amount = None
|
|
try:
|
|
if additional_data and "tg_id:" in additional_data:
|
|
parts = additional_data.split(",")
|
|
for part in parts:
|
|
if part.startswith("tg_id:"):
|
|
tg_id = int(part.split("tg_id:")[1])
|
|
elif part.startswith("rub_amount:"):
|
|
rub_amount = float(part.split("rub_amount:")[1])
|
|
|
|
elif order_id and "_" in order_id:
|
|
tg_id = int(order_id.split("_")[1])
|
|
usd_amount = float(amount)
|
|
rub_amount = usd_amount * HELEKET_CURRENCY_RATE
|
|
else:
|
|
logger.error("Heleket: Cannot extract tg_id from data")
|
|
return web.Response(status=400, text="Cannot extract user ID")
|
|
|
|
except (ValueError, IndexError) as e:
|
|
logger.error(f"Heleket: Error extracting tg_id or rub_amount: {e}")
|
|
return web.Response(status=400, text="Invalid user ID or amount format")
|
|
|
|
if not rub_amount:
|
|
logger.error("Heleket: Could not determine rub_amount")
|
|
return web.Response(status=400, text="Cannot determine amount")
|
|
|
|
async with async_session_maker() as session:
|
|
await update_balance(session, tg_id, rub_amount)
|
|
await send_payment_success_notification(tg_id, rub_amount, session)
|
|
await add_payment(session, tg_id, rub_amount, "heleket")
|
|
|
|
processed_payments.add(uuid)
|
|
if order_id:
|
|
processed_payments.add(order_id)
|
|
|
|
logger.info(f"✅ Heleket: Payment processed for user {tg_id}, amount {rub_amount} RUB (${amount}), uuid={uuid}")
|
|
return web.Response(status=200, text="OK")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Heleket webhook error: {e}")
|
|
return web.Response(status=500, text="Internal server error")
|
|
|
|
|
|
def verify_heleket_webhook_signature(data: dict, signature: str) -> bool:
|
|
"""
|
|
Проверка подписи вебхука Heleket
|
|
"""
|
|
try:
|
|
data_without_sign = {k: v for k, v in data.items() if k != "sign"}
|
|
|
|
json_data = json.dumps(data_without_sign, separators=(",", ":"))
|
|
base64_data = base64.b64encode(json_data.encode("utf-8")).decode("utf-8")
|
|
sign_string = base64_data + HELEKET_API_KEY
|
|
expected_signature = hashlib.md5(sign_string.encode("utf-8")).hexdigest()
|
|
|
|
result = signature.upper() == expected_signature.upper()
|
|
|
|
if not result:
|
|
logger.error("Heleket webhook signature mismatch")
|
|
logger.error(f"Expected: {expected_signature}, Got: {signature}")
|
|
logger.error(f"Base64 data: {base64_data}")
|
|
logger.error(f"Sign string: {sign_string}")
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
logger.error(f"Heleket signature verification error: {e}")
|
|
return False
|