diff --git a/home/admin.py b/home/admin.py index 7abd91a..ee54876 100644 --- a/home/admin.py +++ b/home/admin.py @@ -3,7 +3,8 @@ from django.contrib import admin from django import forms from .models import ( 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 import logging @@ -12,6 +13,15 @@ from django_ckeditor_5.widgets import CKEditor5Widget 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) class ChangeFactionPriceAdmin(admin.ModelAdmin): diff --git a/home/migrations/0010_loginattempt.py b/home/migrations/0010_loginattempt.py new file mode 100644 index 0000000..3f008a9 --- /dev/null +++ b/home/migrations/0010_loginattempt.py @@ -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)), + ], + ), + ] diff --git a/home/models.py b/home/models.py index 2bd828c..e3666f3 100644 --- a/home/models.py +++ b/home/models.py @@ -270,7 +270,16 @@ class HomeApiPoints(models.Model): db_table = 'home_api_points' 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): diff --git a/home/templates/partials/security_history.html b/home/templates/partials/security_history.html index 01fe561..d62b8b0 100644 --- a/home/templates/partials/security_history.html +++ b/home/templates/partials/security_history.html @@ -1,82 +1,65 @@
-
-
-

Historial de seguridad

-
- -
-
-

Aquí verás la actividad de la cuenta y los últimos 20 intentos de conexión de tu cuenta a la página web.

-

Si observas alguna actividad sospechosa puedes cambiar la contraseña o contactar con el equipo de {{ NOMBRE_SERVIDOR }}.

-
-
- -
-

Historial de actividad

-
- - - - -
No hay actividad
-
-
- -
-

Historial de conexiones

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UsuarioEstadoIPFecha
INNAPMINEConexión exitosa37.133.171.7612:13:36 11-11-2024
INNAPMINEConexión exitosa37.133.171.7612:03:48 11-11-2024
INNAPMINEConexión exitosa37.133.171.7610:12:54 11-11-2024
INNAPMINEConexión exitosa37.133.171.7605:55:34 11-11-2024
INNAPMINEConexión exitosa84.236.195.2118:48:48 10-11-2024
INNAPMINEConexión exitosa84.236.195.2118:17:30 10-11-2024
INNAPMINEConexión exitosa84.236.195.2114:25:53 10-11-2024
-
-
+
+
+

Historial de seguridad

+
+ +
+
+

Aquí verás la actividad de la cuenta y los últimos 20 intentos de conexión de tu cuenta a la página web.

+

Si observas alguna actividad sospechosa puedes cambiar la contraseña o contactar con el equipo de {{ NOMBRE_SERVIDOR }}.

-
\ No newline at end of file + +
+

Historial de actividad

+
+ + + {% if login_attempts %} + {% for attempt in login_attempts %} + + + + + + + {% endfor %} + {% else %} + + + + {% endif %} + +
{{ attempt.username }} {{ attempt.timestamp|date:"d-m-Y H:i:s" }}{{ attempt.status }}{{ attempt.ip_address }}
No hay actividad
+
+
+ +
+

Historial de conexiones

+
+ + + + + + + + + + + {% for attempt in login_attempts %} + + + + + + + {% endfor %} + +
UsuarioEstadoIPFecha
{{ attempt.username }}{{ attempt.status }}{{ attempt.ip_address }}{{ attempt.timestamp|date:"d-m-Y H:i:s" }}
+
+
+
+
+
diff --git a/home/views.py b/home/views.py index f3d95eb..536798b 100644 --- a/home/views.py +++ b/home/views.py @@ -8,7 +8,8 @@ from django.contrib.auth import logout from django import forms import stripe 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 datetime import datetime, timedelta from .zone_definitions import get_zone_name @@ -196,20 +197,26 @@ def login_view(request): if form.is_valid(): username = form.cleaned_data['username'] 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): - # 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() return JsonResponse({'success': True}) 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: - return JsonResponse({'success': False, 'error': "Formulario no válido"}) + return JsonResponse({'success': False, 'error': "Formulario no valido"}) form = LoginForm() return render(request, 'auth/login.html', {'form': form}) - # Función para contar los personajes en línea def get_online_characters_count(): with connections['acore_characters'].cursor() as cursor: @@ -2320,10 +2327,23 @@ def ban_history_view(request): return render(request, 'account/ban_history.html') def security_history_view(request): - """ - Vista para mostrar el historial de seguridad del usuario. - """ - return render(request, 'account/security_history.html') + username = request.session.get('username') + if not username: + return redirect('login') # Si no est¨¢ autenticado, redirigir al login + + # 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):