Ruff format/ Cleanup
This commit is contained in:
+6
-6
@@ -16,20 +16,20 @@ from config import (
|
||||
BACKUP_CAPTION,
|
||||
BACKUP_CHANNEL_ID,
|
||||
BACKUP_CHANNEL_THREAD_ID,
|
||||
BACKUP_CREATE_ARCHIVE,
|
||||
BACKUP_INCLUDE_CONFIG,
|
||||
BACKUP_INCLUDE_DB,
|
||||
BACKUP_INCLUDE_IMG,
|
||||
BACKUP_INCLUDE_TEXTS,
|
||||
BACKUP_OTHER_BOT_TOKEN,
|
||||
BACKUP_SEND_MODE,
|
||||
BACK_DIR,
|
||||
DB_NAME,
|
||||
DB_PASSWORD,
|
||||
DB_USER,
|
||||
PG_IN_DOCKER,
|
||||
PG_HOST,
|
||||
PG_IN_DOCKER,
|
||||
PG_PORT,
|
||||
BACKUP_CREATE_ARCHIVE,
|
||||
BACKUP_INCLUDE_DB,
|
||||
BACKUP_INCLUDE_CONFIG,
|
||||
BACKUP_INCLUDE_TEXTS,
|
||||
BACKUP_INCLUDE_IMG,
|
||||
)
|
||||
from logger import logger
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import aiogram.types
|
||||
|
||||
from pydantic import ConfigDict
|
||||
|
||||
|
||||
_UniqueGiftColors = getattr(aiogram.types, "UniqueGiftColors", None)
|
||||
if _UniqueGiftColors is not None:
|
||||
_cfg = getattr(_UniqueGiftColors, "model_config", None)
|
||||
@@ -24,7 +26,7 @@ def apply_button_icons_patch(config: dict[str, dict[str, str]] | None = None) ->
|
||||
_button_icon_config.update(config)
|
||||
|
||||
class _PatchedInlineKeyboardButton(_OriginalInlineKeyboardButton):
|
||||
def __init__(self, **kwargs: object):
|
||||
def __init__(self, **kwargs: object) -> None:
|
||||
key = kwargs.get("callback_data") or kwargs.get("url")
|
||||
if key is not None and isinstance(key, str):
|
||||
config = _button_icon_config.get(key)
|
||||
|
||||
+1
-1
@@ -8,8 +8,8 @@ from sqlalchemy import exists, func, join, not_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.constants import PAYMENT_SYSTEMS_EXCLUDED
|
||||
from database.models import Key, Payment, Referral, Tariff, User
|
||||
from database.access.resolution import resolve_user_optional
|
||||
from database.models import Key, Payment, Referral, Tariff, User
|
||||
|
||||
|
||||
async def export_users_csv(session: AsyncSession) -> BufferedInputFile:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aiogram import Bot
|
||||
@@ -9,6 +10,7 @@ from aiogram.types import MessageEntity
|
||||
|
||||
from logger import logger
|
||||
|
||||
|
||||
_PLACEHOLDER_CACHE: dict[str, str] = {}
|
||||
_BOT: Bot | None = None
|
||||
|
||||
@@ -274,6 +276,7 @@ def patch_bot_methods() -> bool:
|
||||
global _BOT
|
||||
try:
|
||||
from aiogram.types import Message
|
||||
|
||||
from bot import bot
|
||||
|
||||
_BOT = bot
|
||||
|
||||
+145
-48
@@ -1,53 +1,149 @@
|
||||
from logger import logger
|
||||
|
||||
|
||||
_BUILTIN_DOMAINS: set[str] = {
|
||||
"mailinator.com", "guerrillamail.com", "guerrillamail.de", "guerrillamail.net",
|
||||
"guerrillamail.org", "guerrillamailblock.com", "grr.la", "sharklasers.com",
|
||||
"guerrillamail.info", "tempmail.com", "temp-mail.org", "temp-mail.io",
|
||||
"throwaway.email", "fakeinbox.com", "tempail.com", "tempr.email",
|
||||
"dispostable.com", "yopmail.com", "yopmail.fr", "yopmail.net",
|
||||
"cool.fr.nf", "jetable.fr.nf", "nospam.ze.tc", "nomail.xl.cx",
|
||||
"mega.zik.dj", "speed.1s.fr", "courriel.fr.nf", "moncourrier.fr.nf",
|
||||
"monemail.fr.nf", "monmail.fr.nf", "hide.biz.st", "mytrashmail.com",
|
||||
"mailnesia.com", "maildrop.cc", "discard.email", "discardmail.com",
|
||||
"discardmail.de", "trashmail.com", "trashmail.me", "trashmail.net",
|
||||
"trashmail.org", "trashmail.at", "trashmail.io", "trashmail.ws",
|
||||
"trash-mail.com", "trash-mail.at", "trashemail.de",
|
||||
"mailcatch.com", "mailscrap.com", "mailforspam.com",
|
||||
"spamgourmet.com", "spamgourmet.net", "spamgourmet.org",
|
||||
"mailexpire.com", "tempinbox.com", "tempomail.fr",
|
||||
"10minutemail.com", "10minutemail.co.za", "10minutemail.net",
|
||||
"minutemail.io", "emailondeck.com", "getnada.com",
|
||||
"mohmal.com", "burnermail.io", "inboxbear.com",
|
||||
"mailsac.com", "harakirimail.com", "33mail.com",
|
||||
"maildax.com", "crazymailing.com", "mailtemp.info",
|
||||
"emkei.cz", "example.com", "test.com", "mailinator.net",
|
||||
"binkmail.com", "bobmail.info", "chammy.info",
|
||||
"devnullmail.com", "letthemeatspam.com", "mailnull.com",
|
||||
"nomail.pw", "nowmymail.com", "rmqkr.net",
|
||||
"sharklasers.com", "spamfree24.org", "spamhereplease.com",
|
||||
"tempmailaddress.com", "wegwerfmail.de", "wegwerfmail.net",
|
||||
"wh4f.org", "mailzilla.com", "anonbox.net",
|
||||
"bspamfree.org", "kurzepost.de", "objectmail.com",
|
||||
"proxymail.eu", "rcpt.at", "reallymymail.com",
|
||||
"recode.me", "regbypass.com", "s0ny.net",
|
||||
"safetymail.info", "safetypost.de", "shieldedmail.com",
|
||||
"sogetthis.com", "soodonims.com", "spambox.us",
|
||||
"spamcero.com", "spamday.com", "spamex.com",
|
||||
"spamfighter.cf", "spamfighter.ga", "spamfighter.gq",
|
||||
"spamfighter.ml", "spamfighter.tk",
|
||||
"spamhole.com", "spaml.com", "spaml.de",
|
||||
"uggsrock.com", "uroid.com", "veryreallymymail.com",
|
||||
"viditag.com", "vomoto.com", "vpn.st",
|
||||
"vsimcard.com", "vubby.com", "vztc.com",
|
||||
"wasteland.rfc822.org", "webemail.me",
|
||||
"zetmail.com", "zippymail.info",
|
||||
"mailnator.com", "mailtothis.com",
|
||||
"mx0.wwwnew.eu", "mypartyclip.de",
|
||||
"myzx.com", "nb.gy", "nobulk.com",
|
||||
"noclickemail.com", "nogmailspam.info",
|
||||
"nomail.xl.cx", "nomorespamemails.com",
|
||||
"nospam.ze.tc", "nothingtoseehere.ca",
|
||||
"mailinator.com",
|
||||
"guerrillamail.com",
|
||||
"guerrillamail.de",
|
||||
"guerrillamail.net",
|
||||
"guerrillamail.org",
|
||||
"guerrillamailblock.com",
|
||||
"grr.la",
|
||||
"sharklasers.com",
|
||||
"guerrillamail.info",
|
||||
"tempmail.com",
|
||||
"temp-mail.org",
|
||||
"temp-mail.io",
|
||||
"throwaway.email",
|
||||
"fakeinbox.com",
|
||||
"tempail.com",
|
||||
"tempr.email",
|
||||
"dispostable.com",
|
||||
"yopmail.com",
|
||||
"yopmail.fr",
|
||||
"yopmail.net",
|
||||
"cool.fr.nf",
|
||||
"jetable.fr.nf",
|
||||
"nospam.ze.tc",
|
||||
"nomail.xl.cx",
|
||||
"mega.zik.dj",
|
||||
"speed.1s.fr",
|
||||
"courriel.fr.nf",
|
||||
"moncourrier.fr.nf",
|
||||
"monemail.fr.nf",
|
||||
"monmail.fr.nf",
|
||||
"hide.biz.st",
|
||||
"mytrashmail.com",
|
||||
"mailnesia.com",
|
||||
"maildrop.cc",
|
||||
"discard.email",
|
||||
"discardmail.com",
|
||||
"discardmail.de",
|
||||
"trashmail.com",
|
||||
"trashmail.me",
|
||||
"trashmail.net",
|
||||
"trashmail.org",
|
||||
"trashmail.at",
|
||||
"trashmail.io",
|
||||
"trashmail.ws",
|
||||
"trash-mail.com",
|
||||
"trash-mail.at",
|
||||
"trashemail.de",
|
||||
"mailcatch.com",
|
||||
"mailscrap.com",
|
||||
"mailforspam.com",
|
||||
"spamgourmet.com",
|
||||
"spamgourmet.net",
|
||||
"spamgourmet.org",
|
||||
"mailexpire.com",
|
||||
"tempinbox.com",
|
||||
"tempomail.fr",
|
||||
"10minutemail.com",
|
||||
"10minutemail.co.za",
|
||||
"10minutemail.net",
|
||||
"minutemail.io",
|
||||
"emailondeck.com",
|
||||
"getnada.com",
|
||||
"mohmal.com",
|
||||
"burnermail.io",
|
||||
"inboxbear.com",
|
||||
"mailsac.com",
|
||||
"harakirimail.com",
|
||||
"33mail.com",
|
||||
"maildax.com",
|
||||
"crazymailing.com",
|
||||
"mailtemp.info",
|
||||
"emkei.cz",
|
||||
"example.com",
|
||||
"test.com",
|
||||
"mailinator.net",
|
||||
"binkmail.com",
|
||||
"bobmail.info",
|
||||
"chammy.info",
|
||||
"devnullmail.com",
|
||||
"letthemeatspam.com",
|
||||
"mailnull.com",
|
||||
"nomail.pw",
|
||||
"nowmymail.com",
|
||||
"rmqkr.net",
|
||||
"spamfree24.org",
|
||||
"spamhereplease.com",
|
||||
"tempmailaddress.com",
|
||||
"wegwerfmail.de",
|
||||
"wegwerfmail.net",
|
||||
"wh4f.org",
|
||||
"mailzilla.com",
|
||||
"anonbox.net",
|
||||
"bspamfree.org",
|
||||
"kurzepost.de",
|
||||
"objectmail.com",
|
||||
"proxymail.eu",
|
||||
"rcpt.at",
|
||||
"reallymymail.com",
|
||||
"recode.me",
|
||||
"regbypass.com",
|
||||
"s0ny.net",
|
||||
"safetymail.info",
|
||||
"safetypost.de",
|
||||
"shieldedmail.com",
|
||||
"sogetthis.com",
|
||||
"soodonims.com",
|
||||
"spambox.us",
|
||||
"spamcero.com",
|
||||
"spamday.com",
|
||||
"spamex.com",
|
||||
"spamfighter.cf",
|
||||
"spamfighter.ga",
|
||||
"spamfighter.gq",
|
||||
"spamfighter.ml",
|
||||
"spamfighter.tk",
|
||||
"spamhole.com",
|
||||
"spaml.com",
|
||||
"spaml.de",
|
||||
"uggsrock.com",
|
||||
"uroid.com",
|
||||
"veryreallymymail.com",
|
||||
"viditag.com",
|
||||
"vomoto.com",
|
||||
"vpn.st",
|
||||
"vsimcard.com",
|
||||
"vubby.com",
|
||||
"vztc.com",
|
||||
"wasteland.rfc822.org",
|
||||
"webemail.me",
|
||||
"zetmail.com",
|
||||
"zippymail.info",
|
||||
"mailnator.com",
|
||||
"mailtothis.com",
|
||||
"mx0.wwwnew.eu",
|
||||
"mypartyclip.de",
|
||||
"myzx.com",
|
||||
"nb.gy",
|
||||
"nobulk.com",
|
||||
"noclickemail.com",
|
||||
"nogmailspam.info",
|
||||
"nomorespamemails.com",
|
||||
"nothingtoseehere.ca",
|
||||
}
|
||||
|
||||
_loaded_extra = False
|
||||
@@ -61,7 +157,8 @@ def _load_extra() -> None:
|
||||
_loaded_extra = True
|
||||
try:
|
||||
from config import DISPOSABLE_EMAIL_BLOCKLIST_EXTRA
|
||||
if isinstance(DISPOSABLE_EMAIL_BLOCKLIST_EXTRA, (list, set, tuple)):
|
||||
|
||||
if isinstance(DISPOSABLE_EMAIL_BLOCKLIST_EXTRA, list | set | tuple):
|
||||
_extra_domains = {d.strip().lower() for d in DISPOSABLE_EMAIL_BLOCKLIST_EXTRA if isinstance(d, str)}
|
||||
if _extra_domains:
|
||||
logger.info("[DisposableEmail] загружено {} дополнительных доменов", len(_extra_domains))
|
||||
|
||||
+5
-3
@@ -8,8 +8,10 @@ from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError, Teleg
|
||||
from aiogram.filters import ExceptionTypeFilter
|
||||
from aiogram.types import BufferedInputFile, ErrorEvent
|
||||
from aiogram.utils.markdown import hbold
|
||||
from sqlalchemy.exc import InterfaceError as SQLAlchemyInterfaceError
|
||||
from sqlalchemy.exc import OperationalError as SQLAlchemyOperationalError
|
||||
from sqlalchemy.exc import (
|
||||
InterfaceError as SQLAlchemyInterfaceError,
|
||||
OperationalError as SQLAlchemyOperationalError,
|
||||
)
|
||||
|
||||
from config import ADMIN_ID
|
||||
from database import async_session_maker
|
||||
@@ -104,7 +106,7 @@ def setup_error_handlers(dp: Dispatcher) -> None:
|
||||
|
||||
if isinstance(
|
||||
event.exception,
|
||||
(SQLAlchemyInterfaceError, SQLAlchemyOperationalError),
|
||||
SQLAlchemyInterfaceError | SQLAlchemyOperationalError,
|
||||
):
|
||||
chat_id = None
|
||||
if event.update.message:
|
||||
|
||||
@@ -22,7 +22,7 @@ def encode_referral_code(user_id: int) -> str:
|
||||
raw = int(user_id).to_bytes(8, byteorder="big", signed=False)
|
||||
secret = _secret_bytes()
|
||||
mask = hmac.new(secret, b"ref-mask-v1", hashlib.sha256).digest()[:8]
|
||||
obfuscated = bytes(a ^ b for a, b in zip(raw, mask))
|
||||
obfuscated = bytes(a ^ b for a, b in zip(raw, mask, strict=False))
|
||||
signature = hmac.new(secret, b"ref-sign-v1:" + obfuscated, hashlib.sha256).digest()[:6]
|
||||
payload = base64.urlsafe_b64encode(obfuscated + signature).decode("ascii").rstrip("=")
|
||||
return f"r1_{payload}"
|
||||
@@ -34,7 +34,7 @@ def encode_partner_code(user_id: int) -> str:
|
||||
raw = int(user_id).to_bytes(8, byteorder="big", signed=False)
|
||||
secret = _secret_bytes()
|
||||
mask = hmac.new(secret, b"partner-mask-v1", hashlib.sha256).digest()[:8]
|
||||
obfuscated = bytes(a ^ b for a, b in zip(raw, mask))
|
||||
obfuscated = bytes(a ^ b for a, b in zip(raw, mask, strict=False))
|
||||
signature = hmac.new(secret, b"partner-sign-v1:" + obfuscated, hashlib.sha256).digest()[:6]
|
||||
payload = base64.urlsafe_b64encode(obfuscated + signature).decode("ascii").rstrip("=")
|
||||
return f"p1_{payload}"
|
||||
@@ -58,7 +58,7 @@ def decode_referral_code(value: str | None) -> int | None:
|
||||
if not hmac.compare_digest(signature, expected):
|
||||
return None
|
||||
mask = hmac.new(secret, b"ref-mask-v1", hashlib.sha256).digest()[:8]
|
||||
raw = bytes(a ^ b for a, b in zip(obfuscated, mask))
|
||||
raw = bytes(a ^ b for a, b in zip(obfuscated, mask, strict=False))
|
||||
parsed = int.from_bytes(raw, byteorder="big", signed=False)
|
||||
return parsed if parsed > 0 else None
|
||||
if token.startswith("p1_"):
|
||||
@@ -88,7 +88,7 @@ def decode_partner_code(value: str | None) -> int | None:
|
||||
if not hmac.compare_digest(signature, expected):
|
||||
return None
|
||||
mask = hmac.new(secret, b"partner-mask-v1", hashlib.sha256).digest()[:8]
|
||||
raw = bytes(a ^ b for a, b in zip(obfuscated, mask))
|
||||
raw = bytes(a ^ b for a, b in zip(obfuscated, mask, strict=False))
|
||||
parsed = int.from_bytes(raw, byteorder="big", signed=False)
|
||||
return parsed if parsed > 0 else None
|
||||
if token.startswith("r1_"):
|
||||
|
||||
@@ -47,6 +47,7 @@ def verify_webapp_init_data(
|
||||
https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app
|
||||
"""
|
||||
import json
|
||||
|
||||
from urllib.parse import parse_qs
|
||||
|
||||
if not init_data or not bot_token:
|
||||
|
||||
@@ -3,6 +3,7 @@ import httpx
|
||||
from config import TURNSTILE_SECRET_KEY
|
||||
from logger import logger
|
||||
|
||||
|
||||
_VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from core.redis_cache import (
|
||||
redis_connection_ok,
|
||||
)
|
||||
|
||||
|
||||
_RESEND_COOLDOWN_SEC = 60.0
|
||||
_IP_WINDOW_SEC = 3600.0
|
||||
_IP_MAX_SENDS = 40
|
||||
|
||||
Reference in New Issue
Block a user