Implementado Logs de Pagos de Stripe y Historial de conexiones de seguridad

This commit is contained in:
adevopg
2025-02-18 11:42:46 +01:00
parent e94915e667
commit 0a650eb161
5 changed files with 136 additions and 91 deletions
+11 -1
View File
@@ -3,7 +3,8 @@ from django.contrib import admin
from django import forms from django import forms
from .models import ( from .models import (
Noticia, ClienteCategoria, SistemaOperativo, ServerSelection, Noticia, ClienteCategoria, SistemaOperativo, ServerSelection,
RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, GuildRenameSettings, VoteSite, RenamePrice, CustomizePrice, ChangeRacePrice, ChangeFactionPrice, LevelUpPrice, GoldPrice, TransferPrice, MaintenanceMode RecruitAFriend, DownloadClientPage, ContentCreator, RecruitReward, GuildRenameSettings, VoteSite, RenamePrice, CustomizePrice, ChangeRacePrice, ChangeFactionPrice, LevelUpPrice, GoldPrice, TransferPrice, MaintenanceMode,
StripeLog
) )
from django.db import connections from django.db import connections
import logging import logging
@@ -12,6 +13,15 @@ from django_ckeditor_5.widgets import CKEditor5Widget
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@admin.register(StripeLog)
class StripeLogAdmin(admin.ModelAdmin):
list_display = (
'account_id', 'username', 'email', 'acore_ip', 'stripe_ip', 'product_name',
'amount', 'session_id', 'mode', 'character_name', 'timestamp'
) # Añadido stripe_ip
list_filter = ('mode', 'timestamp') # Filtros por campo en la parte lateral
search_fields = ('username', 'product_name', 'session_id', 'email', 'stripe_ip') # Ahora incluye 'stripe_ip' en la búsqueda
ordering = ('-timestamp',) # Ordenar por timestamp descendentes
@admin.register(ChangeFactionPrice) @admin.register(ChangeFactionPrice)
class ChangeFactionPriceAdmin(admin.ModelAdmin): class ChangeFactionPriceAdmin(admin.ModelAdmin):
+23
View File
@@ -0,0 +1,23 @@
# Generated by Django 5.1.4 on 2025-02-18 10:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0009_stripelog'),
]
operations = [
migrations.CreateModel(
name='LoginAttempt',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('username', models.CharField(max_length=100)),
('status', models.CharField(max_length=50)),
('ip_address', models.GenericIPAddressField()),
('timestamp', models.DateTimeField(auto_now_add=True)),
],
),
]
+9
View File
@@ -272,6 +272,15 @@ class HomeApiPoints(models.Model):
def __str__(self): def __str__(self):
return f"Cuenta {self.accountID} - PV: {self.vp}, DP: {self.dp}" return f"Cuenta {self.accountID} - PV: {self.vp}, DP: {self.dp}"
class LoginAttempt(models.Model):
username = models.CharField(max_length=100)
status = models.CharField(max_length=50) # Ejemplo: 'Éxito' o 'Fracaso'
ip_address = models.GenericIPAddressField() # IP del intento de inicio de sesión
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.username} - {self.status} - {self.timestamp}"
class StripeLog(models.Model): class StripeLog(models.Model):
account_id = models.IntegerField() # ID de la cuenta en acore_auth account_id = models.IntegerField() # ID de la cuenta en acore_auth
+56 -73
View File
@@ -1,82 +1,65 @@
<div class="main-page"> <div class="main-page">
<div class="middle-content"> <div class="middle-content">
<div class="body-content"> <div class="body-content">
<div class="title-content"><h1>Historial de seguridad</h1></div> <div class="title-content"><h1>Historial de seguridad</h1></div>
<div class="box-content"> <div class="box-content">
<div class="title-box-content"><h2>Información</h2><a class="back-to-account" href="my-account">Regresar a mi cuenta</a><a class="back-to-account-responsive" href="my-account">Regresar</a></div> <div class="title-box-content"><h2>Información</h2><a class="back-to-account" href="my-account">Regresar a mi cuenta</a><a class="back-to-account-responsive" href="my-account">Regresar</a></div>
<div class="body-box-content justified"> <div class="body-box-content justified">
<br> <br>
<p>Aquí verás la actividad de la cuenta y los últimos 20 intentos de conexión de tu cuenta a la página web.</p> <p>Aquí verás la actividad de la cuenta y los últimos 20 intentos de conexión de tu cuenta a la página web.</p>
<p>Si observas alguna actividad sospechosa puedes cambiar la contraseña o contactar con el equipo de {{ NOMBRE_SERVIDOR }}.</p> <p>Si observas alguna actividad sospechosa puedes cambiar la contraseña o contactar con el equipo de {{ NOMBRE_SERVIDOR }}.</p>
</div> </div>
</div> </div>
<div class="box-content"> <div class="box-content">
<div class="title-box-content"><h2>Historial de actividad</h2></div> <div class="title-box-content"><h2>Historial de actividad</h2></div>
<div class="body-box-content centered"> <div class="body-box-content centered">
<table class="max-center-table-aligned2"> <table class="max-center-table-aligned2">
<tbody><tr> <tbody>
<td class="centered"><span>No hay actividad</span></td> {% if login_attempts %}
{% for attempt in login_attempts %}
<tr>
<td>{{ attempt.username }}</td> <!-- Agregado: Mostrar el nombre de usuario -->
<td>{{ attempt.timestamp|date:"d-m-Y H:i:s" }}</td>
<td>{{ attempt.status }}</td>
<td>{{ attempt.ip_address }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="4" class="centered"><span>No hay actividad</span></td>
</tr> </tr>
</tbody></table> {% endif %}
</div> </tbody>
</div> </table>
</div>
</div>
<div class="box-content"> <div class="box-content">
<div class="title-box-content"><h2>Historial de conexiones</h2></div> <div class="title-box-content"><h2>Historial de conexiones</h2></div>
<div class="body-box-content centered"> <div class="body-box-content centered">
<table class="max-center-table-aligned"> <table class="max-center-table-aligned">
<tbody><tr> <thead>
<th>Usuario</th> <tr>
<th>Estado</th> <th>Usuario</th>
<th>IP</th> <th>Estado</th>
<th>Fecha</th> <th>IP</th>
</tr> <th>Fecha</th>
</tr>
</thead>
<tbody>
{% for attempt in login_attempts %}
<tr> <tr>
<td><span>INNAPMINE</span></td> <td>{{ attempt.username }}</td>
<td><span>Conexión exitosa</span></td> <td>{{ attempt.status }}</td>
<td class="long-td"><span>37.133.171.76</span></td> <td>{{ attempt.ip_address }}</td>
<td><span>12:13:36 11-11-2024</span></td> <td>{{ attempt.timestamp|date:"d-m-Y H:i:s" }}</td>
</tr> </tr>
<tr> {% endfor %}
<td><span>INNAPMINE</span></td> </tbody>
<td><span>Conexión exitosa</span></td> </table>
<td class="long-td"><span>37.133.171.76</span></td>
<td><span>12:03:48 11-11-2024</span></td>
</tr>
<tr>
<td><span>INNAPMINE</span></td>
<td><span>Conexión exitosa</span></td>
<td class="long-td"><span>37.133.171.76</span></td>
<td><span>10:12:54 11-11-2024</span></td>
</tr>
<tr>
<td><span>INNAPMINE</span></td>
<td><span>Conexión exitosa</span></td>
<td class="long-td"><span>37.133.171.76</span></td>
<td><span>05:55:34 11-11-2024</span></td>
</tr>
<tr>
<td><span>INNAPMINE</span></td>
<td><span>Conexión exitosa</span></td>
<td class="long-td"><span>84.236.195.21</span></td>
<td><span>18:48:48 10-11-2024</span></td>
</tr>
<tr>
<td><span>INNAPMINE</span></td>
<td><span>Conexión exitosa</span></td>
<td class="long-td"><span>84.236.195.21</span></td>
<td><span>18:17:30 10-11-2024</span></td>
</tr>
<tr>
<td><span>INNAPMINE</span></td>
<td><span>Conexión exitosa</span></td>
<td class="long-td"><span>84.236.195.21</span></td>
<td><span>14:25:53 10-11-2024</span></td>
</tr>
</tbody></table>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
+30 -10
View File
@@ -8,7 +8,8 @@ from django.contrib.auth import logout
from django import forms from django import forms
import stripe import stripe
from .pagos_stripe import create_checkout_session from .pagos_stripe import create_checkout_session
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 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
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from datetime import datetime, timedelta from datetime import datetime, timedelta
from .zone_definitions import get_zone_name from .zone_definitions import get_zone_name
@@ -196,20 +197,26 @@ def login_view(request):
if form.is_valid(): if form.is_valid():
username = form.cleaned_data['username'] username = form.cleaned_data['username']
password = form.cleaned_data['password'] password = form.cleaned_data['password']
ip_address = request.META.get('REMOTE_ADDR') # Obtener la IP del cliente
# Llamar a la función de autenticación # Llamar a la funci¨®n de autenticaci¨®n
if authenticate(username, password): if authenticate(username, password):
# Guardar el nombre de usuario en mayúsculas en la sesión # Guardar el intento exitoso
log_login_attempt(username, "Exito", ip_address)
# Guardar el nombre de usuario en may¨²sculas en la sesi¨®n
request.session['username'] = username.upper() request.session['username'] = username.upper()
return JsonResponse({'success': True}) return JsonResponse({'success': True})
else: else:
return JsonResponse({'success': False, 'error': "Usuario o contraseña incorrectos"}) # Guardar el intento fallido
log_login_attempt(username, "Fracaso", ip_address)
return JsonResponse({'success': False, 'error': "Usuario o contrase?a incorrectos"})
else: else:
return JsonResponse({'success': False, 'error': "Formulario no válido"}) return JsonResponse({'success': False, 'error': "Formulario no valido"})
form = LoginForm() form = LoginForm()
return render(request, 'auth/login.html', {'form': form}) return render(request, 'auth/login.html', {'form': form})
# Función para contar los personajes en línea # Función para contar los personajes en línea
def get_online_characters_count(): def get_online_characters_count():
with connections['acore_characters'].cursor() as cursor: with connections['acore_characters'].cursor() as cursor:
@@ -2320,10 +2327,23 @@ def ban_history_view(request):
return render(request, 'account/ban_history.html') return render(request, 'account/ban_history.html')
def security_history_view(request): def security_history_view(request):
""" username = request.session.get('username')
Vista para mostrar el historial de seguridad del usuario. if not username:
""" return redirect('login') # Si no est¨¢ autenticado, redirigir al login
return render(request, 'account/security_history.html')
# Obtener los ¨²ltimos 20 intentos de inicio de sesi¨®n
login_attempts = LoginAttempt.objects.filter(username=username).order_by('-timestamp')[:20]
return render(request, 'account/security_history.html', {'login_attempts': login_attempts})
def log_login_attempt(username, status, ip_address):
# Registrar intento de inicio de sesi¨®n en el historial
LoginAttempt.objects.create(
username=username,
status=status,
ip_address=ip_address,
timestamp=timezone.now()
)
def trade_points_view(request): def trade_points_view(request):