fix: block legacy subscription renewal bypass in tariff mode
When switching from configurator to tariff mode, users with old subscriptions (tariff_id=NULL) could still renew them through unguarded paths, bypassing tariff pricing entirely. Vulnerable paths fixed: - MiniApp POST /subscription/renewal/options: returns empty list for classic subscriptions in tariff mode - MiniApp POST /subscription/renewal: raises 400 with classic_subscription_blocked error code - Bot confirm_extend_subscription: blocks stale extend_period_ callbacks with tariff mode check - Monitoring _process_autopayments: skips classic subscriptions (tariff_id=NULL) in autopay loop when tariff mode active Already protected (no changes needed): - Cabinet GET/POST renewal endpoints (renewal.py:51,117) - Auto-purchase service (_prepare_auto_extend_context:244) - Bot handle_extend_subscription menu (purchase.py:1657) - Tariff extend flow (tariff_purchase.py:2047)
This commit is contained in:
@@ -1817,6 +1817,14 @@ async def confirm_extend_subscription(
|
||||
days = int(callback.data.split('_')[2])
|
||||
texts = get_texts(db_user.language)
|
||||
|
||||
# Block classic subscription renewal when tariff mode is active
|
||||
if settings.is_tariffs_mode():
|
||||
await callback.answer(
|
||||
texts.t('TARIFF_MODE_RENEWAL_BLOCKED', '❌ Продление в этом режиме недоступно. Выберите тариф.'),
|
||||
show_alert=True,
|
||||
)
|
||||
return
|
||||
|
||||
# Валидация что период доступен для продления
|
||||
available_renewal_periods = settings.get_available_renewal_periods()
|
||||
if days not in available_renewal_periods:
|
||||
|
||||
@@ -1075,6 +1075,15 @@ class MonitoringService:
|
||||
)
|
||||
continue
|
||||
|
||||
# Skip classic subscriptions (tariff_id=NULL) when tariff mode is active
|
||||
if settings.is_tariffs_mode() and not sub.tariff_id:
|
||||
logger.debug(
|
||||
'Пропускаем классическую подписку без тарифа в autopay (tariff mode)',
|
||||
sub_id=sub.id,
|
||||
user_id=sub.user_id,
|
||||
)
|
||||
continue
|
||||
|
||||
days_before_expiry = (sub.end_date - current_time).days
|
||||
if days_before_expiry <= min(sub.autopay_days_before or 3, 3):
|
||||
autopay_subscriptions.append(sub)
|
||||
|
||||
@@ -5106,6 +5106,14 @@ async def get_subscription_renewal_options_endpoint(
|
||||
)
|
||||
_validate_subscription_id(payload.subscription_id, subscription)
|
||||
|
||||
# Block classic subscription renewal when tariff mode is active
|
||||
if settings.is_tariffs_mode() and not subscription.tariff_id:
|
||||
return MiniAppSubscriptionRenewalOptionsResponse(
|
||||
periods=[],
|
||||
balance_kopeks=getattr(user, 'balance_kopeks', 0),
|
||||
balance_currency=(getattr(user, 'balance_currency', None) or 'RUB').upper(),
|
||||
)
|
||||
|
||||
periods, pricing_map, default_period_id = await _prepare_subscription_renewal_options(
|
||||
db,
|
||||
user,
|
||||
@@ -5197,6 +5205,16 @@ async def submit_subscription_renewal_endpoint(
|
||||
)
|
||||
_validate_subscription_id(payload.subscription_id, subscription)
|
||||
|
||||
# Block classic subscription renewal when tariff mode is active
|
||||
if settings.is_tariffs_mode() and not subscription.tariff_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail={
|
||||
'code': 'classic_subscription_blocked',
|
||||
'message': 'Classic subscriptions cannot be renewed. Please purchase a tariff.',
|
||||
},
|
||||
)
|
||||
|
||||
period_days: int | None = None
|
||||
if payload.period_days is not None:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user