"""Imports y utilidades compartidas por el paquete de vistas (`home.views`). Cada submódulo de vistas hace `from ._base import *` para heredar estos imports y el decorador `require_paid_stripe`. """ import socket, hashlib, gmpy2, binascii, os, re, json, logging, secrets from collections import Counter from datetime import datetime, timedelta from decimal import Decimal, ROUND_HALF_UP from functools import wraps from django import forms from django.conf import settings from django.contrib import messages from django.contrib.auth import logout from django.db import connections from django.http import HttpResponse, JsonResponse from django.shortcuts import render, redirect from django.urls import reverse from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.timezone import now from django.views.decorators.csrf import csrf_exempt import stripe from ..ac_soap import execute_soap_command from ..library_correo import enviar_correo from ..pagos_stripe import create_checkout_session, is_session_paid from ..pagos_sumup import crear_checkout, crear_checkout_battlepay, obtener_checkout from ..zone_definitions import get_zone_name from .. import bnet from ..models import ( Noticia, ClienteCategoria, ServerSelection, RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, ClaimedReward, AccountActivation, SecurityToken, GuildRenameSettings, VoteSite, VoteLog, HomeApiPoints, UnstuckHistory, ReviveHistory, RenamePrice, CustomizePrice, ChangeRacePrice, ChangeFactionPrice, LevelUpPrice, GoldPrice, TransferPrice, Category, Item, StripeLog, LoginAttempt, Pedido, PasswordReset, ) # Configuración del logger logger = logging.getLogger(__name__) def verify_turnstile(request): """Verifica el token de Cloudflare Turnstile enviado por el formulario. Devuelve True si no hay secreto configurado (captcha desactivado) o si Cloudflare confirma el token. Ante fallo de red devuelve False (fail-closed). """ import json import urllib.parse import urllib.request secret = settings.TURNSTILE_SECRET_KEY if not secret: return True token = request.POST.get('cf-turnstile-response', '').strip() if not token: return False payload = urllib.parse.urlencode({ 'secret': secret, 'response': token, 'remoteip': request.META.get('REMOTE_ADDR', ''), }).encode() try: req = urllib.request.Request( 'https://challenges.cloudflare.com/turnstile/v0/siteverify', data=payload) with urllib.request.urlopen(req, timeout=5) as resp: result = json.loads(resp.read().decode()) return bool(result.get('success')) except Exception as e: logger.warning("Turnstile: fallo al verificar: %s", e) return False def require_paid_stripe(redirect_to='index'): """ Protege las vistas de "éxito" de pago: exige un `session_id` de Stripe realmente PAGADO en la URL (Stripe lo añade tras el pago) y evita re-entregas marcando el StripeLog como `fulfilled`. Cierra el bypass de ir directo a la success-url sin pagar. """ def deco(view): @wraps(view) def wrapper(request, *args, **kwargs): session_id = request.GET.get('session_id') if not is_session_paid(session_id): messages.error(request, 'No se ha podido verificar el pago.') return redirect(redirect_to) log = StripeLog.objects.filter(session_id=session_id).first() if log is not None and log.fulfilled: messages.info(request, 'Este pago ya había sido procesado.') return redirect(redirect_to) response = view(request, *args, **kwargs) if log is not None: log.fulfilled = True log.save(update_fields=['fulfilled']) return response return wrapper return deco