Crypto payment via Heleket

This commit is contained in:
Boris Kovalskii
2025-07-24 23:14:36 +10:00
committed by GitHub
parent 3b64b28b86
commit cfe8b2edcd
7 changed files with 508 additions and 9 deletions
+3
View File
@@ -7,13 +7,16 @@ from config import TBLOCKER_WEBHOOK_PATH
from .tblocker import tblocker_webhook
from .wata_payment import wata_payment_webhook
from .kassai_payment import kassai_payment_webhook
from .heleket_payment import heleket_payment_webhook
WATA_WEBHOOK_PATH = "/wata/webhook"
KASSAI_WEBHOOK_PATH = "/kassai/webhook"
HELEKET_WEBHOOK_PATH = "/heleket/webhook"
async def register_web_routes(router: UrlDispatcher) -> None:
router.add_post(TBLOCKER_WEBHOOK_PATH, tblocker_webhook)
router.add_post(WATA_WEBHOOK_PATH, wata_payment_webhook)
router.add_post(KASSAI_WEBHOOK_PATH, kassai_payment_webhook)
router.add_post(HELEKET_WEBHOOK_PATH, heleket_payment_webhook)
+121
View File
@@ -0,0 +1,121 @@
import hashlib
import base64
import json
from aiohttp import web
from database import add_payment, async_session_maker, update_balance
from handlers.payments.utils import send_payment_success_notification
from config import HELEKET_API_KEY, HELEKET_CURRENCY_RATE
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(f"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(f"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(f"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(f"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