Initial commit: VPN Telegram bot (sanitized defaults)

This commit is contained in:
VPN Service
2026-07-26 23:21:41 +03:00
commit aaf04faa96
77 changed files with 33249 additions and 0 deletions
+233
View File
@@ -0,0 +1,233 @@
"""Сборка платёжных клиентов и публичный payload для админки."""
from __future__ import annotations
from typing import Any
from config import Settings, get_settings
from services.anypay import Anypay
from services.cryptopay import CryptoPay
from services.digiseller import Digiseller
from services.env_file import (
BOOL_ENV_KEYS,
PAYMENT_ENV_KEYS,
SECRET_ENV_KEYS,
env_file_path,
env_writable,
mask_secret,
upsert_env_keys,
)
from services.heleket import Heleket
from services.lava import Lava
def build_payment_clients(settings: Settings) -> dict[str, Any]:
return {
"cryptopay": CryptoPay(
settings.crypto_bot_token,
testnet=settings.crypto_pay_testnet,
),
"heleket": Heleket(
settings.heleket_merchant_id,
settings.heleket_api_key,
callback_url=settings.heleket_callback_url,
currency=settings.heleket_currency,
),
"digiseller": Digiseller(
settings.digiseller_seller_id,
settings.digiseller_api_key,
product_ids=settings.digiseller_product_ids,
pay_url=settings.digiseller_pay_url,
credit_from=settings.digiseller_credit_from,
),
"lava": Lava(
settings.lava_shop_id,
settings.lava_secret_key,
additional_key=settings.lava_additional_key,
hook_url=settings.lava_hook_url,
success_url=settings.lava_success_url,
fail_url=settings.lava_fail_url,
expire_minutes=settings.lava_expire_minutes,
),
"anypay": Anypay(
settings.anypay_api_id,
settings.anypay_api_key,
settings.anypay_project_id,
currency=settings.anypay_currency,
method=settings.anypay_method,
success_url=settings.anypay_success_url,
fail_url=settings.anypay_fail_url,
default_email=settings.anypay_email or "pay@anypay.local",
check_ip=settings.anypay_check_ip,
),
}
def apply_payment_runtime(app: Any, settings: Settings) -> dict[str, Any]:
clients = build_payment_clients(settings)
app["settings"] = settings
app["cryptopay"] = clients["cryptopay"]
app["heleket"] = clients["heleket"]
app["digiseller"] = clients["digiseller"]
app["lava"] = clients["lava"]
app["anypay"] = clients["anypay"]
inject = app.get("inject")
if inject is not None:
inject.settings = settings
inject.cryptopay = clients["cryptopay"]
inject.heleket = clients["heleket"]
inject.digiseller = clients["digiseller"]
inject.lava = clients["lava"]
inject.anypay = clients["anypay"]
return clients
def payments_public_dict(settings: Settings) -> dict[str, Any]:
path = env_file_path()
return {
"env_path": str(path),
"env_writable": env_writable(path),
"crypto": {
"enabled": bool(settings.crypto_bot_token),
"token_set": bool(settings.crypto_bot_token),
"token_hint": mask_secret(settings.crypto_bot_token),
"testnet": bool(settings.crypto_pay_testnet),
},
"heleket": {
"enabled": bool(settings.heleket_merchant_id and settings.heleket_api_key),
"merchant_id": settings.heleket_merchant_id,
"api_key_set": bool(settings.heleket_api_key),
"api_key_hint": mask_secret(settings.heleket_api_key),
"callback_url": settings.heleket_callback_url,
"currency": settings.heleket_currency or "RUB",
},
"lava": {
"enabled": bool(settings.lava_shop_id and settings.lava_secret_key),
"shop_id": settings.lava_shop_id,
"secret_key_set": bool(settings.lava_secret_key),
"secret_key_hint": mask_secret(settings.lava_secret_key),
"additional_key_set": bool(settings.lava_additional_key),
"additional_key_hint": mask_secret(settings.lava_additional_key),
"hook_url": settings.lava_hook_url,
"success_url": settings.lava_success_url,
"fail_url": settings.lava_fail_url,
"expire_minutes": settings.lava_expire_minutes,
},
"anypay": {
"enabled": bool(
settings.anypay_api_id
and settings.anypay_api_key
and settings.anypay_project_id
),
"api_id": settings.anypay_api_id,
"api_key_set": bool(settings.anypay_api_key),
"api_key_hint": mask_secret(settings.anypay_api_key),
"project_id": settings.anypay_project_id,
"currency": settings.anypay_currency or "RUB",
"method": settings.anypay_method,
"success_url": settings.anypay_success_url,
"fail_url": settings.anypay_fail_url,
"email": settings.anypay_email,
"check_ip": bool(settings.anypay_check_ip),
"notify_url": (
f"{settings.webapp_url.rstrip('/')}/api/payments/anypay"
if settings.webapp_url
else "/api/payments/anypay"
),
},
"digiseller": {
"enabled": bool(settings.digiseller_seller_id and settings.digiseller_api_key),
"seller_id": settings.digiseller_seller_id,
"api_key_set": bool(settings.digiseller_api_key),
"api_key_hint": mask_secret(settings.digiseller_api_key),
"product_ids": ",".join(str(x) for x in settings.digiseller_product_ids),
"pay_url": settings.digiseller_pay_url,
"credit_from": settings.digiseller_credit_from or "cnt_goods",
"callback_url": settings.digiseller_callback_url,
},
"stars": {
"enabled": bool(settings.stars_enabled),
"rub_per_star": settings.stars_rub_per_star,
},
"topup_code_pay_url": settings.topup_code_pay_url,
}
def _is_masked_placeholder(value: str) -> bool:
v = (value or "").strip()
if not v:
return True
return "" in v or "" in v or "..." in v
def apply_payments_body(body: dict[str, Any]) -> Settings:
"""Применить тело POST админки: .env + os.environ + новый Settings."""
updates: dict[str, str | None] = {}
mapping = {
"CRYPTO_BOT_TOKEN": body.get("crypto_bot_token"),
"CRYPTO_PAY_TESTNET": body.get("crypto_pay_testnet"),
"HELEKET_MERCHANT_ID": body.get("heleket_merchant_id"),
"HELEKET_API_KEY": body.get("heleket_api_key"),
"HELEKET_CALLBACK_URL": body.get("heleket_callback_url"),
"HELEKET_CURRENCY": body.get("heleket_currency"),
"LAVA_SHOP_ID": body.get("lava_shop_id"),
"LAVA_SECRET_KEY": body.get("lava_secret_key"),
"LAVA_ADDITIONAL_KEY": body.get("lava_additional_key"),
"LAVA_HOOK_URL": body.get("lava_hook_url"),
"LAVA_SUCCESS_URL": body.get("lava_success_url"),
"LAVA_FAIL_URL": body.get("lava_fail_url"),
"LAVA_EXPIRE_MINUTES": body.get("lava_expire_minutes"),
"ANYPAY_API_ID": body.get("anypay_api_id"),
"ANYPAY_API_KEY": body.get("anypay_api_key"),
"ANYPAY_PROJECT_ID": body.get("anypay_project_id"),
"ANYPAY_CURRENCY": body.get("anypay_currency"),
"ANYPAY_METHOD": body.get("anypay_method"),
"ANYPAY_SUCCESS_URL": body.get("anypay_success_url"),
"ANYPAY_FAIL_URL": body.get("anypay_fail_url"),
"ANYPAY_EMAIL": body.get("anypay_email"),
"ANYPAY_CHECK_IP": body.get("anypay_check_ip"),
"DIGISELLER_SELLER_ID": body.get("digiseller_seller_id"),
"DIGISELLER_API_KEY": body.get("digiseller_api_key"),
"DIGISELLER_PRODUCT_IDS": body.get("digiseller_product_ids"),
"DIGISELLER_PAY_URL": body.get("digiseller_pay_url"),
"DIGISELLER_CREDIT_FROM": body.get("digiseller_credit_from"),
"DIGISELLER_CALLBACK_URL": body.get("digiseller_callback_url"),
"STARS_ENABLED": body.get("stars_enabled"),
"STARS_RUB_PER_STAR": body.get("stars_rub_per_star"),
"TOPUP_CODE_PAY_URL": body.get("topup_code_pay_url"),
}
for env_key, raw in mapping.items():
if env_key not in PAYMENT_ENV_KEYS:
continue
if raw is None:
continue
if env_key in BOOL_ENV_KEYS:
if isinstance(raw, bool):
updates[env_key] = "true" if raw else "false"
else:
updates[env_key] = (
"true"
if str(raw).strip().lower() in {"1", "true", "yes", "on"}
else "false"
)
continue
text = str(raw).strip()
if env_key in SECRET_ENV_KEYS:
if text == "__clear__":
updates[env_key] = None
elif _is_masked_placeholder(text):
continue
else:
updates[env_key] = text
continue
updates[env_key] = text if text else None
if updates:
upsert_env_keys(updates)
return get_settings(require_bot_token=False)