mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-04-28 08:41:05 +00:00
fix: prevent self-referral loops, invalidate all sessions on merge
- Add User.id != primary.id filter to referred_by_id reassignment to prevent self-referral loops when primary was referred by secondary - Clear primary.referred_by_id if it pointed to secondary - Add exclusion filter to ReferralEarning.referral_id reassignment to prevent user_id == referral_id rows - Invalidate refresh tokens for BOTH primary and secondary during merge (primary gets a fresh session after merge) - Fix duplicate step 4 comment numbering in execute_merge_endpoint - Add referred_by_id field to test fixture _make_user
This commit is contained in:
@@ -469,7 +469,7 @@ async def execute_merge_endpoint(
|
||||
detail='Account merge failed due to an internal error',
|
||||
) from exc
|
||||
|
||||
# 4. Re-fetch merged user with full relationships for auth response
|
||||
# 5. Re-fetch merged user with full relationships for auth response
|
||||
merged_user = await get_user_by_id(db, primary_user_id)
|
||||
if not merged_user:
|
||||
raise HTTPException(
|
||||
@@ -477,7 +477,7 @@ async def execute_merge_endpoint(
|
||||
detail='Failed to load merged user',
|
||||
)
|
||||
|
||||
# 5. Create auth tokens for the merged user
|
||||
# 6. Create auth tokens for the merged user
|
||||
try:
|
||||
auth_response = await _create_auth_response(merged_user, db)
|
||||
await _store_refresh_token(db, merged_user.id, auth_response.refresh_token, device_info='merge')
|
||||
|
||||
@@ -420,26 +420,35 @@ async def execute_merge(
|
||||
for payment_model in _PAYMENT_MODELS:
|
||||
await db.execute(update(payment_model).where(payment_model.user_id == secondary.id).values(user_id=primary.id))
|
||||
|
||||
# 8. Переназначение referral_earnings (обе колонки)
|
||||
# 8. Переназначение referral_earnings (обе колонки, исключая self-referral)
|
||||
await db.execute(update(ReferralEarning).where(ReferralEarning.user_id == secondary.id).values(user_id=primary.id))
|
||||
await db.execute(
|
||||
update(ReferralEarning).where(ReferralEarning.referral_id == secondary.id).values(referral_id=primary.id)
|
||||
update(ReferralEarning)
|
||||
.where(ReferralEarning.referral_id == secondary.id, ReferralEarning.user_id != primary.id)
|
||||
.values(referral_id=primary.id)
|
||||
)
|
||||
|
||||
# 9. Переназначение реферальной цепочки
|
||||
await db.execute(update(User).where(User.referred_by_id == secondary.id).values(referred_by_id=primary.id))
|
||||
# 9. Переназначение реферальной цепочки (исключая self-referral)
|
||||
await db.execute(
|
||||
update(User)
|
||||
.where(User.referred_by_id == secondary.id, User.id != primary.id)
|
||||
.values(referred_by_id=primary.id)
|
||||
)
|
||||
# Если primary был приглашён secondary — очищаем (нельзя ссылаться на самого себя)
|
||||
if primary.referred_by_id == secondary.id:
|
||||
primary.referred_by_id = None
|
||||
|
||||
# 10. Переназначение withdrawal_requests
|
||||
await db.execute(
|
||||
update(WithdrawalRequest).where(WithdrawalRequest.user_id == secondary.id).values(user_id=primary.id)
|
||||
)
|
||||
|
||||
# 11. Инвалидация refresh-токенов secondary
|
||||
# 11. Инвалидация refresh-токенов обоих пользователей (после мержа будет создан новый)
|
||||
now = datetime.now(UTC)
|
||||
await db.execute(
|
||||
update(CabinetRefreshToken)
|
||||
.where(
|
||||
CabinetRefreshToken.user_id == secondary.id,
|
||||
CabinetRefreshToken.user_id.in_([primary.id, secondary.id]),
|
||||
CabinetRefreshToken.revoked_at.is_(None),
|
||||
)
|
||||
.values(revoked_at=now)
|
||||
|
||||
@@ -40,6 +40,7 @@ def _make_user(
|
||||
partner_status: str = 'none',
|
||||
referral_code: str | None = None,
|
||||
referral_commission_percent: int | None = None,
|
||||
referred_by_id: int | None = None,
|
||||
remnawave_uuid: str | None = None,
|
||||
subscription: object | None = None,
|
||||
created_at: datetime | None = None,
|
||||
@@ -63,6 +64,7 @@ def _make_user(
|
||||
partner_status=partner_status,
|
||||
referral_code=referral_code,
|
||||
referral_commission_percent=referral_commission_percent,
|
||||
referred_by_id=referred_by_id,
|
||||
remnawave_uuid=remnawave_uuid,
|
||||
subscription=subscription,
|
||||
created_at=created_at or datetime(2024, 1, 1, tzinfo=UTC),
|
||||
|
||||
Reference in New Issue
Block a user