[REPO REFACTOR]: changed to a better git repository structure with branches
This commit is contained in:
2
BYODSEC/.gitignore
vendored
Normal file
2
BYODSEC/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/bin/
|
||||||
|
/target/
|
||||||
54
BYODSEC/log/client.log
Normal file
54
BYODSEC/log/client.log
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
2025-10-20 03:41:45 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 03:41:50 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: smt4497 -> Servidor
|
||||||
|
2025-10-20 18:03:23 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:03:34 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'alvgulveg' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:03:38 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: smt4497 -> Servidor
|
||||||
|
2025-10-20 18:03:40 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: alvgulveg -> Servidor
|
||||||
|
2025-10-20 18:04:04 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'ricolinad' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:04:15 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: ricolinad -> Servidor
|
||||||
|
2025-10-20 18:04:36 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'ricolinad' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:05:48 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:09:21 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:10:12 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:12:49 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' registrado correctamente.
|
||||||
|
2025-10-20 18:12:54 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:12:57 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:14:49 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:14:57 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'alvgulveg' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:15:04 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:15:08 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: smt4497 -> Servidor
|
||||||
|
2025-10-20 18:15:09 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: alvgulveg -> Servidor
|
||||||
|
2025-10-20 18:15:14 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: psancas -> Servidor
|
||||||
|
2025-10-20 18:16:28 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: psancas -> Servidor
|
||||||
|
2025-10-20 18:17:38 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'ricolinad' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:17:43 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: ricolinad -> Servidor
|
||||||
|
2025-10-20 18:18:16 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:20:11 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:20:24 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:24:49 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:25:09 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'smt4497': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:25:20 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'smt4497': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:25:23 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'smt4497': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:25:47 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'smt4497' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:32:42 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:32:49 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'psancas': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:32:56 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:35:05 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:35:07 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'psancas': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:35:22 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:35:24 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:35:26 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:37:28 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:37:31 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'psancas': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:37:40 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'psancas': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:37:44 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 18:39:08 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:39:21 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'psancas': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 18:41:15 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 18:41:25 WARN n.miarma.byodsec.client.ClientSocket - Intento de login fallido para 'psancas': Ha ocurrido un error inesperado.
|
||||||
|
2025-10-20 22:42:26 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 22:42:36 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'smt4497' ya tiene una sesión activa.
|
||||||
|
2025-10-20 22:43:17 INFO n.miarma.byodsec.client.ClientSocket - El usuario 'psancas' ha iniciado sesión correctamente.
|
||||||
|
2025-10-20 22:43:20 INFO n.miarma.byodsec.client.ClientSocket - Mensaje enviado: smt4497 -> Servidor
|
||||||
|
2025-10-20 22:43:24 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'psancas' ha cerrado sesión correctamente.
|
||||||
|
2025-10-20 22:43:26 INFO n.miarma.byodsec.client.ClientSocket - Usuario 'smt4497' ha cerrado sesión correctamente.
|
||||||
575
BYODSEC/log/server.log
Normal file
575
BYODSEC/log/server.log
Normal file
@@ -0,0 +1,575 @@
|
|||||||
|
2025-10-20 03:41:45 [main] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:58152
|
||||||
|
2025-10-20 03:41:45 [main] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 03:41:50 [main] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:35314
|
||||||
|
2025-10-20 03:41:50 [main] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de smt4497 a Servidor | hola
|
||||||
|
2025-10-20 03:42:15 [main] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:45928
|
||||||
|
2025-10-20 03:42:15 [main] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 03:42:15 [main] ERROR n.miarma.byodsec.server.RemoteSocket - Fallo procesando solicitud
|
||||||
|
jakarta.persistence.NonUniqueResultException: Query did not return a unique result: 2 results were returned
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:114)
|
||||||
|
at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:291)
|
||||||
|
at net.miarma.byodsec.common.db.dao.SessionDAO.getByUserId(SessionDAO.java:10)
|
||||||
|
at net.miarma.byodsec.server.RemoteSocket.main(RemoteSocket.java:126)
|
||||||
|
Caused by: org.hibernate.NonUniqueResultException: Query did not return a unique result: 2 results were returned
|
||||||
|
at org.hibernate.query.spi.AbstractSelectionQuery.uniqueElement(AbstractSelectionQuery.java:305)
|
||||||
|
at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:288)
|
||||||
|
... 2 common frames omitted
|
||||||
|
2025-10-20 18:03:22 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:36678
|
||||||
|
2025-10-20 18:03:22 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:03:33 [pool-3-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:50342
|
||||||
|
2025-10-20 18:03:33 [pool-3-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para alvgulveg
|
||||||
|
2025-10-20 18:03:37 [pool-4-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:60208
|
||||||
|
2025-10-20 18:03:37 [pool-4-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de smt4497 a Servidor | illo que
|
||||||
|
2025-10-20 18:03:40 [pool-5-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:60218
|
||||||
|
2025-10-20 18:03:40 [pool-5-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de alvgulveg a Servidor | yoyoyo
|
||||||
|
2025-10-20 18:04:04 [pool-6-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:54898
|
||||||
|
2025-10-20 18:04:04 [pool-6-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para ricolinad
|
||||||
|
2025-10-20 18:04:15 [pool-7-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:35428
|
||||||
|
2025-10-20 18:04:15 [pool-7-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de ricolinad a Servidor | we are number one
|
||||||
|
2025-10-20 18:04:33 [pool-8-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:37304
|
||||||
|
2025-10-20 18:04:33 [pool-8-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:04:35 [pool-9-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:59664
|
||||||
|
2025-10-20 18:04:35 [pool-9-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para b176f04e-6b8a-4447-948a-af290d3ebb82
|
||||||
|
2025-10-20 18:04:35 [pool-10-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:59676
|
||||||
|
2025-10-20 18:04:35 [pool-10-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 85218286-76fc-46af-b3c0-71bb09896531
|
||||||
|
2025-10-20 18:05:47 [pool-11-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:47858
|
||||||
|
2025-10-20 18:05:47 [pool-11-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:05:51 [pool-12-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:47864
|
||||||
|
2025-10-20 18:05:51 [pool-12-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:09:20 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:55666
|
||||||
|
2025-10-20 18:09:20 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:09:27 [pool-3-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:41602
|
||||||
|
2025-10-20 18:09:27 [pool-3-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:10:12 [pool-4-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:46782
|
||||||
|
2025-10-20 18:10:12 [pool-4-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:10:26 [pool-5-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:51828
|
||||||
|
2025-10-20 18:10:26 [pool-5-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:12:48 [pool-6-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34644
|
||||||
|
2025-10-20 18:12:48 [pool-6-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando REGISTER para psancas
|
||||||
|
2025-10-20 18:12:54 [pool-7-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34658
|
||||||
|
2025-10-20 18:12:54 [pool-7-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:12:57 [pool-8-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:56042
|
||||||
|
2025-10-20 18:12:57 [pool-8-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 585d98f3-5951-40d6-8d35-f32b65d9d43e
|
||||||
|
2025-10-20 18:14:48 [pool-9-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:39960
|
||||||
|
2025-10-20 18:14:48 [pool-9-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:14:56 [pool-10-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:60056
|
||||||
|
2025-10-20 18:14:57 [pool-10-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para alvgulveg
|
||||||
|
2025-10-20 18:15:03 [pool-11-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:60068
|
||||||
|
2025-10-20 18:15:03 [pool-11-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:15:07 [pool-12-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34964
|
||||||
|
2025-10-20 18:15:07 [pool-12-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de smt4497 a Servidor | dsadasdas
|
||||||
|
2025-10-20 18:15:09 [pool-13-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34978
|
||||||
|
2025-10-20 18:15:09 [pool-13-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de alvgulveg a Servidor | sfdsgefrgfr
|
||||||
|
2025-10-20 18:15:14 [pool-14-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34986
|
||||||
|
2025-10-20 18:15:14 [pool-14-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de psancas a Servidor | odio a la derecha
|
||||||
|
2025-10-20 18:16:28 [pool-15-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:54852
|
||||||
|
2025-10-20 18:16:28 [pool-15-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de psancas a Servidor | dictadura
|
||||||
|
2025-10-20 18:17:38 [pool-16-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:43520
|
||||||
|
2025-10-20 18:17:38 [pool-16-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para ricolinad
|
||||||
|
2025-10-20 18:17:43 [pool-17-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:43528
|
||||||
|
2025-10-20 18:17:43 [pool-17-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de ricolinad a Servidor | we are number one
|
||||||
|
2025-10-20 18:18:15 [pool-18-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:60346
|
||||||
|
2025-10-20 18:18:16 [pool-18-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:20:10 [pool-19-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34420
|
||||||
|
2025-10-20 18:20:10 [pool-19-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:20:23 [pool-20-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:45642
|
||||||
|
2025-10-20 18:20:23 [pool-20-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:20:45 [pool-21-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:40882
|
||||||
|
2025-10-20 18:20:45 [pool-21-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:20:55 [pool-22-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:35040
|
||||||
|
2025-10-20 18:20:55 [pool-22-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:24:49 [pool-23-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:52902
|
||||||
|
2025-10-20 18:24:49 [pool-23-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:25:08 [pool-24-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:56154
|
||||||
|
2025-10-20 18:25:08 [pool-24-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:25:09 [pool-24-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:90)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:25:20 [pool-25-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:47508
|
||||||
|
2025-10-20 18:25:20 [pool-25-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:25:20 [pool-25-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:90)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:25:22 [pool-26-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:47518
|
||||||
|
2025-10-20 18:25:22 [pool-26-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 18:25:23 [pool-26-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:90)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=195) Duplicate entry 'cb1465ad-6d6d-4784-a2e9-9670a60e778a' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:25:47 [pool-27-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:36890
|
||||||
|
2025-10-20 18:25:47 [pool-27-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
|
2025-10-20 18:32:42 [pool-28-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:47312
|
||||||
|
2025-10-20 18:32:42 [pool-28-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:32:48 [pool-29-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:39420
|
||||||
|
2025-10-20 18:32:48 [pool-29-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:32:49 [pool-29-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.client.ClientHandler.run(ClientHandler.java:90)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:32:55 [pool-30-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:47214
|
||||||
|
2025-10-20 18:32:55 [pool-30-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 585d98f3-5951-40d6-8d35-f32b65d9d43e
|
||||||
|
2025-10-20 18:35:05 [pool-31-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:36694
|
||||||
|
2025-10-20 18:35:05 [pool-31-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:35:06 [pool-32-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:36710
|
||||||
|
2025-10-20 18:35:07 [pool-32-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:35:07 [pool-32-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.client.ClientHandler.run(ClientHandler.java:90)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=195) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:35:22 [pool-33-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:45686
|
||||||
|
2025-10-20 18:35:22 [pool-33-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 585d98f3-5951-40d6-8d35-f32b65d9d43e
|
||||||
|
2025-10-20 18:35:24 [pool-34-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:45688
|
||||||
|
2025-10-20 18:35:24 [pool-34-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:35:26 [pool-35-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:45378
|
||||||
|
2025-10-20 18:35:26 [pool-35-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 585d98f3-5951-40d6-8d35-f32b65d9d43e
|
||||||
|
2025-10-20 18:37:27 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:39072
|
||||||
|
2025-10-20 18:37:27 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:37:31 [pool-3-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:39080
|
||||||
|
2025-10-20 18:37:31 [pool-3-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:37:31 [pool-3-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:93)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:37:39 [pool-4-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:42422
|
||||||
|
2025-10-20 18:37:39 [pool-4-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:37:40 [pool-4-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:93)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:37:44 [pool-5-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:42426
|
||||||
|
2025-10-20 18:37:44 [pool-5-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 585d98f3-5951-40d6-8d35-f32b65d9d43e
|
||||||
|
2025-10-20 18:39:07 [pool-6-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:42476
|
||||||
|
2025-10-20 18:39:07 [pool-6-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:39:20 [pool-7-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:52194
|
||||||
|
2025-10-20 18:39:20 [pool-7-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:39:21 [pool-7-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:93)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 18:41:14 [pool-8-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:49238
|
||||||
|
2025-10-20 18:41:14 [pool-8-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:41:24 [pool-9-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:49240
|
||||||
|
2025-10-20 18:41:24 [pool-9-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 18:41:25 [pool-9-thread-1] ERROR n.miarma.byodsec.server.RemoteSocket - Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
jakarta.persistence.RollbackException: Error while committing the transaction [could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]]
|
||||||
|
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:70)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:93)
|
||||||
|
at net.miarma.byodsec.server.ClientHandler.run(ClientHandler.java:93)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1474)
|
||||||
|
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement [(conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'] [insert into sessions (userId,sessionId) values (?,?)]
|
||||||
|
at org.hibernate.dialect.MariaDBDialect.lambda$buildSQLExceptionConversionDelegate$1(MariaDBDialect.java:379)
|
||||||
|
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:34)
|
||||||
|
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:115)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:193)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:148)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:53)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:66)
|
||||||
|
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:191)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:129)
|
||||||
|
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:101)
|
||||||
|
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:113)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:646)
|
||||||
|
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:513)
|
||||||
|
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:378)
|
||||||
|
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
|
||||||
|
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:140)
|
||||||
|
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1443)
|
||||||
|
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:488)
|
||||||
|
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2321)
|
||||||
|
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2029)
|
||||||
|
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:394)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:167)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:249)
|
||||||
|
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:243)
|
||||||
|
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:90)
|
||||||
|
... 4 common frames omitted
|
||||||
|
Caused by: java.sql.SQLIntegrityConstraintViolationException: (conn=241) Duplicate entry '585d98f3-5951-40d6-8d35-f32b65d9d43e' for key 'userId'
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:301)
|
||||||
|
at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:386)
|
||||||
|
at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:187)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1376)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1315)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:1234)
|
||||||
|
at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:1158)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:91)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:345)
|
||||||
|
at org.mariadb.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:322)
|
||||||
|
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:190)
|
||||||
|
... 26 common frames omitted
|
||||||
|
2025-10-20 22:42:25 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:53230
|
||||||
|
2025-10-20 22:42:25 [pool-2-thread-1] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 22:42:35 [pool-2-thread-2] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:40972
|
||||||
|
2025-10-20 22:42:35 [pool-2-thread-2] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-20 22:43:17 [pool-2-thread-3] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34616
|
||||||
|
2025-10-20 22:43:17 [pool-2-thread-3] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGIN para psancas
|
||||||
|
2025-10-20 22:43:20 [pool-2-thread-4] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34618
|
||||||
|
2025-10-20 22:43:20 [pool-2-thread-4] INFO n.miarma.byodsec.server.RemoteSocket - Procesando SEND_MESSAGE de smt4497 a Servidor | hola
|
||||||
|
2025-10-20 22:43:23 [pool-2-thread-5] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:41190
|
||||||
|
2025-10-20 22:43:23 [pool-2-thread-5] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para 585d98f3-5951-40d6-8d35-f32b65d9d43e
|
||||||
|
2025-10-20 22:43:26 [pool-2-thread-6] INFO n.miarma.byodsec.server.RemoteSocket - Nueva conexión desde /127.0.0.1:41194
|
||||||
|
2025-10-20 22:43:26 [pool-2-thread-6] INFO n.miarma.byodsec.server.RemoteSocket - Procesando LOGOUT para cb1465ad-6d6d-4784-a2e9-9670a60e778a
|
||||||
155
BYODSEC/pom.xml
Normal file
155
BYODSEC/pom.xml
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>net.miarma</groupId>
|
||||||
|
<artifactId>integridos</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>net.miarma.integridos.Integridos</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>25</maven.compiler.source>
|
||||||
|
<maven.compiler.target>25</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- ##### Gson ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.12.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ################ -->
|
||||||
|
|
||||||
|
<!-- ##### SLF4J + Logback #####-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.12</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.5.13</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ########################## -->
|
||||||
|
|
||||||
|
<!-- ##### BASE DE DATOS Y DATA SOURCE ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
|
<version>3.5.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.persistence</groupId>
|
||||||
|
<artifactId>jakarta.persistence-api</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.orm</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>7.1.1.Final</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>5.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ##################################### -->
|
||||||
|
|
||||||
|
<!-- ##### JWT Tokens ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>java-jwt</artifactId>
|
||||||
|
<version>4.5.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ####################### -->
|
||||||
|
|
||||||
|
<!-- ##### BCrypt ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mindrot</groupId>
|
||||||
|
<artifactId>jbcrypt</artifactId>
|
||||||
|
<version>0.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ################### -->
|
||||||
|
|
||||||
|
<!-- ###################### SWING ############################# -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.miglayout</groupId>
|
||||||
|
<artifactId>miglayout-swing</artifactId>
|
||||||
|
<version>11.4.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf-intellij-themes</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf-extras</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont-swing</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont-font_awesome</artifactId>
|
||||||
|
<version>4.7.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont-google_material_design_icons</artifactId>
|
||||||
|
<version>2.2.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ################################################################# -->
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven Shade Plugin -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.5.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>net.miarma.integridos.net.miarma.integridos.Integridos</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
128
BYODSEC/src/main/java/net/miarma/byodsec/Byodsec.java
Normal file
128
BYODSEC/src/main/java/net/miarma/byodsec/Byodsec.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package net.miarma.byodsec;
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
|
||||||
|
import jiconfont.icons.font_awesome.FontAwesome;
|
||||||
|
import jiconfont.icons.google_material_design_icons.GoogleMaterialDesignIcons;
|
||||||
|
import jiconfont.swing.IconFontSwing;
|
||||||
|
import net.miarma.byodsec.common.ConfigManager;
|
||||||
|
import net.miarma.byodsec.common.db.DBPopulator;
|
||||||
|
import net.miarma.byodsec.client.ui.MainWindow;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public class Byodsec {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(Byodsec.class);
|
||||||
|
private static ConfigManager configManager = ConfigManager.getInstance();
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
initConfig();
|
||||||
|
initDB();
|
||||||
|
initProperties();
|
||||||
|
initJKS();
|
||||||
|
initUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initConfig() {
|
||||||
|
File configFile = configManager.getConfigFile();
|
||||||
|
File parentDir = configFile.getParentFile();
|
||||||
|
|
||||||
|
if (!parentDir.exists()) {
|
||||||
|
if (parentDir.mkdirs()) {
|
||||||
|
logger.info("Created app directory: " + parentDir.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
logger.error("Failed to create app directory: " + parentDir.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
try (InputStream in = Byodsec.class.getClassLoader().getResourceAsStream("default.properties")) {
|
||||||
|
if (in != null) {
|
||||||
|
Files.copy(in, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
logger.info("Default config file created at: {}", configFile.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
logger.error("Resource default.properties not found!");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error creating config file: ", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("Config file already exists at: {}", configFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
configManager.loadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initDB() {
|
||||||
|
if(DBPopulator.getInstance().isFirstRun())
|
||||||
|
DBPopulator.getInstance().populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initJKS() {
|
||||||
|
File jksFile = configManager.getJksFile();
|
||||||
|
|
||||||
|
if (!jksFile.exists()) {
|
||||||
|
String path = jksFile.getAbsolutePath();
|
||||||
|
String password = configManager.getStringProperty("jksPassword");
|
||||||
|
|
||||||
|
logger.info("Executing JKS initialization command...");
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(
|
||||||
|
"keytool",
|
||||||
|
"-genkeypair",
|
||||||
|
"-alias", "byodsec",
|
||||||
|
"-keyalg", "RSA",
|
||||||
|
"-keystore", path,
|
||||||
|
"-storepass", password,
|
||||||
|
"-keypass", password,
|
||||||
|
"-dname", "CN=localhost, OU=Byodsec, O=Chat33, L=Sevilla, ST=Andalucia, C=ES",
|
||||||
|
"-validity", "365"
|
||||||
|
);
|
||||||
|
|
||||||
|
pb.inheritIO();
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
process = pb.start();
|
||||||
|
process.waitFor();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error executing JKS initialization command: ", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error("Error executing JKS initialization command: ", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initProperties() {
|
||||||
|
// especificamos mediante propiedades el KS y la contraseña
|
||||||
|
System.setProperty("javax.net.ssl.keyStore", configManager.getJksFile().getAbsolutePath());
|
||||||
|
System.setProperty("javax.net.ssl.keyStorePassword", configManager.getStringProperty("jksPassword"));
|
||||||
|
System.setProperty("javax.net.ssl.trustStore", configManager.getJksFile().getAbsolutePath());
|
||||||
|
System.setProperty("javax.net.ssl.trustStorePassword", configManager.getStringProperty("jksPassword"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initUI() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(new FlatMacDarkLaf());
|
||||||
|
} catch(UnsupportedLookAndFeelException e) {
|
||||||
|
logger.error("Error setting LaF. Falling back to default Swing looks.");
|
||||||
|
}
|
||||||
|
IconFontSwing.register(FontAwesome.getIconFont());
|
||||||
|
IconFontSwing.register(GoogleMaterialDesignIcons.getIconFont());
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
new MainWindow().setVisible(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package net.miarma.byodsec.client;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
import javax.net.ssl.*;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import net.miarma.byodsec.common.ConfigManager;
|
||||||
|
import net.miarma.byodsec.common.db.dto.LoginDTO;
|
||||||
|
import net.miarma.byodsec.common.db.dto.MessageDTO;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketRequest;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketResponse;
|
||||||
|
|
||||||
|
public class ClientSocket implements AutoCloseable {
|
||||||
|
private SSLSocket socket;
|
||||||
|
private PrintWriter output;
|
||||||
|
private BufferedReader input;
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
private final ConfigManager configManager = ConfigManager.getInstance();
|
||||||
|
|
||||||
|
public ClientSocket() throws IOException {
|
||||||
|
configManager.loadConfig();
|
||||||
|
|
||||||
|
// inicializamos el socket SSL, la versión de TLS y los Cipher Suites a utilizar
|
||||||
|
SSLSocketFactory factory;
|
||||||
|
try {
|
||||||
|
factory = initSSL();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException("Error initializing SSL context.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket = (SSLSocket) factory.createSocket("localhost", 6969);
|
||||||
|
this.socket.setEnabledProtocols(new String[]{ "TLSv1.3" });
|
||||||
|
this.socket.setEnabledCipherSuites(new String[]{
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256"
|
||||||
|
});
|
||||||
|
|
||||||
|
// buffers
|
||||||
|
this.output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
|
||||||
|
this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SSLSocketFactory initSSL() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
ks.load(new FileInputStream(configManager.getJksFile().getAbsolutePath()),
|
||||||
|
configManager.getStringProperty("jksPassword").toCharArray());
|
||||||
|
|
||||||
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||||
|
kmf.init(ks, configManager.getStringProperty("jksPassword").toCharArray());
|
||||||
|
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
tmf.init(ks);
|
||||||
|
|
||||||
|
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
|
||||||
|
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||||
|
|
||||||
|
return sslContext.getSocketFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse login(String username, String password) throws IOException {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.LOGIN, new LoginDTO(username, password));
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse register(String username, String password) throws IOException {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.REGISTER, new LoginDTO(username, password));
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse logout(String userId) throws IOException {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.LOGOUT, userId);
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse sendMessage(MessageDTO message) throws Exception {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.SEND_MESSAGE, message);
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
input.close();
|
||||||
|
output.close();
|
||||||
|
socket.close();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package net.miarma.byodsec.client.ui;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class AutoShrinkLabel extends JLabel {
|
||||||
|
public AutoShrinkLabel(String text) {
|
||||||
|
super(text);
|
||||||
|
setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
String text = getText();
|
||||||
|
if (text == null || text.isEmpty()) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Insets insets = getInsets();
|
||||||
|
int availableHeight = getHeight() - insets.top - insets.bottom;
|
||||||
|
int availableWidth = getWidth() - insets.left - insets.right;
|
||||||
|
|
||||||
|
if (availableWidth <= 0 || availableHeight <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics2D graphics2d = (Graphics2D) g.create();
|
||||||
|
|
||||||
|
Font font = getFont();
|
||||||
|
int fontSize = font.getSize();
|
||||||
|
|
||||||
|
FontMetrics fm;
|
||||||
|
int textWidth;
|
||||||
|
int textHeight;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Font testFont = font.deriveFont((float) fontSize);
|
||||||
|
fm = graphics2d.getFontMetrics(testFont);
|
||||||
|
textWidth = fm.stringWidth(text);
|
||||||
|
textHeight = fm.getHeight();
|
||||||
|
if (textWidth <= availableWidth && textHeight <= availableHeight) {
|
||||||
|
font = testFont;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fontSize--;
|
||||||
|
} while (fontSize > 5);
|
||||||
|
|
||||||
|
graphics2d.setFont(font);
|
||||||
|
|
||||||
|
int x = (getWidth() - fm.stringWidth(text)) / 2;
|
||||||
|
int y = (getHeight() + fm.getAscent() - fm.getDescent()) / 2;
|
||||||
|
|
||||||
|
graphics2d.drawString(text, x, y);
|
||||||
|
graphics2d.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(200, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,442 @@
|
|||||||
|
/*
|
||||||
|
* Created by JFormDesigner on Wed Oct 01 16:21:10 CEST 2025
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.miarma.byodsec.client.ui;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import jiconfont.icons.font_awesome.FontAwesome;
|
||||||
|
import jiconfont.swing.IconFontSwing;
|
||||||
|
import net.miarma.byodsec.common.Constants;
|
||||||
|
|
||||||
|
import net.miarma.byodsec.common.security.IntegrityProvider;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketResponse;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketStatus;
|
||||||
|
import net.miarma.byodsec.common.db.dto.MessageDTO;
|
||||||
|
import net.miarma.byodsec.common.db.entities.UserEntity;
|
||||||
|
import net.miarma.byodsec.client.ClientSocket;
|
||||||
|
import net.miginfocom.swing.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jomaa
|
||||||
|
*/
|
||||||
|
public class MainWindow extends JFrame {
|
||||||
|
public static UserEntity _loggedUser;
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ClientSocket.class);
|
||||||
|
|
||||||
|
public MainWindow() {
|
||||||
|
initComponents();
|
||||||
|
this.setTitle(Constants.APP_NAME);
|
||||||
|
versionLabel.setText(Constants.APP_NAME + " v" + Constants.APP_VERSION + " by Security Team 33");
|
||||||
|
setIcons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setIcons() {
|
||||||
|
userLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.USER, 18, Color.WHITE));
|
||||||
|
passwordLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.KEY, 18, Color.WHITE));
|
||||||
|
loginBtn.setIcon(IconFontSwing.buildIcon(FontAwesome.SIGN_IN, 18, Color.WHITE));
|
||||||
|
registerBtn.setIcon(IconFontSwing.buildIcon(FontAwesome.USER_PLUS, 18, Color.WHITE));
|
||||||
|
clientLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.USER_CIRCLE, 16, Color.WHITE));
|
||||||
|
logoutBtn.setIcon(IconFontSwing.buildIcon(FontAwesome.SIGN_OUT, 16, Color.WHITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearLoginInputs() {
|
||||||
|
userTextField.setText("");
|
||||||
|
passwordTextField.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearMainInputs() {
|
||||||
|
clientTextField.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendChatMessage(String message) {
|
||||||
|
chatTextArea.append(message + "\r\n");
|
||||||
|
chatTextArea.setCaretPosition(chatTextArea.getDocument().getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setView(String name) {
|
||||||
|
((CardLayout)getContentPane().getLayout()).show(getContentPane(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loginBtn(ActionEvent e) {
|
||||||
|
String username = userTextField.getText();
|
||||||
|
String password = new String(passwordTextField.getPassword());
|
||||||
|
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
SocketResponse res = client.login(username, password);
|
||||||
|
|
||||||
|
if (res.getStatus() == SocketStatus.OK) {
|
||||||
|
_loggedUser = new Gson().fromJson(
|
||||||
|
new Gson().toJson(res.getData()),
|
||||||
|
UserEntity.class
|
||||||
|
);
|
||||||
|
logger.info("El usuario '{}' ha iniciado sesión correctamente.", username);
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage().getMessage(),
|
||||||
|
res.getStatus().toString(),
|
||||||
|
JOptionPane.INFORMATION_MESSAGE
|
||||||
|
);
|
||||||
|
clientLabel.setText("Cliente: " + _loggedUser.getUserName());
|
||||||
|
this.setTitle(Constants.APP_NAME + " @" + _loggedUser.getUserName());
|
||||||
|
clearLoginInputs();
|
||||||
|
setView("mainPanel");
|
||||||
|
} else if(res.getStatus() == SocketStatus.ALREADY_LOGGED_IN) {
|
||||||
|
logger.info("El usuario '{}' ya tiene una sesión activa.", username);
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje",
|
||||||
|
res.getStatus().toString(),
|
||||||
|
JOptionPane.WARNING_MESSAGE
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.warn("Intento de login fallido para '{}': {}", username,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje");
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje",
|
||||||
|
res.getStatus().toString(),
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("Error de conexión con el servidor al intentar loguear '{}': {}", username, ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerBtn(ActionEvent e) {
|
||||||
|
String username = userTextField.getText();
|
||||||
|
String password = new String(passwordTextField.getPassword());
|
||||||
|
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
SocketResponse res = client.register(username, password);
|
||||||
|
|
||||||
|
if(res.getStatus() == SocketStatus.OK) {
|
||||||
|
logger.info("Usuario '{}' registrado correctamente.", username);
|
||||||
|
} else {
|
||||||
|
logger.warn("Error al registrar '{}': {}", username,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje");
|
||||||
|
}
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje",
|
||||||
|
res.getStatus().toString(),
|
||||||
|
res.getStatus() == SocketStatus.OK ?
|
||||||
|
JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
|
||||||
|
clearLoginInputs();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("Error de conexión con el servidor al registrar '{}': {}", username, ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logout() {
|
||||||
|
if (_loggedUser != null) {
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
SocketResponse res = client.logout(_loggedUser.getUserId());
|
||||||
|
|
||||||
|
if (res != null && res.getMessage() != null) {
|
||||||
|
if (res.getStatus() == SocketStatus.OK) {
|
||||||
|
logger.info("Usuario '{}' ha cerrado sesión correctamente.", _loggedUser.getUserName());
|
||||||
|
this.setTitle(Constants.APP_NAME);
|
||||||
|
} else {
|
||||||
|
logger.warn("Intento de logout de '{}' con estado: {}", _loggedUser.getUserName(), res.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage().getMessage(),
|
||||||
|
res.getStatus().toString(),
|
||||||
|
res.getStatus() == SocketStatus.OK ?
|
||||||
|
JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("Error de conexión con el servidor al hacer logout de '{}': {}", _loggedUser.getUserName(), ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMainInputs();
|
||||||
|
_loggedUser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void thisWindowClosing(WindowEvent e) {
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send(ActionEvent e) {
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
String message = clientTextField.getText();
|
||||||
|
MessageDTO dto = new MessageDTO(_loggedUser.getUserName(), message);
|
||||||
|
SocketResponse res = client.sendMessage(dto);
|
||||||
|
|
||||||
|
appendChatMessage(String.format("%s: %s", _loggedUser.getUserName(), message));
|
||||||
|
appendChatMessage("Servidor: " + res.getData());
|
||||||
|
|
||||||
|
if (res.getStatus() == SocketStatus.OK) {
|
||||||
|
logger.info("Mensaje enviado: {} -> Servidor", _loggedUser.getUserName());
|
||||||
|
} else if (res.getStatus() == SocketStatus.SESSION_EXPIRED) {
|
||||||
|
logger.warn("Sesión expirada para '{}'. Se cerrará sesión.", _loggedUser.getUserName());
|
||||||
|
_loggedUser = null;
|
||||||
|
setView("loginPanel");
|
||||||
|
clearMainInputs();
|
||||||
|
} else {
|
||||||
|
logger.warn("Error enviando mensaje de {} a Servidor: {}", _loggedUser.getUserName(),
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Sin mensaje");
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMainInputs();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error("Error de conexión con el servidor enviando mensaje de {} a Servidor: {}",
|
||||||
|
_loggedUser.getUserName(), ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logoutBtn(ActionEvent e) {
|
||||||
|
logout();
|
||||||
|
setView("loginPanel");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initComponents() {
|
||||||
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
|
||||||
|
// Generated using JFormDesigner Educational license - José Manuel Amador Gallardo (José Manuel Amador)
|
||||||
|
loginPanel = new JPanel();
|
||||||
|
logo = new JLabel();
|
||||||
|
userPanel = new JPanel();
|
||||||
|
userLabel = new JLabel();
|
||||||
|
userTextField = new JTextField();
|
||||||
|
passwordPanel = new JPanel();
|
||||||
|
passwordLabel = new JLabel();
|
||||||
|
passwordTextField = new JPasswordField();
|
||||||
|
loginBtn = new JButton();
|
||||||
|
btnLoginPanel = new JPanel();
|
||||||
|
noAccountLabel = new JLabel();
|
||||||
|
registerBtn = new JButton();
|
||||||
|
versionLabel = new JLabel();
|
||||||
|
mainPanel = new JPanel();
|
||||||
|
chatScrollPane = new JScrollPane();
|
||||||
|
chatTextArea = new JTextArea();
|
||||||
|
clientPanel = new JPanel();
|
||||||
|
clientLabel = new JLabel();
|
||||||
|
logoutBtn = new JButton();
|
||||||
|
clientTextField = new JTextField();
|
||||||
|
|
||||||
|
//======== this ========
|
||||||
|
setResizable(false);
|
||||||
|
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||||
|
addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
thisWindowClosing(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var contentPane = getContentPane();
|
||||||
|
contentPane.setLayout(new CardLayout(6, 6));
|
||||||
|
|
||||||
|
//======== loginPanel ========
|
||||||
|
{
|
||||||
|
loginPanel.setLayout(new MigLayout(
|
||||||
|
"hidemode 3,gapy 12",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[]para" +
|
||||||
|
"[fill]" +
|
||||||
|
"[fill]para" +
|
||||||
|
"[]" +
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- logo ----
|
||||||
|
logo.setIcon(new ImageIcon(getClass().getResource("/images/logo.png")));
|
||||||
|
logo.setMaximumSize(new Dimension(256, 256));
|
||||||
|
logo.setMinimumSize(new Dimension(256, 256));
|
||||||
|
logo.setPreferredSize(new Dimension(256, 256));
|
||||||
|
logo.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||||
|
loginPanel.add(logo, "cell 0 0,alignx center,growx 0");
|
||||||
|
|
||||||
|
//======== userPanel ========
|
||||||
|
{
|
||||||
|
userPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- userLabel ----
|
||||||
|
userLabel.setText("Usuario:");
|
||||||
|
userLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
userLabel.setMaximumSize(new Dimension(130, 23));
|
||||||
|
userLabel.setMinimumSize(new Dimension(130, 23));
|
||||||
|
userLabel.setPreferredSize(new Dimension(130, 23));
|
||||||
|
userPanel.add(userLabel, "cell 0 0");
|
||||||
|
|
||||||
|
//---- userTextField ----
|
||||||
|
userTextField.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
userPanel.add(userTextField, "cell 1 0");
|
||||||
|
}
|
||||||
|
loginPanel.add(userPanel, "cell 0 1");
|
||||||
|
|
||||||
|
//======== passwordPanel ========
|
||||||
|
{
|
||||||
|
passwordPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- passwordLabel ----
|
||||||
|
passwordLabel.setText("Contrase\u00f1a:");
|
||||||
|
passwordLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
passwordLabel.setMaximumSize(new Dimension(130, 23));
|
||||||
|
passwordLabel.setMinimumSize(new Dimension(130, 23));
|
||||||
|
passwordLabel.setPreferredSize(new Dimension(130, 23));
|
||||||
|
passwordPanel.add(passwordLabel, "cell 0 0");
|
||||||
|
|
||||||
|
//---- passwordTextField ----
|
||||||
|
passwordTextField.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
passwordPanel.add(passwordTextField, "cell 1 0");
|
||||||
|
}
|
||||||
|
loginPanel.add(passwordPanel, "cell 0 2");
|
||||||
|
|
||||||
|
//---- loginBtn ----
|
||||||
|
loginBtn.setText("Iniciar sesi\u00f3n");
|
||||||
|
loginBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
loginBtn.addActionListener(e -> loginBtn(e));
|
||||||
|
loginPanel.add(loginBtn, "cell 0 3,alignx trailing,growx 0");
|
||||||
|
|
||||||
|
//======== btnLoginPanel ========
|
||||||
|
{
|
||||||
|
btnLoginPanel.setLayout(new MigLayout(
|
||||||
|
"hidemode 3,aligny bottom",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[]" +
|
||||||
|
"[fill]para" +
|
||||||
|
"[]"));
|
||||||
|
|
||||||
|
//---- noAccountLabel ----
|
||||||
|
noAccountLabel.setText("\u00bfNo tiene cuenta?");
|
||||||
|
btnLoginPanel.add(noAccountLabel, "cell 0 0,alignx center,growx 0");
|
||||||
|
|
||||||
|
//---- registerBtn ----
|
||||||
|
registerBtn.setText("Registrarse");
|
||||||
|
registerBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
registerBtn.addActionListener(e -> registerBtn(e));
|
||||||
|
btnLoginPanel.add(registerBtn, "cell 0 1,alignx center,growx 0");
|
||||||
|
|
||||||
|
//---- versionLabel ----
|
||||||
|
versionLabel.setForeground(new Color(0xa0a0a0));
|
||||||
|
btnLoginPanel.add(versionLabel, "cell 0 2,alignx center,growx 0");
|
||||||
|
}
|
||||||
|
loginPanel.add(btnLoginPanel, "cell 0 4");
|
||||||
|
}
|
||||||
|
contentPane.add(loginPanel, "loginPanel");
|
||||||
|
|
||||||
|
//======== mainPanel ========
|
||||||
|
{
|
||||||
|
mainPanel.setLayout(new MigLayout(
|
||||||
|
"hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]" +
|
||||||
|
"[fill]" +
|
||||||
|
"[fill]"));
|
||||||
|
|
||||||
|
//======== chatScrollPane ========
|
||||||
|
{
|
||||||
|
|
||||||
|
//---- chatTextArea ----
|
||||||
|
chatTextArea.setEditable(false);
|
||||||
|
chatTextArea.setFocusable(false);
|
||||||
|
chatTextArea.setFont(new Font("Adwaita Mono", Font.PLAIN, 16));
|
||||||
|
chatScrollPane.setViewportView(chatTextArea);
|
||||||
|
}
|
||||||
|
mainPanel.add(chatScrollPane, "cell 0 0");
|
||||||
|
|
||||||
|
//======== clientPanel ========
|
||||||
|
{
|
||||||
|
clientPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]" +
|
||||||
|
"[fill]",
|
||||||
|
// rows
|
||||||
|
"[]"));
|
||||||
|
|
||||||
|
//---- clientLabel ----
|
||||||
|
clientLabel.setText("Cliente: $c");
|
||||||
|
clientLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 16));
|
||||||
|
clientPanel.add(clientLabel, "cell 0 0");
|
||||||
|
|
||||||
|
//---- logoutBtn ----
|
||||||
|
logoutBtn.setText("Cerrar sesi\u00f3n");
|
||||||
|
logoutBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 16));
|
||||||
|
logoutBtn.addActionListener(e -> logoutBtn(e));
|
||||||
|
clientPanel.add(logoutBtn, "cell 1 0");
|
||||||
|
}
|
||||||
|
mainPanel.add(clientPanel, "cell 0 1");
|
||||||
|
|
||||||
|
//---- clientTextField ----
|
||||||
|
clientTextField.addActionListener(e -> send(e));
|
||||||
|
mainPanel.add(clientTextField, "cell 0 2");
|
||||||
|
}
|
||||||
|
contentPane.add(mainPanel, "mainPanel");
|
||||||
|
setSize(400, 600);
|
||||||
|
setLocationRelativeTo(getOwner());
|
||||||
|
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
|
||||||
|
// Generated using JFormDesigner Educational license - José Manuel Amador Gallardo (José Manuel Amador)
|
||||||
|
private JPanel loginPanel;
|
||||||
|
private JLabel logo;
|
||||||
|
private JPanel userPanel;
|
||||||
|
private JLabel userLabel;
|
||||||
|
private JTextField userTextField;
|
||||||
|
private JPanel passwordPanel;
|
||||||
|
private JLabel passwordLabel;
|
||||||
|
private JPasswordField passwordTextField;
|
||||||
|
private JButton loginBtn;
|
||||||
|
private JPanel btnLoginPanel;
|
||||||
|
private JLabel noAccountLabel;
|
||||||
|
private JButton registerBtn;
|
||||||
|
private JLabel versionLabel;
|
||||||
|
private JPanel mainPanel;
|
||||||
|
private JScrollPane chatScrollPane;
|
||||||
|
private JTextArea chatTextArea;
|
||||||
|
private JPanel clientPanel;
|
||||||
|
private JLabel clientLabel;
|
||||||
|
private JButton logoutBtn;
|
||||||
|
private JTextField clientTextField;
|
||||||
|
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
JFDML JFormDesigner: "8.2.4.0.393" Java: "21.0.8" encoding: "UTF-8"
|
||||||
|
|
||||||
|
new FormModel {
|
||||||
|
contentType: "form/swing"
|
||||||
|
root: new FormRoot {
|
||||||
|
add( new FormWindow( "javax.swing.JFrame", new FormLayoutManager( class java.awt.CardLayout ) {
|
||||||
|
"hgap": 6
|
||||||
|
"vgap": 6
|
||||||
|
} ) {
|
||||||
|
name: "this"
|
||||||
|
"$sizePolicy": 1
|
||||||
|
"resizable": false
|
||||||
|
"defaultCloseOperation": 3
|
||||||
|
addEvent( new FormEvent( "java.awt.event.WindowListener", "windowClosing", "thisWindowClosing", true ) )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3,gapy 12"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[]para[fill][fill]para[][grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "loginPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "logo"
|
||||||
|
"icon": new com.jformdesigner.model.SwingIcon( 0, "/images/logo.png" )
|
||||||
|
"maximumSize": new java.awt.Dimension( 256, 256 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 256, 256 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 256, 256 )
|
||||||
|
"horizontalTextPosition": 0
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "userPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "userLabel"
|
||||||
|
"text": "Usuario:"
|
||||||
|
"font": &Font0 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
"maximumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||||
|
name: "userTextField"
|
||||||
|
"font": &Font1 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "passwordPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "passwordLabel"
|
||||||
|
"text": "Contraseña:"
|
||||||
|
"font": #Font0
|
||||||
|
"maximumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JPasswordField" ) {
|
||||||
|
name: "passwordTextField"
|
||||||
|
"font": #Font1
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 2"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "loginBtn"
|
||||||
|
"text": "Iniciar sesión"
|
||||||
|
"font": &Font2 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "loginBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 3,alignx trailing,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3,aligny bottom"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[][fill]para[]"
|
||||||
|
} ) {
|
||||||
|
name: "btnLoginPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "noAccountLabel"
|
||||||
|
"text": "¿No tiene cuenta?"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "registerBtn"
|
||||||
|
"text": "Registrarse"
|
||||||
|
"font": #Font2
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "registerBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "versionLabel"
|
||||||
|
"foreground": new java.awt.Color( 160, 160, 160, 255 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 2,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 4"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
|
"value": "loginPanel"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill][fill][fill]"
|
||||||
|
} ) {
|
||||||
|
name: "mainPanel"
|
||||||
|
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||||
|
name: "chatScrollPane"
|
||||||
|
add( new FormComponent( "javax.swing.JTextArea" ) {
|
||||||
|
name: "chatTextArea"
|
||||||
|
"editable": false
|
||||||
|
"focusable": false
|
||||||
|
"font": new java.awt.Font( "Adwaita Mono", 0, 16 )
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[grow,fill][fill]"
|
||||||
|
"$rowConstraints": "[]"
|
||||||
|
} ) {
|
||||||
|
name: "clientPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "clientLabel"
|
||||||
|
"text": "Cliente: $c"
|
||||||
|
"font": &Font3 new java.awt.Font( "Adwaita Sans", 0, 16 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "logoutBtn"
|
||||||
|
"text": "Cerrar sesión"
|
||||||
|
"font": #Font3
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "logoutBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||||
|
name: "clientTextField"
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "send", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 2"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
|
"value": "mainPanel"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( null ) {
|
||||||
|
"location": new java.awt.Point( 0, 0 )
|
||||||
|
"size": new java.awt.Dimension( 400, 600 )
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package net.miarma.byodsec.common;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class ConfigManager {
|
||||||
|
private static ConfigManager INSTANCE;
|
||||||
|
private final File jksFile;
|
||||||
|
private final File configFile;
|
||||||
|
private final Properties config;
|
||||||
|
private static final String JKS_FILE_NAME = "byodsec.jks";
|
||||||
|
private static final String CONFIG_FILE_NAME = "config.properties";
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
|
||||||
|
|
||||||
|
private ConfigManager() {
|
||||||
|
String jksPath = getBaseDir() + JKS_FILE_NAME;
|
||||||
|
String configPath = getBaseDir() + CONFIG_FILE_NAME;
|
||||||
|
this.jksFile = new File(jksPath);
|
||||||
|
this.configFile = new File(configPath);
|
||||||
|
this.config = new Properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigManager getInstance() {
|
||||||
|
if(INSTANCE == null) {
|
||||||
|
INSTANCE = new ConfigManager();
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadConfig() {
|
||||||
|
try (FileInputStream fis = new FileInputStream(configFile);
|
||||||
|
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8)) {
|
||||||
|
config.load(isr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error loading configuration file: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getJksFile() {
|
||||||
|
return jksFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getConfigFile() {
|
||||||
|
return configFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHomeDir() {
|
||||||
|
return getOS() == OSType.WINDOWS ?
|
||||||
|
"C:/Users/" + System.getProperty("user.name") + "/" :
|
||||||
|
getOS() == OSType.LINUX ?
|
||||||
|
(System.getProperty("user.home").contains("root") ? "/root/" :
|
||||||
|
"/home/" + System.getProperty("user.name") + "/") :
|
||||||
|
getOS() == OSType.MACOS ? "/Users/" + System.getProperty("user.name") + "/" : System.getProperty("user.home");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseDir() {
|
||||||
|
return getHomeDir() +
|
||||||
|
(getOS() == OSType.WINDOWS || getOS() == OSType.MACOS ? ".byodsec/" :
|
||||||
|
getOS() == OSType.LINUX ? ".config/byodsec/" :
|
||||||
|
".byodsec/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OSType getOS() {
|
||||||
|
String os = System.getProperty("os.name").toLowerCase();
|
||||||
|
if (os.contains("win")) {
|
||||||
|
return OSType.WINDOWS;
|
||||||
|
} else if (os.contains("nix") || os.contains("nux")) {
|
||||||
|
return OSType.LINUX;
|
||||||
|
} else if (os.contains("mac")) {
|
||||||
|
return OSType.MACOS;
|
||||||
|
} else {
|
||||||
|
return OSType.INVALID_OS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStringProperty(String key) {
|
||||||
|
return config.getProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIntProperty(String key) {
|
||||||
|
String value = config.getProperty(key);
|
||||||
|
return value != null ? Integer.parseInt(value) : 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBooleanProperty(String key) {
|
||||||
|
return Boolean.parseBoolean(config.getProperty(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperty(String key, String value) {
|
||||||
|
config.setProperty(key, value);
|
||||||
|
saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveConfig() {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||||
|
config.store(fos, "Configuration for: " + Constants.APP_NAME);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error saving configuration file: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.miarma.byodsec.common;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
public static final String APP_NAME = "BYODSEC";
|
||||||
|
public static final String APP_VERSION = "1.0.0";
|
||||||
|
|
||||||
|
private Constants() {
|
||||||
|
throw new AssertionError("Utility class cannot be instantiated.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.miarma.byodsec.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum que representa los diferentes tipos de sistemas operativos soportados
|
||||||
|
* @author José Manuel Amador Gallardo
|
||||||
|
*/
|
||||||
|
public enum OSType {
|
||||||
|
LINUX, WINDOWS, MACOS, INVALID_OS
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package net.miarma.byodsec.common.db;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
import jakarta.persistence.Persistence;
|
||||||
|
|
||||||
|
public class DBConnector {
|
||||||
|
private static DBConnector instance;
|
||||||
|
private EntityManagerFactory emf;
|
||||||
|
private final ThreadLocal<EntityManager> threadLocal = new ThreadLocal<>();
|
||||||
|
|
||||||
|
private DBConnector() {
|
||||||
|
this.emf = Persistence.createEntityManagerFactory("ssii-pai2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DBConnector getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DBConnector();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityManager getEntityManager() {
|
||||||
|
EntityManager em = threadLocal.get();
|
||||||
|
if (em == null || !em.isOpen()) {
|
||||||
|
em = emf.createEntityManager();
|
||||||
|
threadLocal.set(em);
|
||||||
|
}
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
EntityManager em = threadLocal.get();
|
||||||
|
if (em != null && em.isOpen()) {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
threadLocal.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package net.miarma.byodsec.common.db;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.TypedQuery;
|
||||||
|
import net.miarma.byodsec.common.security.PasswordHasher;
|
||||||
|
import net.miarma.byodsec.common.db.entities.UserEntity;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class DBPopulator {
|
||||||
|
private final DBConnector conn = DBConnector.getInstance();
|
||||||
|
private EntityManager em;
|
||||||
|
private static DBPopulator instance;
|
||||||
|
|
||||||
|
private DBPopulator() {
|
||||||
|
em = conn.getEntityManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DBPopulator getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DBPopulator();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFirstRun() {
|
||||||
|
TypedQuery<Long> q = em.createQuery("SELECT COUNT(u) FROM UserEntity u", Long.class);
|
||||||
|
Long count = q.getSingleResult();
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populate() {
|
||||||
|
UserEntity u1 = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
"ricolinad", PasswordHasher.hash("ricardo2025"));
|
||||||
|
UserEntity u2 = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
"alvgulveg", PasswordHasher.hash("alcalde_dimision"));
|
||||||
|
UserEntity u3 = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
"smt4497", PasswordHasher.hash("quemenlaus"));
|
||||||
|
try {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(u1);
|
||||||
|
em.persist(u2);
|
||||||
|
em.persist(u3);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
em.getTransaction().rollback();
|
||||||
|
} finally {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package net.miarma.byodsec.common.db.dao;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import net.miarma.byodsec.common.db.entities.SessionEntity;
|
||||||
|
|
||||||
|
public class SessionDAO {
|
||||||
|
public SessionEntity getByUserId(EntityManager em, String userId) {
|
||||||
|
return em.createQuery("SELECT s FROM SessionEntity s WHERE s.userId = :userId", SessionEntity.class)
|
||||||
|
.setParameter("userId", userId)
|
||||||
|
.getSingleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoggedIn(EntityManager em, String userId) {
|
||||||
|
Long count = em.createQuery(
|
||||||
|
"SELECT COUNT(s) FROM SessionEntity s WHERE s.userId = :userId", Long.class)
|
||||||
|
.setParameter("userId", userId)
|
||||||
|
.getSingleResult();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package net.miarma.byodsec.common.db.dao;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import net.miarma.byodsec.common.db.entities.UserEntity;
|
||||||
|
|
||||||
|
public class UserDAO {
|
||||||
|
public UserEntity getByUserName(EntityManager em, String userName) {
|
||||||
|
try {
|
||||||
|
return em.createQuery("SELECT u FROM UserEntity u WHERE u.userName = :userName", UserEntity.class)
|
||||||
|
.setParameter("userName", userName)
|
||||||
|
.getSingleResult();
|
||||||
|
} catch (jakarta.persistence.NoResultException e) {
|
||||||
|
return null; // No se encontró, devolvemos null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.miarma.byodsec.common.db.dto;
|
||||||
|
|
||||||
|
public class LoginDTO {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public LoginDTO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginDTO(String username, String password) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package net.miarma.byodsec.common.db.dto;
|
||||||
|
|
||||||
|
public class MessageDTO {
|
||||||
|
private String fromUserName;
|
||||||
|
private String messageText;
|
||||||
|
|
||||||
|
public MessageDTO() {}
|
||||||
|
|
||||||
|
public MessageDTO(String fromUserName, String messageText) {
|
||||||
|
this.fromUserName = fromUserName;
|
||||||
|
this.messageText = messageText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFromUserName() {
|
||||||
|
return fromUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromUserName(String fromUserName) {
|
||||||
|
this.fromUserName = fromUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageText() {
|
||||||
|
return messageText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageText(String messageText) {
|
||||||
|
this.messageText = messageText;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package net.miarma.byodsec.common.db.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "sessions")
|
||||||
|
public class SessionEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name = "sessionId", nullable = false, updatable = false)
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
@Column(name = "userId", nullable = false)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column(name = "createdAt", nullable = false, updatable = false, insertable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(name = "expiresAt", nullable = false, updatable = false, insertable = false)
|
||||||
|
private LocalDateTime expiresAt;
|
||||||
|
|
||||||
|
public SessionEntity() {}
|
||||||
|
|
||||||
|
public SessionEntity(String sessionId, String userId, LocalDateTime createdAt, LocalDateTime expiresAt) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionId(String sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getExpiresAt() {
|
||||||
|
return expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiresAt(LocalDateTime expiresAt) {
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package net.miarma.byodsec.common.db.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
public class UserEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name = "userId", nullable = false, updatable = false, length = 36)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column(name = "userName", unique = true, nullable = false, length = 64)
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
@Column(name = "password", nullable = false, length = 256)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public UserEntity() {}
|
||||||
|
|
||||||
|
public UserEntity(String userId, String userName, String password) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.userName = userName;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.miarma.byodsec.common.security;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class IntegrityProvider {
|
||||||
|
public static String generateHMAC(String key, String data) throws Exception {
|
||||||
|
Mac sha256HMAC = Mac.getInstance("HmacSHA256");
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||||
|
sha256HMAC.init(secretKey);
|
||||||
|
return byteArrayToHex(sha256HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generateNonce() {
|
||||||
|
byte[] nonce = new byte[16];
|
||||||
|
new SecureRandom().nextBytes(nonce);
|
||||||
|
return Base64.getEncoder().encodeToString(nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String byteArrayToHex(byte[] arr) {
|
||||||
|
StringBuilder sb = new StringBuilder(arr.length * 2);
|
||||||
|
for(byte b : arr) {
|
||||||
|
sb.append(String.format("%02x", b));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package net.miarma.byodsec.common.security;
|
||||||
|
|
||||||
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clase de utilidad para el hash de contraseñas.
|
||||||
|
* Utiliza BCrypt para generar y verificar hashes de contraseñas.
|
||||||
|
*
|
||||||
|
* @author José Manuel Amador Gallardo
|
||||||
|
*/
|
||||||
|
public class PasswordHasher {
|
||||||
|
|
||||||
|
private static final int SALT_ROUNDS = 12;
|
||||||
|
|
||||||
|
public static String hash(String plainPassword) {
|
||||||
|
return BCrypt.hashpw(plainPassword, BCrypt.gensalt(SALT_ROUNDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean verify(String plainPassword, String hashedPassword) {
|
||||||
|
return BCrypt.checkpw(plainPassword, hashedPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package net.miarma.byodsec.common.socket;
|
||||||
|
|
||||||
|
public class SocketRequest {
|
||||||
|
private SocketRequest.Action action;
|
||||||
|
private Object payload;
|
||||||
|
|
||||||
|
public SocketRequest() {}
|
||||||
|
|
||||||
|
public SocketRequest(SocketRequest.Action action, Object payload) {
|
||||||
|
this.action = action;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketRequest.Action getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(SocketRequest.Action action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayload(Object payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SocketRequest{" +
|
||||||
|
"action='" + action.name() + '\'' +
|
||||||
|
", payload=" + (payload != null ? payload.toString() : "null") +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
LOGIN, REGISTER, SEND_MESSAGE, LOGOUT
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package net.miarma.byodsec.common.socket;
|
||||||
|
|
||||||
|
public class SocketResponse {
|
||||||
|
|
||||||
|
private SocketStatus status;
|
||||||
|
private Message message;
|
||||||
|
private Object data;
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status, Message message) {
|
||||||
|
this(status, message, message != null ? message.getMessage() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status, Message message, Object data) {
|
||||||
|
this.status = status;
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SocketResponse{" +
|
||||||
|
"status=" + status +
|
||||||
|
", message=" + (message != null ? message.name() : "null") +
|
||||||
|
", data=" + (data != null ? data.toString() : "null") +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Message {
|
||||||
|
LOGGED_OUT("Ha cerrado sesión correctamente"),
|
||||||
|
LOGGED_IN("Ha iniciado sesión correctamente"),
|
||||||
|
MESSAGE_SENT("Su mensaje se ha enviado"),
|
||||||
|
USER_NOT_FOUND("El usuario no existe."),
|
||||||
|
WRONG_PASSWORD("Contraseña incorrecta."),
|
||||||
|
USER_ALREADY_EXISTS("El usuario ya está registrado."),
|
||||||
|
CONNECTION_ERROR("Error de conexión con el servidor."),
|
||||||
|
UNKNOWN_ERROR("Ha ocurrido un error inesperado."),
|
||||||
|
SESSION_EXPIRED("Tu sesión ha expirado."),
|
||||||
|
INTEGRITY_FAIL("Fallo de integridad en el mensaje."),
|
||||||
|
INVALID_AMOUNT("Cantidad no válida."),
|
||||||
|
REPLAY_ATTACK("Intento de repetición detectado."),
|
||||||
|
RECIPIENT_NOT_FOUND("El destinatario no existe"),
|
||||||
|
REGISTERED("Se ha registrado correctamente"),
|
||||||
|
SESSION_ACTIVE("Ya hay una sesión activa para este usuario.");
|
||||||
|
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
Message(String userMessage) {
|
||||||
|
this.message = userMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.miarma.byodsec.common.socket;
|
||||||
|
|
||||||
|
public enum SocketStatus {
|
||||||
|
OK,
|
||||||
|
ERROR,
|
||||||
|
SESSION_EXPIRED,
|
||||||
|
ALREADY_LOGGED_IN,
|
||||||
|
INTEGRITY_FAIL,
|
||||||
|
UNAUTHORIZED,
|
||||||
|
INVALID_REQUEST;
|
||||||
|
|
||||||
|
public static boolean isOk(String status) {
|
||||||
|
return OK.name().equalsIgnoreCase(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
package net.miarma.byodsec.server;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import net.miarma.byodsec.common.db.DBConnector;
|
||||||
|
import net.miarma.byodsec.common.db.dao.SessionDAO;
|
||||||
|
import net.miarma.byodsec.common.db.dao.UserDAO;
|
||||||
|
import net.miarma.byodsec.common.db.dto.LoginDTO;
|
||||||
|
import net.miarma.byodsec.common.db.dto.MessageDTO;
|
||||||
|
import net.miarma.byodsec.common.db.entities.SessionEntity;
|
||||||
|
import net.miarma.byodsec.common.db.entities.UserEntity;
|
||||||
|
import net.miarma.byodsec.common.security.PasswordHasher;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketRequest;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketResponse;
|
||||||
|
import net.miarma.byodsec.common.socket.SocketStatus;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ClientHandler implements Runnable {
|
||||||
|
private final SSLSocket socket;
|
||||||
|
private final Gson gson;
|
||||||
|
private final UserDAO userDAO;
|
||||||
|
private final SessionDAO sessionDAO;
|
||||||
|
private final DBConnector conn;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
public ClientHandler(SSLSocket socket, Gson gson, UserDAO userDAO, SessionDAO sessionDAO, DBConnector conn, Logger logger) {
|
||||||
|
this.socket = socket;
|
||||||
|
this.gson = gson;
|
||||||
|
this.userDAO = userDAO;
|
||||||
|
this.sessionDAO = sessionDAO;
|
||||||
|
this.conn = conn;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try (
|
||||||
|
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
|
||||||
|
) {
|
||||||
|
logger.info("Nueva conexión desde {}:{}", socket.getInetAddress(), socket.getPort());
|
||||||
|
SocketRequest msg = gson.fromJson(input.readLine(), SocketRequest.class);
|
||||||
|
SocketResponse res;
|
||||||
|
|
||||||
|
switch (msg.getAction()) {
|
||||||
|
case REGISTER -> {
|
||||||
|
LoginDTO dto = gson.fromJson(gson.toJson(msg.getPayload()), LoginDTO.class);
|
||||||
|
logger.info("Procesando REGISTER para {}", dto.getUsername());
|
||||||
|
EntityManager em = conn.getEntityManager();
|
||||||
|
try {
|
||||||
|
if (userDAO.getByUserName(em, dto.getUsername()) != null) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.USER_ALREADY_EXISTS);
|
||||||
|
} else {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
UserEntity u = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
dto.getUsername(), PasswordHasher.hash(dto.getPassword()));
|
||||||
|
em.persist(u);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.REGISTERED, u);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (em.getTransaction().isActive()) em.getTransaction().rollback();
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
res = new SocketResponse(SocketStatus.ERROR, SocketResponse.Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
conn.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case LOGIN -> {
|
||||||
|
LoginDTO dto = gson.fromJson(gson.toJson(msg.getPayload()), LoginDTO.class);
|
||||||
|
logger.info("Procesando LOGIN para {}", dto.getUsername());
|
||||||
|
try (EntityManager em = conn.getEntityManager()) {
|
||||||
|
UserEntity user = userDAO.getByUserName(em, dto.getUsername());
|
||||||
|
if (user == null) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.USER_NOT_FOUND);
|
||||||
|
} else if (PasswordHasher.verify(dto.getPassword(), user.getPassword())) {
|
||||||
|
if(sessionDAO.isLoggedIn(em, user.getUserId())) {
|
||||||
|
res = new SocketResponse(SocketStatus.ALREADY_LOGGED_IN, SocketResponse.Message.SESSION_ACTIVE);
|
||||||
|
} else {
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.LOGGED_IN, user);
|
||||||
|
|
||||||
|
SessionEntity session = new SessionEntity();
|
||||||
|
session.setSessionId(UUID.randomUUID().toString());
|
||||||
|
session.setUserId(user.getUserId());
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(session);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.WRONG_PASSWORD);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
res = new SocketResponse(SocketStatus.ERROR, SocketResponse.Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case LOGOUT -> {
|
||||||
|
String userId = gson.fromJson(gson.toJson(msg.getPayload()), String.class);
|
||||||
|
logger.info("Procesando LOGOUT para {}", userId);
|
||||||
|
try (EntityManager em = conn.getEntityManager()) {
|
||||||
|
SessionEntity session = sessionDAO.getByUserId(em, userId);
|
||||||
|
if (session != null) {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.remove(session);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.LOGGED_OUT);
|
||||||
|
} else {
|
||||||
|
res = new SocketResponse(SocketStatus.SESSION_EXPIRED, SocketResponse.Message.SESSION_EXPIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case SEND_MESSAGE -> {
|
||||||
|
MessageDTO dto = gson.fromJson(gson.toJson(msg.getPayload()), MessageDTO.class);
|
||||||
|
|
||||||
|
logger.info("Procesando SEND_MESSAGE de {} a Servidor | {}", dto.getFromUserName(), dto.getMessageText());
|
||||||
|
|
||||||
|
EntityManager em = conn.getEntityManager();
|
||||||
|
try {
|
||||||
|
UserEntity fromUser = userDAO.getByUserName(em, dto.getFromUserName());
|
||||||
|
|
||||||
|
if (fromUser == null || !sessionDAO.isLoggedIn(em, fromUser.getUserId())) {
|
||||||
|
res = new SocketResponse(SocketStatus.SESSION_EXPIRED, SocketResponse.Message.SESSION_EXPIRED);
|
||||||
|
} else if (dto.getMessageText().isBlank()) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.INVALID_AMOUNT);
|
||||||
|
} else {
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.MESSAGE_SENT, dto.getMessageText());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
res = new SocketResponse(SocketStatus.ERROR, SocketResponse.Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
conn.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default -> {
|
||||||
|
logger.warn("Acción desconocida recibida: {}", msg.getAction());
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.println(gson.toJson(res));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package net.miarma.byodsec.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLServerSocket;
|
||||||
|
import javax.net.ssl.SSLServerSocketFactory;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
|
||||||
|
import net.miarma.byodsec.common.ConfigManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import net.miarma.byodsec.common.db.DBConnector;
|
||||||
|
import net.miarma.byodsec.common.db.dao.SessionDAO;
|
||||||
|
import net.miarma.byodsec.common.db.dao.UserDAO;
|
||||||
|
|
||||||
|
public class RemoteSocket {
|
||||||
|
static void main(String[] args) throws IOException {
|
||||||
|
ConfigManager configManager = ConfigManager.getInstance();
|
||||||
|
configManager.loadConfig();
|
||||||
|
DBConnector conn = DBConnector.getInstance();
|
||||||
|
UserDAO userDAO = new UserDAO();
|
||||||
|
SessionDAO sessionDAO = new SessionDAO();
|
||||||
|
Gson gson = new Gson();
|
||||||
|
final Logger logger = LoggerFactory.getLogger(RemoteSocket.class);
|
||||||
|
|
||||||
|
// especificamos mediante propiedades el KS y la contraseña
|
||||||
|
System.setProperty("javax.net.ssl.keyStore", configManager.getJksFile().getAbsolutePath());
|
||||||
|
System.setProperty("javax.net.ssl.keyStorePassword", configManager.getStringProperty("jksPassword"));
|
||||||
|
System.setProperty("javax.net.ssl.trustStore", configManager.getJksFile().getAbsolutePath());
|
||||||
|
System.setProperty("javax.net.ssl.trustStorePassword", configManager.getStringProperty("jksPassword"));
|
||||||
|
|
||||||
|
// inicializamos el socket SSL, la versión de TLS y los Cipher Suites a utilizar
|
||||||
|
SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
||||||
|
SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(6969);
|
||||||
|
serverSocket.setEnabledProtocols(new String[]{ "TLSv1.3" });
|
||||||
|
serverSocket.setEnabledCipherSuites(new String[]{
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256"
|
||||||
|
});
|
||||||
|
serverSocket.setNeedClientAuth(true);
|
||||||
|
|
||||||
|
// main loop
|
||||||
|
Executor executor = Executors.newFixedThreadPool(300);
|
||||||
|
while (true) {
|
||||||
|
SSLSocket socket = (SSLSocket) serverSocket.accept();
|
||||||
|
executor.execute(new ClientHandler(socket, gson, userDAO, sessionDAO, conn, logger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
BYODSEC/src/main/resources/META-INF/persistence.xml
Normal file
29
BYODSEC/src/main/resources/META-INF/persistence.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||||
|
version="2.0">
|
||||||
|
|
||||||
|
<persistence-unit name="ssii-pai2">
|
||||||
|
<description>
|
||||||
|
Persistence unit for PAI-2
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<class>net.miarma.byodsec.common.db.entities.UserEntity</class>
|
||||||
|
<class>net.miarma.byodsec.common.db.entities.SessionEntity</class>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="jakarta.persistence.jdbc.url" value="jdbc:mariadb://miarma.net:3307/pai2" />
|
||||||
|
<property name="jakarta.persistence.jdbc.user" value="admin" />
|
||||||
|
<property name="jakarta.persistence.jdbc.password" value="55ii.P4I.1;" />
|
||||||
|
<property name="jakarta.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/>
|
||||||
|
<property name="hibernate.dialect" value="org.hibernate.dialect.MariaDBDialect" />
|
||||||
|
|
||||||
|
<property name="hibernate.show_sql" value="true" />
|
||||||
|
<property name="hibernate.format_sql" value="true" />
|
||||||
|
<property name="hibernate.highlight_sql" value="true" />
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</persistence-unit>
|
||||||
|
|
||||||
|
</persistence>
|
||||||
|
|
||||||
1
BYODSEC/src/main/resources/default.properties
Normal file
1
BYODSEC/src/main/resources/default.properties
Normal file
@@ -0,0 +1 @@
|
|||||||
|
jksPassword=
|
||||||
BIN
BYODSEC/src/main/resources/images/banco.png
Normal file
BIN
BYODSEC/src/main/resources/images/banco.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
BYODSEC/src/main/resources/images/logo.png
Normal file
BIN
BYODSEC/src/main/resources/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
53
BYODSEC/src/main/resources/logback.xml
Normal file
53
BYODSEC/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="CLIENT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/client.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/client-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="SERVER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/server.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/server-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="net.miarma.byodsec.ui" level="INFO" additivity="false">
|
||||||
|
<appender-ref ref="CLIENT"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="net.miarma.byodsec.client.ClientSocket" level="INFO" additivity="false">
|
||||||
|
<appender-ref ref="CLIENT"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="net.miarma.byodsec.server.RemoteSocket" level="DEBUG" additivity="false">
|
||||||
|
<appender-ref ref="SERVER"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="net.miarma.byodsec.db" level="INFO" additivity="false">
|
||||||
|
<appender-ref ref="SERVER"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
27
BYODSEC/src/main/resources/scripts/db.sql
Normal file
27
BYODSEC/src/main/resources/scripts/db.sql
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
USE pai2;
|
||||||
|
|
||||||
|
-- Cleanup
|
||||||
|
DROP TABLE IF EXISTS sessions;
|
||||||
|
DROP TABLE IF EXISTS users;
|
||||||
|
-- END Cleanup
|
||||||
|
|
||||||
|
-- DDL
|
||||||
|
CREATE TABLE users (
|
||||||
|
userId UUID NOT NULL PRIMARY KEY,
|
||||||
|
userName VARCHAR(64) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(256) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sessions (
|
||||||
|
sessionId UUID NOT NULL PRIMARY KEY,
|
||||||
|
userId UUID NOT NULL UNIQUE,
|
||||||
|
createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
expiresAt TIMESTAMP AS (createdAt + INTERVAL 15 MINUTE) STORED,
|
||||||
|
FOREIGN KEY (userId) REFERENCES users(userId) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE EVENT IF NOT EXISTS clear_expired_sessions
|
||||||
|
ON SCHEDULE EVERY 1 MINUTE
|
||||||
|
DO
|
||||||
|
DELETE FROM sessions WHERE expiresAt <= NOW();
|
||||||
|
-- END DDL
|
||||||
0
DevSecOps/.gitkeep
Normal file
0
DevSecOps/.gitkeep
Normal file
2
Integridos/.gitignore
vendored
Normal file
2
Integridos/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.env
|
||||||
|
target/
|
||||||
15
Integridos/log/client.log
Normal file
15
Integridos/log/client.log
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
2025-10-06 19:44:03 INFO n.m.integridos.client.ClientSocket - El usuario 'alvgulveg' ha iniciado sesión correctamente.
|
||||||
|
2025-10-06 19:44:12 INFO n.m.integridos.client.ClientSocket - Transacción enviada: alvgulveg -> smt4497 | 50.0€
|
||||||
|
2025-10-06 19:44:13 INFO n.m.integridos.client.ClientSocket - Usuario 'alvgulveg' ha cerrado sesión correctamente.
|
||||||
|
2025-10-06 19:48:16 WARN n.m.integridos.client.ClientSocket - Intento de login fallido para 'noexiste': El usuario no existe.
|
||||||
|
2025-10-06 19:48:53 INFO n.m.integridos.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-06 19:49:14 INFO n.m.integridos.client.ClientSocket - Transacción enviada: smt4497 -> alvgulveg | 50.0€
|
||||||
|
2025-10-06 19:49:14 INFO n.m.integridos.client.ClientSocket - Usuario 'smt4497' ha cerrado sesión correctamente.
|
||||||
|
2025-10-06 19:49:35 WARN n.m.integridos.client.ClientSocket - Intento de login fallido para 'smt4497': Contraseña incorrecta.
|
||||||
|
2025-10-06 19:57:25 INFO n.m.integridos.client.ClientSocket - El usuario 'smt4497' ha iniciado sesión correctamente.
|
||||||
|
2025-10-06 19:57:31 WARN n.m.integridos.client.ClientSocket - Error enviando transacción de smt4497 a alvgulveg: Cantidad no válida.
|
||||||
|
2025-10-06 19:57:38 WARN n.m.integridos.client.ClientSocket - Error enviando transacción de smt4497 a alvgulveg: Cantidad no válida.
|
||||||
|
2025-10-06 19:57:42 WARN n.m.integridos.client.ClientSocket - Error enviando transacción de smt4497 a noexiste: El destinatario no existe
|
||||||
|
2025-10-06 19:57:52 INFO n.m.integridos.client.ClientSocket - Usuario 'smt4497' ha cerrado sesión correctamente.
|
||||||
|
2025-10-06 19:57:58 WARN n.m.integridos.client.ClientSocket - Intento de login fallido para 'alvgulveg': Contraseña incorrecta.
|
||||||
|
2025-10-06 19:58:04 WARN n.m.integridos.client.ClientSocket - Intento de login fallido para 'noexiste': El usuario no existe.
|
||||||
46
Integridos/log/server.log
Normal file
46
Integridos/log/server.log
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
2025-10-06 19:44:02 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:58622
|
||||||
|
2025-10-06 19:44:02 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para alvgulveg
|
||||||
|
2025-10-06 19:44:11 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:36988
|
||||||
|
2025-10-06 19:44:11 [main] INFO n.m.integridos.server.RemoteSocket - Procesando SEND_TRANSACTION de alvgulveg a smt4497 | 50.0
|
||||||
|
2025-10-06 19:44:13 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:36992
|
||||||
|
2025-10-06 19:44:13 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGOUT para 5b3532d0-d6ff-4845-8aa0-03a1d11a94b2
|
||||||
|
2025-10-06 19:48:16 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34878
|
||||||
|
2025-10-06 19:48:16 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para noexiste
|
||||||
|
2025-10-06 19:48:53 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:34066
|
||||||
|
2025-10-06 19:48:53 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-06 19:49:13 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:44270
|
||||||
|
2025-10-06 19:49:13 [main] INFO n.m.integridos.server.RemoteSocket - Procesando SEND_TRANSACTION de smt4497 a alvgulveg | 50.0
|
||||||
|
2025-10-06 19:49:13 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC recibida: 7f00bda9f22b98fdfbd0f2c1b61b4d40cd0eca66a38efb1304adf3fd33599fe0
|
||||||
|
2025-10-06 19:49:13 [main] DEBUG n.m.integridos.server.RemoteSocket - Mensaje JSON para calcular HMAC: {"action":"SEND_TRANSACTION","payload":{"fromUserName":"smt4497","toUserName":"alvgulveg","amount":50.0,"nonce":"x8Dsu3aNocd014/bH7lymw\u003d\u003d"}}
|
||||||
|
2025-10-06 19:49:13 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC generada: 7f00bda9f22b98fdfbd0f2c1b61b4d40cd0eca66a38efb1304adf3fd33599fe0
|
||||||
|
2025-10-06 19:49:13 [main] DEBUG n.m.integridos.server.RemoteSocket - Las HMAC coinciden
|
||||||
|
2025-10-06 19:49:14 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:44274
|
||||||
|
2025-10-06 19:49:14 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGOUT para 06a85107-285d-4b10-a412-427e63afecfb
|
||||||
|
2025-10-06 19:49:35 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:59576
|
||||||
|
2025-10-06 19:49:35 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-06 19:57:25 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:55456
|
||||||
|
2025-10-06 19:57:25 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para smt4497
|
||||||
|
2025-10-06 19:57:31 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:41488
|
||||||
|
2025-10-06 19:57:31 [main] INFO n.m.integridos.server.RemoteSocket - Procesando SEND_TRANSACTION de smt4497 a alvgulveg | -10.0
|
||||||
|
2025-10-06 19:57:31 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC recibida: 25417b475e6cf28707e519bb6d49a1241d502de90ef5db3c2ab384fcabdb6bdf
|
||||||
|
2025-10-06 19:57:31 [main] DEBUG n.m.integridos.server.RemoteSocket - Mensaje JSON para calcular HMAC: {"action":"SEND_TRANSACTION","payload":{"fromUserName":"smt4497","toUserName":"alvgulveg","amount":-10.0,"nonce":"Z5vRIKxPXsBBV6LKKZZITg\u003d\u003d"}}
|
||||||
|
2025-10-06 19:57:31 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC generada: 25417b475e6cf28707e519bb6d49a1241d502de90ef5db3c2ab384fcabdb6bdf
|
||||||
|
2025-10-06 19:57:31 [main] DEBUG n.m.integridos.server.RemoteSocket - Las HMAC coinciden
|
||||||
|
2025-10-06 19:57:37 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:50254
|
||||||
|
2025-10-06 19:57:37 [main] INFO n.m.integridos.server.RemoteSocket - Procesando SEND_TRANSACTION de smt4497 a alvgulveg | 1000.0
|
||||||
|
2025-10-06 19:57:37 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC recibida: 2e2ac0a1df12e8127bdb046a932cee65187c872fbc536161d0b982037142fc76
|
||||||
|
2025-10-06 19:57:37 [main] DEBUG n.m.integridos.server.RemoteSocket - Mensaje JSON para calcular HMAC: {"action":"SEND_TRANSACTION","payload":{"fromUserName":"smt4497","toUserName":"alvgulveg","amount":1000.0,"nonce":"3dOKgYJ9fKOV4IdU/94Arg\u003d\u003d"}}
|
||||||
|
2025-10-06 19:57:37 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC generada: 2e2ac0a1df12e8127bdb046a932cee65187c872fbc536161d0b982037142fc76
|
||||||
|
2025-10-06 19:57:37 [main] DEBUG n.m.integridos.server.RemoteSocket - Las HMAC coinciden
|
||||||
|
2025-10-06 19:57:42 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:50270
|
||||||
|
2025-10-06 19:57:42 [main] INFO n.m.integridos.server.RemoteSocket - Procesando SEND_TRANSACTION de smt4497 a noexiste | 10.0
|
||||||
|
2025-10-06 19:57:42 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC recibida: dea4a26a0fee02ae093acff80eca84d6409918b58dcc0e1706f8c5bf77bdaa31
|
||||||
|
2025-10-06 19:57:42 [main] DEBUG n.m.integridos.server.RemoteSocket - Mensaje JSON para calcular HMAC: {"action":"SEND_TRANSACTION","payload":{"fromUserName":"smt4497","toUserName":"noexiste","amount":10.0,"nonce":"ok94L3xsMJG/626yvUlyRQ\u003d\u003d"}}
|
||||||
|
2025-10-06 19:57:42 [main] DEBUG n.m.integridos.server.RemoteSocket - HMAC generada: dea4a26a0fee02ae093acff80eca84d6409918b58dcc0e1706f8c5bf77bdaa31
|
||||||
|
2025-10-06 19:57:42 [main] DEBUG n.m.integridos.server.RemoteSocket - Las HMAC coinciden
|
||||||
|
2025-10-06 19:57:51 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:53674
|
||||||
|
2025-10-06 19:57:51 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGOUT para 06a85107-285d-4b10-a412-427e63afecfb
|
||||||
|
2025-10-06 19:57:58 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:42006
|
||||||
|
2025-10-06 19:57:58 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para alvgulveg
|
||||||
|
2025-10-06 19:58:04 [main] INFO n.m.integridos.server.RemoteSocket - Nueva conexión desde /127.0.0.1:42008
|
||||||
|
2025-10-06 19:58:04 [main] INFO n.m.integridos.server.RemoteSocket - Procesando LOGIN para noexiste
|
||||||
155
Integridos/pom.xml
Normal file
155
Integridos/pom.xml
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>net.miarma</groupId>
|
||||||
|
<artifactId>integridos</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>net.miarma.integridos.Integridos</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>25</maven.compiler.source>
|
||||||
|
<maven.compiler.target>25</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- ##### Gson ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.12.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ################ -->
|
||||||
|
|
||||||
|
<!-- ##### SLF4J + Logback #####-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.12</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.5.13</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ########################## -->
|
||||||
|
|
||||||
|
<!-- ##### BASE DE DATOS Y DATA SOURCE ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
|
<version>3.5.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.persistence</groupId>
|
||||||
|
<artifactId>jakarta.persistence-api</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.orm</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>7.1.1.Final</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>5.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ##################################### -->
|
||||||
|
|
||||||
|
<!-- ##### JWT Tokens ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>java-jwt</artifactId>
|
||||||
|
<version>4.5.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ####################### -->
|
||||||
|
|
||||||
|
<!-- ##### BCrypt ##### -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mindrot</groupId>
|
||||||
|
<artifactId>jbcrypt</artifactId>
|
||||||
|
<version>0.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ################### -->
|
||||||
|
|
||||||
|
<!-- ###################### SWING ############################# -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.miglayout</groupId>
|
||||||
|
<artifactId>miglayout-swing</artifactId>
|
||||||
|
<version>11.4.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf-intellij-themes</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf-extras</artifactId>
|
||||||
|
<version>3.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont-swing</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont-font_awesome</artifactId>
|
||||||
|
<version>4.7.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jiconfont</groupId>
|
||||||
|
<artifactId>jiconfont-google_material_design_icons</artifactId>
|
||||||
|
<version>2.2.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ################################################################# -->
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Maven Shade Plugin -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.5.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>net.miarma.integridos.net.miarma.integridos.Integridos</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
8
Integridos/src/main/java/module-info.java
Normal file
8
Integridos/src/main/java/module-info.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
module BYODSEC {
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package net.miarma.integridos;
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.themes.FlatMacLightLaf;
|
||||||
|
import jiconfont.icons.font_awesome.FontAwesome;
|
||||||
|
import jiconfont.icons.google_material_design_icons.GoogleMaterialDesignIcons;
|
||||||
|
import jiconfont.swing.IconFontSwing;
|
||||||
|
import net.miarma.integridos.common.ConfigManager;
|
||||||
|
import net.miarma.integridos.common.Constants;
|
||||||
|
import net.miarma.integridos.common.db.DBPopulator;
|
||||||
|
import net.miarma.integridos.client.ui.MainWindow;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
|
public class Integridos {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(Integridos.class);
|
||||||
|
private static ConfigManager configManager;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
configManager = ConfigManager.getInstance();
|
||||||
|
createFiles();
|
||||||
|
configManager.loadConfig();
|
||||||
|
if(DBPopulator.getInstance().isFirstRun()) {
|
||||||
|
DBPopulator.getInstance().populate();
|
||||||
|
}
|
||||||
|
initUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initUI() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(new FlatMacLightLaf());
|
||||||
|
} catch(UnsupportedLookAndFeelException e) {
|
||||||
|
logger.error("Error setting LaF. Falling back to default Swing looks.");
|
||||||
|
}
|
||||||
|
IconFontSwing.register(FontAwesome.getIconFont());
|
||||||
|
IconFontSwing.register(GoogleMaterialDesignIcons.getIconFont());
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
new MainWindow().setVisible(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createFiles() {
|
||||||
|
File configFile = new File(configManager.getConfigFile().getAbsolutePath());
|
||||||
|
File parentDir = configFile.getParentFile();
|
||||||
|
|
||||||
|
if (!parentDir.exists()) {
|
||||||
|
if (parentDir.mkdirs()) {
|
||||||
|
logger.info("Created config directory: " + parentDir.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
logger.error("Failed to create config directory: " + parentDir.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
try (InputStream in = Integridos.class.getClassLoader().getResourceAsStream("default.properties")) {
|
||||||
|
if (in != null) {
|
||||||
|
Files.copy(in, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
logger.info("Default config file created at: " + configFile.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
logger.error("Resource default.properties not found!");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error creating config file: ", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("Config file already exists at: " + configFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package net.miarma.integridos.client;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import net.miarma.integridos.common.*;
|
||||||
|
import net.miarma.integridos.common.security.IntegrityProvider;
|
||||||
|
import net.miarma.integridos.common.socket.SocketRequest;
|
||||||
|
import net.miarma.integridos.common.socket.SocketResponse;
|
||||||
|
import net.miarma.integridos.common.db.dto.LoginDTO;
|
||||||
|
import net.miarma.integridos.common.db.dto.TransactionDTO;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
public class ClientSocket implements AutoCloseable {
|
||||||
|
private Socket socket;
|
||||||
|
private PrintWriter output;
|
||||||
|
private BufferedReader input;
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
|
||||||
|
public ClientSocket() throws IOException {
|
||||||
|
this.socket = new Socket("localhost", 6969);
|
||||||
|
this.output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
|
||||||
|
this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse login(String username, String password) throws IOException {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.LOGIN, new LoginDTO(username, password));
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse register(String username, String password) throws IOException {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.REGISTER, new LoginDTO(username, password));
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse logout(String userId) throws IOException {
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.LOGOUT, userId);
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse sendTransaction(TransactionDTO transaction) throws Exception {
|
||||||
|
transaction.setHmac(null);
|
||||||
|
SocketRequest msg = new SocketRequest(SocketRequest.Action.SEND_TRANSACTION, transaction);
|
||||||
|
String jsonMsg = gson.toJson(msg);
|
||||||
|
String hmac = IntegrityProvider.generateHMAC(ConfigManager.getInstance().getStringProperty("secret"), jsonMsg);
|
||||||
|
transaction.setHmac(hmac);
|
||||||
|
msg.setPayload(transaction);
|
||||||
|
output.println(gson.toJson(msg));
|
||||||
|
return gson.fromJson(input.readLine(), SocketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
input.close();
|
||||||
|
output.close();
|
||||||
|
socket.close();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package net.miarma.integridos.client.ui;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class AutoShrinkLabel extends JLabel {
|
||||||
|
public AutoShrinkLabel(String text) {
|
||||||
|
super(text);
|
||||||
|
setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
String text = getText();
|
||||||
|
if (text == null || text.isEmpty()) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Insets insets = getInsets();
|
||||||
|
int availableHeight = getHeight() - insets.top - insets.bottom;
|
||||||
|
int availableWidth = getWidth() - insets.left - insets.right;
|
||||||
|
|
||||||
|
if (availableWidth <= 0 || availableHeight <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics2D graphics2d = (Graphics2D) g.create();
|
||||||
|
|
||||||
|
Font font = getFont();
|
||||||
|
int fontSize = font.getSize();
|
||||||
|
|
||||||
|
FontMetrics fm;
|
||||||
|
int textWidth;
|
||||||
|
int textHeight;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Font testFont = font.deriveFont((float) fontSize);
|
||||||
|
fm = graphics2d.getFontMetrics(testFont);
|
||||||
|
textWidth = fm.stringWidth(text);
|
||||||
|
textHeight = fm.getHeight();
|
||||||
|
if (textWidth <= availableWidth && textHeight <= availableHeight) {
|
||||||
|
font = testFont;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fontSize--;
|
||||||
|
} while (fontSize > 5);
|
||||||
|
|
||||||
|
graphics2d.setFont(font);
|
||||||
|
|
||||||
|
int x = (getWidth() - fm.stringWidth(text)) / 2;
|
||||||
|
int y = (getHeight() + fm.getAscent() - fm.getDescent()) / 2;
|
||||||
|
|
||||||
|
graphics2d.drawString(text, x, y);
|
||||||
|
graphics2d.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(200, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,492 @@
|
|||||||
|
/*
|
||||||
|
* Created by JFormDesigner on Wed Oct 01 16:21:10 CEST 2025
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.miarma.integridos.client.ui;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import jiconfont.icons.font_awesome.FontAwesome;
|
||||||
|
import jiconfont.swing.IconFontSwing;
|
||||||
|
import net.miarma.integridos.common.Constants;
|
||||||
|
|
||||||
|
import net.miarma.integridos.common.security.IntegrityProvider;
|
||||||
|
import net.miarma.integridos.common.socket.SocketResponse;
|
||||||
|
import net.miarma.integridos.common.socket.SocketStatus;
|
||||||
|
import net.miarma.integridos.common.db.dto.TransactionDTO;
|
||||||
|
import net.miarma.integridos.common.db.entities.UserEntity;
|
||||||
|
import net.miarma.integridos.client.ClientSocket;
|
||||||
|
import net.miginfocom.swing.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jomaa
|
||||||
|
*/
|
||||||
|
public class MainWindow extends JFrame {
|
||||||
|
public static UserEntity _loggedUser;
|
||||||
|
private AutoShrinkLabel balanceLabel = new AutoShrinkLabel("0.00€");
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ClientSocket.class);
|
||||||
|
|
||||||
|
public MainWindow() {
|
||||||
|
initComponents();
|
||||||
|
this.setTitle(Constants.APP_NAME);
|
||||||
|
versionLabel.setText(Constants.APP_NAME + " v" + Constants.APP_VERSION + " by Security Team 33");
|
||||||
|
setIcons();
|
||||||
|
addBalanceLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setIcons() {
|
||||||
|
userLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.USER, 18, Color.BLACK));
|
||||||
|
passwordLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.KEY, 18, Color.BLACK));
|
||||||
|
loginBtn.setIcon(IconFontSwing.buildIcon(FontAwesome.SIGN_IN, 18, Color.BLACK));
|
||||||
|
registerBtn.setIcon(IconFontSwing.buildIcon(FontAwesome.USER_PLUS, 18, Color.BLACK));
|
||||||
|
destLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.USER_SECRET, 18, Color.BLACK));
|
||||||
|
amountLabel.setIcon(IconFontSwing.buildIcon(FontAwesome.MONEY, 18, Color.BLACK));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearLoginInputs() {
|
||||||
|
userTextField.setText("");
|
||||||
|
passwordTextField.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearMainInputs() {
|
||||||
|
destTextField.setText("");
|
||||||
|
amountTextField.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBalanceLabel() {
|
||||||
|
balanceLabel.setFont(new Font("Adwaita Sans", Font.BOLD, 64));
|
||||||
|
balanceLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
mainPanel.add(balanceLabel, "cell 0 0,alignx center,growx 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setView(String name) {
|
||||||
|
((CardLayout)getContentPane().getLayout()).show(getContentPane(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loginBtn(ActionEvent e) {
|
||||||
|
String username = userTextField.getText();
|
||||||
|
String password = new String(passwordTextField.getPassword());
|
||||||
|
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
SocketResponse res = client.login(username, password);
|
||||||
|
|
||||||
|
if (res.getStatus() == SocketStatus.OK) {
|
||||||
|
_loggedUser = new Gson().fromJson(
|
||||||
|
new Gson().toJson(res.getData()),
|
||||||
|
UserEntity.class
|
||||||
|
);
|
||||||
|
logger.info("El usuario '{}' ha iniciado sesión correctamente.", username);
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage().getMessage(),
|
||||||
|
res.getStatus().toString(),
|
||||||
|
JOptionPane.INFORMATION_MESSAGE
|
||||||
|
);
|
||||||
|
setView("mainPanel");
|
||||||
|
balanceLabel.setText(String.format("%.2f€", _loggedUser.getBalance()));
|
||||||
|
} else {
|
||||||
|
logger.warn("Intento de login fallido para '{}': {}", username,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje");
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje",
|
||||||
|
res.getStatus().toString(),
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearLoginInputs();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("Error de conexión con el servidor al intentar loguear '{}': {}", username, ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerBtn(ActionEvent e) {
|
||||||
|
String username = userTextField.getText();
|
||||||
|
String password = new String(passwordTextField.getPassword());
|
||||||
|
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
SocketResponse res = client.register(username, password);
|
||||||
|
|
||||||
|
if(res.getStatus() == SocketStatus.OK) {
|
||||||
|
logger.info("Usuario '{}' registrado correctamente.", username);
|
||||||
|
} else {
|
||||||
|
logger.warn("Error al registrar '{}': {}", username,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje");
|
||||||
|
}
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje",
|
||||||
|
res.getStatus().toString(),
|
||||||
|
res.getStatus() == SocketStatus.OK ?
|
||||||
|
JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
|
||||||
|
clearLoginInputs();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("Error de conexión con el servidor al registrar '{}': {}", username, ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendBtn(ActionEvent e) {
|
||||||
|
String destUser = destTextField.getText();
|
||||||
|
double amount;
|
||||||
|
|
||||||
|
try {
|
||||||
|
amount = Double.parseDouble(amountTextField.getText());
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
logger.warn("Cantidad no válida introducida: {}", amountTextField.getText());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Cantidad no válida.",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
String nonce = IntegrityProvider.generateNonce();
|
||||||
|
TransactionDTO dto = new TransactionDTO(_loggedUser.getUserName(), destUser, amount, nonce);
|
||||||
|
SocketResponse res = client.sendTransaction(dto);
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Respuesta sin mensaje",
|
||||||
|
res.getStatus().toString(),
|
||||||
|
res.getStatus() == SocketStatus.OK ?
|
||||||
|
JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.getStatus() == SocketStatus.OK) {
|
||||||
|
logger.info("Transacción enviada: {} -> {} | {}€", _loggedUser.getUserName(), destUser, amount);
|
||||||
|
_loggedUser.setBalance(_loggedUser.getBalance() - amount);
|
||||||
|
balanceLabel.setText(String.format("%.2f€", _loggedUser.getBalance()));
|
||||||
|
} else if (res.getStatus() == SocketStatus.SESSION_EXPIRED) {
|
||||||
|
logger.warn("Sesión expirada para '{}'. Se cerrará sesión.", _loggedUser.getUserName());
|
||||||
|
_loggedUser = null;
|
||||||
|
setView("loginPanel");
|
||||||
|
clearMainInputs();
|
||||||
|
} else {
|
||||||
|
logger.warn("Error enviando transacción de {} a {}: {}", _loggedUser.getUserName(), destUser,
|
||||||
|
res.getMessage() != null ? res.getMessage().getMessage() : "Sin mensaje");
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMainInputs();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error("Error de conexión con el servidor enviando transacción de {} a {}: {}",
|
||||||
|
_loggedUser.getUserName(), destUser, ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logout() {
|
||||||
|
if (_loggedUser != null) {
|
||||||
|
try (ClientSocket client = new ClientSocket()) {
|
||||||
|
SocketResponse res = client.logout(_loggedUser.getUserId());
|
||||||
|
|
||||||
|
if (res != null && res.getMessage() != null) {
|
||||||
|
if (res.getStatus() == SocketStatus.OK) {
|
||||||
|
logger.info("Usuario '{}' ha cerrado sesión correctamente.", _loggedUser.getUserName());
|
||||||
|
} else {
|
||||||
|
logger.warn("Intento de logout de '{}' con estado: {}", _loggedUser.getUserName(), res.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
res.getMessage().getMessage(),
|
||||||
|
res.getStatus().toString(),
|
||||||
|
res.getStatus() == SocketStatus.OK ?
|
||||||
|
JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error("Error de conexión con el servidor al hacer logout de '{}': {}", _loggedUser.getUserName(), ex.getMessage());
|
||||||
|
JOptionPane.showMessageDialog(this,
|
||||||
|
"Error de conexión con el servidor",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMainInputs();
|
||||||
|
_loggedUser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logoutBtn(ActionEvent e) {
|
||||||
|
logout();
|
||||||
|
setView("loginPanel");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void thisWindowClosing(WindowEvent e) {
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initComponents() {
|
||||||
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
|
||||||
|
// Generated using JFormDesigner Educational license - José Manuel Amador Gallardo (José Manuel Amador)
|
||||||
|
loginPanel = new JPanel();
|
||||||
|
logo = new JLabel();
|
||||||
|
welcomeLabel = new JLabel();
|
||||||
|
userPanel = new JPanel();
|
||||||
|
userLabel = new JLabel();
|
||||||
|
userTextField = new JTextField();
|
||||||
|
passwordPanel = new JPanel();
|
||||||
|
passwordLabel = new JLabel();
|
||||||
|
passwordTextField = new JPasswordField();
|
||||||
|
loginBtn = new JButton();
|
||||||
|
btnLoginPanel = new JPanel();
|
||||||
|
noAccountLabel = new JLabel();
|
||||||
|
registerBtn = new JButton();
|
||||||
|
versionLabel = new JLabel();
|
||||||
|
mainPanel = new JPanel();
|
||||||
|
destPanel = new JPanel();
|
||||||
|
destLabel = new JLabel();
|
||||||
|
destTextField = new JTextField();
|
||||||
|
amountPanel = new JPanel();
|
||||||
|
amountLabel = new JLabel();
|
||||||
|
amountTextField = new JTextField();
|
||||||
|
sendBtn = new JButton();
|
||||||
|
logoutBtn = new JButton();
|
||||||
|
|
||||||
|
//======== this ========
|
||||||
|
setResizable(false);
|
||||||
|
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||||
|
addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
thisWindowClosing(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var contentPane = getContentPane();
|
||||||
|
contentPane.setLayout(new CardLayout(12, 6));
|
||||||
|
|
||||||
|
//======== loginPanel ========
|
||||||
|
{
|
||||||
|
loginPanel.setLayout(new MigLayout(
|
||||||
|
"hidemode 3,gapy 12",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[]0" +
|
||||||
|
"[]para" +
|
||||||
|
"[fill]" +
|
||||||
|
"[fill]para" +
|
||||||
|
"[]" +
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- logo ----
|
||||||
|
logo.setIcon(new ImageIcon(getClass().getResource("/images/banco.png")));
|
||||||
|
logo.setMaximumSize(new Dimension(256, 256));
|
||||||
|
logo.setMinimumSize(new Dimension(256, 256));
|
||||||
|
logo.setPreferredSize(new Dimension(256, 256));
|
||||||
|
logo.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||||
|
loginPanel.add(logo, "cell 0 0,alignx center,growx 0");
|
||||||
|
|
||||||
|
//---- welcomeLabel ----
|
||||||
|
welcomeLabel.setText("Bienvenido a Banco Grupo 33. Inicie sesi\u00f3n.");
|
||||||
|
welcomeLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 16));
|
||||||
|
loginPanel.add(welcomeLabel, "cell 0 1,alignx center,growx 0");
|
||||||
|
|
||||||
|
//======== userPanel ========
|
||||||
|
{
|
||||||
|
userPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- userLabel ----
|
||||||
|
userLabel.setText("Usuario:");
|
||||||
|
userLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
userLabel.setMaximumSize(new Dimension(130, 23));
|
||||||
|
userLabel.setMinimumSize(new Dimension(130, 23));
|
||||||
|
userLabel.setPreferredSize(new Dimension(130, 23));
|
||||||
|
userPanel.add(userLabel, "cell 0 0");
|
||||||
|
|
||||||
|
//---- userTextField ----
|
||||||
|
userTextField.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
userTextField.setCaretColor(new Color(0x076854));
|
||||||
|
userTextField.setSelectionColor(new Color(0x076854));
|
||||||
|
userPanel.add(userTextField, "cell 1 0");
|
||||||
|
}
|
||||||
|
loginPanel.add(userPanel, "cell 0 2");
|
||||||
|
|
||||||
|
//======== passwordPanel ========
|
||||||
|
{
|
||||||
|
passwordPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- passwordLabel ----
|
||||||
|
passwordLabel.setText("Contrase\u00f1a:");
|
||||||
|
passwordLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
passwordLabel.setMaximumSize(new Dimension(130, 23));
|
||||||
|
passwordLabel.setMinimumSize(new Dimension(130, 23));
|
||||||
|
passwordLabel.setPreferredSize(new Dimension(130, 23));
|
||||||
|
passwordPanel.add(passwordLabel, "cell 0 0");
|
||||||
|
|
||||||
|
//---- passwordTextField ----
|
||||||
|
passwordTextField.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
passwordTextField.setSelectionColor(new Color(0x076854));
|
||||||
|
passwordTextField.setCaretColor(new Color(0x076854));
|
||||||
|
passwordPanel.add(passwordTextField, "cell 1 0");
|
||||||
|
}
|
||||||
|
loginPanel.add(passwordPanel, "cell 0 3");
|
||||||
|
|
||||||
|
//---- loginBtn ----
|
||||||
|
loginBtn.setText("Iniciar sesi\u00f3n");
|
||||||
|
loginBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
loginBtn.addActionListener(e -> loginBtn(e));
|
||||||
|
loginPanel.add(loginBtn, "cell 0 4,alignx trailing,growx 0");
|
||||||
|
|
||||||
|
//======== btnLoginPanel ========
|
||||||
|
{
|
||||||
|
btnLoginPanel.setLayout(new MigLayout(
|
||||||
|
"hidemode 3,aligny bottom",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[]" +
|
||||||
|
"[fill]para" +
|
||||||
|
"[]"));
|
||||||
|
|
||||||
|
//---- noAccountLabel ----
|
||||||
|
noAccountLabel.setText("\u00bfNo tiene cuenta?");
|
||||||
|
btnLoginPanel.add(noAccountLabel, "cell 0 0,alignx center,growx 0");
|
||||||
|
|
||||||
|
//---- registerBtn ----
|
||||||
|
registerBtn.setText("Registrarse");
|
||||||
|
registerBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
registerBtn.addActionListener(e -> registerBtn(e));
|
||||||
|
btnLoginPanel.add(registerBtn, "cell 0 1,alignx center,growx 0");
|
||||||
|
|
||||||
|
//---- versionLabel ----
|
||||||
|
versionLabel.setForeground(new Color(0xa0a0a0));
|
||||||
|
btnLoginPanel.add(versionLabel, "cell 0 2,alignx center,growx 0");
|
||||||
|
}
|
||||||
|
loginPanel.add(btnLoginPanel, "cell 0 5");
|
||||||
|
}
|
||||||
|
contentPane.add(loginPanel, "loginPanel");
|
||||||
|
|
||||||
|
//======== mainPanel ========
|
||||||
|
{
|
||||||
|
mainPanel.setLayout(new MigLayout(
|
||||||
|
"hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]" +
|
||||||
|
"[fill]" +
|
||||||
|
"[fill]" +
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//======== destPanel ========
|
||||||
|
{
|
||||||
|
destPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[]"));
|
||||||
|
|
||||||
|
//---- destLabel ----
|
||||||
|
destLabel.setText("Destinatario:");
|
||||||
|
destLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
destLabel.setHorizontalAlignment(SwingConstants.LEFT);
|
||||||
|
destPanel.add(destLabel, "cell 0 0");
|
||||||
|
destPanel.add(destTextField, "cell 1 0");
|
||||||
|
}
|
||||||
|
mainPanel.add(destPanel, "cell 0 1");
|
||||||
|
|
||||||
|
//======== amountPanel ========
|
||||||
|
{
|
||||||
|
amountPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[fill]" +
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[grow,fill]"));
|
||||||
|
|
||||||
|
//---- amountLabel ----
|
||||||
|
amountLabel.setText("Cantidad:");
|
||||||
|
amountLabel.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
amountLabel.setMaximumSize(new Dimension(108, 23));
|
||||||
|
amountLabel.setMinimumSize(new Dimension(108, 23));
|
||||||
|
amountLabel.setPreferredSize(new Dimension(108, 23));
|
||||||
|
amountLabel.setHorizontalAlignment(SwingConstants.LEFT);
|
||||||
|
amountPanel.add(amountLabel, "cell 0 0");
|
||||||
|
amountPanel.add(amountTextField, "cell 1 0");
|
||||||
|
}
|
||||||
|
mainPanel.add(amountPanel, "cell 0 2");
|
||||||
|
|
||||||
|
//---- sendBtn ----
|
||||||
|
sendBtn.setText("Enviar");
|
||||||
|
sendBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
sendBtn.addActionListener(e -> sendBtn(e));
|
||||||
|
mainPanel.add(sendBtn, "cell 0 3,alignx trailing,growx 0");
|
||||||
|
|
||||||
|
//---- logoutBtn ----
|
||||||
|
logoutBtn.setText("Cerrar sesi\u00f3n");
|
||||||
|
logoutBtn.setFont(new Font("Adwaita Sans", Font.PLAIN, 18));
|
||||||
|
logoutBtn.addActionListener(e -> logoutBtn(e));
|
||||||
|
mainPanel.add(logoutBtn, "cell 0 4,aligny bottom,growy 0");
|
||||||
|
}
|
||||||
|
contentPane.add(mainPanel, "mainPanel");
|
||||||
|
setSize(400, 600);
|
||||||
|
setLocationRelativeTo(getOwner());
|
||||||
|
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
|
||||||
|
// Generated using JFormDesigner Educational license - José Manuel Amador Gallardo (José Manuel Amador)
|
||||||
|
private JPanel loginPanel;
|
||||||
|
private JLabel logo;
|
||||||
|
private JLabel welcomeLabel;
|
||||||
|
private JPanel userPanel;
|
||||||
|
private JLabel userLabel;
|
||||||
|
private JTextField userTextField;
|
||||||
|
private JPanel passwordPanel;
|
||||||
|
private JLabel passwordLabel;
|
||||||
|
private JPasswordField passwordTextField;
|
||||||
|
private JButton loginBtn;
|
||||||
|
private JPanel btnLoginPanel;
|
||||||
|
private JLabel noAccountLabel;
|
||||||
|
private JButton registerBtn;
|
||||||
|
private JLabel versionLabel;
|
||||||
|
private JPanel mainPanel;
|
||||||
|
private JPanel destPanel;
|
||||||
|
private JLabel destLabel;
|
||||||
|
private JTextField destTextField;
|
||||||
|
private JPanel amountPanel;
|
||||||
|
private JLabel amountLabel;
|
||||||
|
private JTextField amountTextField;
|
||||||
|
private JButton sendBtn;
|
||||||
|
private JButton logoutBtn;
|
||||||
|
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
|
||||||
|
}
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
JFDML JFormDesigner: "8.2.4.0.393" Java: "21.0.8" encoding: "UTF-8"
|
||||||
|
|
||||||
|
new FormModel {
|
||||||
|
contentType: "form/swing"
|
||||||
|
root: new FormRoot {
|
||||||
|
add( new FormWindow( "javax.swing.JFrame", new FormLayoutManager( class java.awt.CardLayout ) {
|
||||||
|
"hgap": 12
|
||||||
|
"vgap": 6
|
||||||
|
} ) {
|
||||||
|
name: "this"
|
||||||
|
"$sizePolicy": 1
|
||||||
|
"resizable": false
|
||||||
|
"defaultCloseOperation": 3
|
||||||
|
addEvent( new FormEvent( "java.awt.event.WindowListener", "windowClosing", "thisWindowClosing", true ) )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3,gapy 12"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[]0[]para[fill][fill]para[][grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "loginPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "logo"
|
||||||
|
"icon": new com.jformdesigner.model.SwingIcon( 0, "/images/banco.png" )
|
||||||
|
"maximumSize": new java.awt.Dimension( 256, 256 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 256, 256 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 256, 256 )
|
||||||
|
"horizontalTextPosition": 0
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "welcomeLabel"
|
||||||
|
"text": "Bienvenido a Banco Grupo 33. Inicie sesión."
|
||||||
|
"font": new java.awt.Font( "Adwaita Sans", 0, 16 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "userPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "userLabel"
|
||||||
|
"text": "Usuario:"
|
||||||
|
"font": &Font0 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
"maximumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||||
|
name: "userTextField"
|
||||||
|
"font": &Font1 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
"caretColor": &Color0 new java.awt.Color( 7, 104, 84, 255 )
|
||||||
|
"selectionColor": new java.awt.Color( 7, 104, 84, 255 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 2"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "passwordPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "passwordLabel"
|
||||||
|
"text": "Contraseña:"
|
||||||
|
"font": #Font0
|
||||||
|
"maximumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 130, 23 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JPasswordField" ) {
|
||||||
|
name: "passwordTextField"
|
||||||
|
"font": #Font1
|
||||||
|
"selectionColor": new java.awt.Color( 7, 104, 84, 255 )
|
||||||
|
"caretColor": #Color0
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 3"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "loginBtn"
|
||||||
|
"text": "Iniciar sesión"
|
||||||
|
"font": &Font2 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "loginBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 4,alignx trailing,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3,aligny bottom"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[][fill]para[]"
|
||||||
|
} ) {
|
||||||
|
name: "btnLoginPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "noAccountLabel"
|
||||||
|
"text": "¿No tiene cuenta?"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "registerBtn"
|
||||||
|
"text": "Registrarse"
|
||||||
|
"font": #Font2
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "registerBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "versionLabel"
|
||||||
|
"foreground": new java.awt.Color( 160, 160, 160, 255 )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 2,alignx center,growx 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 5"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
|
"value": "loginPanel"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill][fill][fill][fill][grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "mainPanel"
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
|
"$rowConstraints": "[]"
|
||||||
|
} ) {
|
||||||
|
name: "destPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "destLabel"
|
||||||
|
"text": "Destinatario:"
|
||||||
|
"font": &Font3 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
"horizontalAlignment": 2
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||||
|
name: "destTextField"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3"
|
||||||
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
|
"$rowConstraints": "[grow,fill]"
|
||||||
|
} ) {
|
||||||
|
name: "amountPanel"
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "amountLabel"
|
||||||
|
"text": "Cantidad:"
|
||||||
|
"font": #Font3
|
||||||
|
"maximumSize": new java.awt.Dimension( 108, 23 )
|
||||||
|
"minimumSize": new java.awt.Dimension( 108, 23 )
|
||||||
|
"preferredSize": new java.awt.Dimension( 108, 23 )
|
||||||
|
"horizontalAlignment": 2
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||||
|
name: "amountTextField"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 2"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "sendBtn"
|
||||||
|
"text": "Enviar"
|
||||||
|
"font": &Font4 new java.awt.Font( "Adwaita Sans", 0, 18 )
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "sendBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 3,alignx trailing,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "logoutBtn"
|
||||||
|
"text": "Cerrar sesión"
|
||||||
|
"font": #Font4
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "logoutBtn", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 4,aligny bottom,growy 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
|
"value": "mainPanel"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( null ) {
|
||||||
|
"location": new java.awt.Point( 0, 0 )
|
||||||
|
"size": new java.awt.Dimension( 400, 600 )
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package net.miarma.integridos.common;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestión de toda la configuración de la aplicación.
|
||||||
|
* Se encarga de cargar, guardar y proporcionar acceso a las propiedades de configuración.
|
||||||
|
* Proporciona métodos para obtener la URL de la base de datos, directorios de archivos,
|
||||||
|
* y propiedades específicas como host, puerto, etc.
|
||||||
|
* <p>
|
||||||
|
* Esta clase sigue el patron Singleton para asegurar una sola instancia.
|
||||||
|
* @author José Manuel Amador Gallardo
|
||||||
|
*/
|
||||||
|
public class ConfigManager {
|
||||||
|
private static ConfigManager INSTANCE;
|
||||||
|
private final File configFile;
|
||||||
|
private final Properties config;
|
||||||
|
private static final String CONFIG_FILE_NAME = "config.properties";
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
|
||||||
|
|
||||||
|
private ConfigManager() {
|
||||||
|
String path = getBaseDir() + CONFIG_FILE_NAME;
|
||||||
|
this.configFile = new File(path);
|
||||||
|
this.config = new Properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigManager getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = new ConfigManager();
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadConfig() {
|
||||||
|
try (FileInputStream fis = new FileInputStream(configFile);
|
||||||
|
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8)) {
|
||||||
|
config.load(isr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error loading configuration file: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public File getConfigFile() {
|
||||||
|
return configFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHomeDir() {
|
||||||
|
return getOS() == OSType.WINDOWS ?
|
||||||
|
"C:/Users/" + System.getProperty("user.name") + "/" :
|
||||||
|
System.getProperty("user.home").contains("root") ? "/root/" :
|
||||||
|
"/home/" + System.getProperty("user.name") + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseDir() {
|
||||||
|
return getHomeDir() +
|
||||||
|
(getOS() == OSType.WINDOWS ? ".integridos/" :
|
||||||
|
getOS() == OSType.LINUX ? ".config/integridos/" :
|
||||||
|
".integridos/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OSType getOS() {
|
||||||
|
String os = System.getProperty("os.name").toLowerCase();
|
||||||
|
if (os.contains("win")) {
|
||||||
|
return OSType.WINDOWS;
|
||||||
|
} else if (os.contains("nix") || os.contains("nux")) {
|
||||||
|
return OSType.LINUX;
|
||||||
|
} else {
|
||||||
|
return OSType.INVALID_OS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStringProperty(String key) {
|
||||||
|
return config.getProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIntProperty(String key) {
|
||||||
|
String value = config.getProperty(key);
|
||||||
|
return value != null ? Integer.parseInt(value) : 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBooleanProperty(String key) {
|
||||||
|
return Boolean.parseBoolean(config.getProperty(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperty(String key, String value) {
|
||||||
|
config.setProperty(key, value);
|
||||||
|
saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveConfig() {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||||
|
config.store(fos, "Configuration for: " + Constants.APP_NAME);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error saving configuration file: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.miarma.integridos.common;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
public static final String APP_NAME = "Integridos";
|
||||||
|
public static final String APP_VERSION = "1.0.0";
|
||||||
|
|
||||||
|
private Constants() {
|
||||||
|
throw new AssertionError("Utility class cannot be instantiated.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.miarma.integridos.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum que representa los diferentes tipos de sistemas operativos soportados
|
||||||
|
* @author José Manuel Amador Gallardo
|
||||||
|
*/
|
||||||
|
public enum OSType {
|
||||||
|
LINUX, WINDOWS, INVALID_OS
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package net.miarma.integridos.common.db;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
import jakarta.persistence.Persistence;
|
||||||
|
|
||||||
|
public class DBConnector {
|
||||||
|
private static DBConnector instance;
|
||||||
|
private EntityManagerFactory emf;
|
||||||
|
|
||||||
|
private DBConnector() {
|
||||||
|
this.emf = Persistence.createEntityManagerFactory("ssii-pai1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DBConnector getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DBConnector();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityManager createEntityManager() {
|
||||||
|
return emf.createEntityManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
if (emf != null && emf.isOpen()) {
|
||||||
|
emf.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package net.miarma.integridos.common.db;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.TypedQuery;
|
||||||
|
import net.miarma.integridos.common.security.PasswordHasher;
|
||||||
|
import net.miarma.integridos.common.db.entities.UserEntity;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class DBPopulator {
|
||||||
|
private final DBConnector conn = DBConnector.getInstance();
|
||||||
|
private EntityManager em;
|
||||||
|
private static DBPopulator instance;
|
||||||
|
|
||||||
|
private DBPopulator() {
|
||||||
|
em = conn.createEntityManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DBPopulator getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DBPopulator();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFirstRun() {
|
||||||
|
TypedQuery<Long> q = em.createQuery("SELECT COUNT(u) FROM UserEntity u", Long.class);
|
||||||
|
Long count = q.getSingleResult();
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populate() {
|
||||||
|
UserEntity u1 = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
"ricolinad", PasswordHasher.hash("ricardo2025"));
|
||||||
|
UserEntity u2 = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
"alvgulveg", PasswordHasher.hash("alcalde_dimision"));
|
||||||
|
UserEntity u3 = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
"smt4497", PasswordHasher.hash("quemenlaus"));
|
||||||
|
try {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(u1);
|
||||||
|
em.persist(u2);
|
||||||
|
em.persist(u3);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
em.getTransaction().rollback();
|
||||||
|
} finally {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package net.miarma.integridos.common.db.dao;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import net.miarma.integridos.common.db.entities.SessionEntity;
|
||||||
|
|
||||||
|
public class SessionDAO {
|
||||||
|
public SessionEntity getByUserId(EntityManager em, String userId) {
|
||||||
|
return em.createQuery("SELECT s FROM SessionEntity s WHERE s.userId = :userId", SessionEntity.class)
|
||||||
|
.setParameter("userId", userId)
|
||||||
|
.getSingleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoggedIn(EntityManager em, String userId) {
|
||||||
|
Long count = em.createQuery(
|
||||||
|
"SELECT COUNT(s) FROM SessionEntity s WHERE s.userId = :userId", Long.class)
|
||||||
|
.setParameter("userId", userId)
|
||||||
|
.getSingleResult();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package net.miarma.integridos.common.db.dao;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
|
||||||
|
public class TransactionDAO {
|
||||||
|
public boolean isNonceUsed(EntityManager em, String nonce) {
|
||||||
|
Long count = em.createQuery(
|
||||||
|
"SELECT COUNT(t) FROM TransactionEntity t WHERE t.nonce = :nonce", Long.class)
|
||||||
|
.setParameter("nonce", nonce)
|
||||||
|
.getSingleResult();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package net.miarma.integridos.common.db.dao;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import net.miarma.integridos.common.db.entities.UserEntity;
|
||||||
|
|
||||||
|
public class UserDAO {
|
||||||
|
public UserEntity getByUserName(EntityManager em, String userName) {
|
||||||
|
try {
|
||||||
|
return em.createQuery("SELECT u FROM UserEntity u WHERE u.userName = :userName", UserEntity.class)
|
||||||
|
.setParameter("userName", userName)
|
||||||
|
.getSingleResult();
|
||||||
|
} catch (jakarta.persistence.NoResultException e) {
|
||||||
|
return null; // No se encontró, devolvemos null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.miarma.integridos.common.db.dto;
|
||||||
|
|
||||||
|
public class LoginDTO {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public LoginDTO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginDTO(String username, String password) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package net.miarma.integridos.common.db.dto;
|
||||||
|
|
||||||
|
public class TransactionDTO {
|
||||||
|
private String fromUserName;
|
||||||
|
private String toUserName;
|
||||||
|
private double amount;
|
||||||
|
private String hmac;
|
||||||
|
private String nonce;
|
||||||
|
|
||||||
|
public TransactionDTO() {}
|
||||||
|
|
||||||
|
public TransactionDTO(String fromUserName, String toUserName, double amount, String nonce) {
|
||||||
|
this.fromUserName = fromUserName;
|
||||||
|
this.toUserName = toUserName;
|
||||||
|
this.amount = amount;
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFromUserName() {
|
||||||
|
return fromUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromUserName(String fromUserName) {
|
||||||
|
this.fromUserName = fromUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToUserName() {
|
||||||
|
return toUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToUserName(String toUserName) {
|
||||||
|
this.toUserName = toUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(double amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHmac() {
|
||||||
|
return hmac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHmac(String hmac) {
|
||||||
|
this.hmac = hmac;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNonce(String nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package net.miarma.integridos.common.db.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "sessions")
|
||||||
|
public class SessionEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name = "sessionId", nullable = false, updatable = false)
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
@Column(name = "userId", nullable = false)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column(name = "createdAt", nullable = false, updatable = false, insertable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(name = "expiresAt", nullable = false, updatable = false, insertable = false)
|
||||||
|
private LocalDateTime expiresAt;
|
||||||
|
|
||||||
|
public SessionEntity() {}
|
||||||
|
|
||||||
|
public SessionEntity(String sessionId, String userId, LocalDateTime createdAt, LocalDateTime expiresAt) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionId(String sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getExpiresAt() {
|
||||||
|
return expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiresAt(LocalDateTime expiresAt) {
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package net.miarma.integridos.common.db.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "transactions")
|
||||||
|
public class TransactionEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name = "transactionId", nullable = false, updatable = false, length = 36)
|
||||||
|
private String transactionId;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "fromUser", referencedColumnName = "userId", nullable = false, updatable = false)
|
||||||
|
private UserEntity fromUser;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "toUser", referencedColumnName = "userId", nullable = false, updatable = false)
|
||||||
|
private UserEntity toUser;
|
||||||
|
|
||||||
|
@Column(name = "transactionAmount", nullable = false, updatable = false)
|
||||||
|
private Double transactionAmount;
|
||||||
|
|
||||||
|
@Column(name = "nonce", nullable = false, updatable = false)
|
||||||
|
private String nonce;
|
||||||
|
|
||||||
|
public TransactionEntity() {}
|
||||||
|
|
||||||
|
public TransactionEntity(String transactionId, UserEntity fromUser, UserEntity toUser, Double transactionAmount) {
|
||||||
|
this.transactionId = transactionId;
|
||||||
|
this.fromUser = fromUser;
|
||||||
|
this.toUser = toUser;
|
||||||
|
this.transactionAmount = transactionAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTransactionId() {
|
||||||
|
return transactionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionId(String transactionId) {
|
||||||
|
this.transactionId = transactionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserEntity getFromUser() {
|
||||||
|
return fromUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromUser(UserEntity fromUser) {
|
||||||
|
this.fromUser = fromUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserEntity getToUser() {
|
||||||
|
return toUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToUser(UserEntity toUser) {
|
||||||
|
this.toUser = toUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getTransactionAmount() {
|
||||||
|
return transactionAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionAmount(Double transactionAmount) {
|
||||||
|
this.transactionAmount = transactionAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNonce(String nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TransactionEntity{" +
|
||||||
|
"transactionId='" + transactionId + '\'' +
|
||||||
|
", fromUser=" + fromUser +
|
||||||
|
", toUser=" + toUser +
|
||||||
|
", transactionAmount=" + transactionAmount +
|
||||||
|
", nonce=" + nonce +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package net.miarma.integridos.common.db.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
public class UserEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name = "userId", nullable = false, updatable = false, length = 36)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column(name = "userName", unique = true, nullable = false, length = 64)
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
@Column(name = "password", nullable = false, length = 256)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(name = "balance", nullable = false)
|
||||||
|
private Double balance = 0.00;
|
||||||
|
|
||||||
|
public UserEntity() {}
|
||||||
|
|
||||||
|
public UserEntity(String userId, String userName, String password) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.userName = userName;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getBalance() {
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBalance(Double balance) {
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package net.miarma.integridos.common.security;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class IntegrityProvider {
|
||||||
|
public static String generateHMAC(String key, String data) throws Exception {
|
||||||
|
Mac sha256HMAC = Mac.getInstance("HmacSHA256");
|
||||||
|
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||||
|
sha256HMAC.init(secretKey);
|
||||||
|
return byteArrayToHex(sha256HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generateNonce() {
|
||||||
|
byte[] nonce = new byte[16];
|
||||||
|
new SecureRandom().nextBytes(nonce);
|
||||||
|
return Base64.getEncoder().encodeToString(nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String byteArrayToHex(byte[] arr) {
|
||||||
|
StringBuilder sb = new StringBuilder(arr.length * 2);
|
||||||
|
for(byte b : arr) {
|
||||||
|
sb.append(String.format("%02x", b));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package net.miarma.integridos.common.security;
|
||||||
|
|
||||||
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clase de utilidad para el hash de contraseñas.
|
||||||
|
* Utiliza BCrypt para generar y verificar hashes de contraseñas.
|
||||||
|
*
|
||||||
|
* @author José Manuel Amador Gallardo
|
||||||
|
*/
|
||||||
|
public class PasswordHasher {
|
||||||
|
|
||||||
|
private static final int SALT_ROUNDS = 12;
|
||||||
|
|
||||||
|
public static String hash(String plainPassword) {
|
||||||
|
return BCrypt.hashpw(plainPassword, BCrypt.gensalt(SALT_ROUNDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean verify(String plainPassword, String hashedPassword) {
|
||||||
|
return BCrypt.checkpw(plainPassword, hashedPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package net.miarma.integridos.common.socket;
|
||||||
|
|
||||||
|
public class SocketRequest {
|
||||||
|
private SocketRequest.Action action;
|
||||||
|
private Object payload;
|
||||||
|
|
||||||
|
public SocketRequest() {}
|
||||||
|
|
||||||
|
public SocketRequest(SocketRequest.Action action, Object payload) {
|
||||||
|
this.action = action;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketRequest.Action getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(SocketRequest.Action action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayload(Object payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SocketRequest{" +
|
||||||
|
"action='" + action.name() + '\'' +
|
||||||
|
", payload=" + (payload != null ? payload.toString() : "null") +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
LOGIN, REGISTER, SEND_TRANSACTION, LOGOUT
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package net.miarma.integridos.common.socket;
|
||||||
|
|
||||||
|
public class SocketResponse {
|
||||||
|
|
||||||
|
private SocketStatus status;
|
||||||
|
private Message message;
|
||||||
|
private Object data;
|
||||||
|
|
||||||
|
public SocketResponse() {}
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status) {
|
||||||
|
this(status, (Message) null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status, Object data) {
|
||||||
|
this(status, null, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status, Message message) {
|
||||||
|
this(status, message, message != null ? message.getMessage() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status, Exception e) {
|
||||||
|
this(status, Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketResponse(SocketStatus status, Message message, Object data) {
|
||||||
|
this.status = status;
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SocketResponse{" +
|
||||||
|
"status=" + status +
|
||||||
|
", message=" + (message != null ? message.name() : "null") +
|
||||||
|
", data=" + (data != null ? data.toString() : "null") +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Message {
|
||||||
|
LOGGED_OUT("Ha cerrado sesión correctamente"),
|
||||||
|
LOGGED_IN("Ha iniciado sesión correctamente"),
|
||||||
|
TRANSACTION_SENT("Su transacción se ha realizado"),
|
||||||
|
USER_NOT_FOUND("El usuario no existe."),
|
||||||
|
WRONG_PASSWORD("Contraseña incorrecta."),
|
||||||
|
USER_ALREADY_EXISTS("El usuario ya está registrado."),
|
||||||
|
CONNECTION_ERROR("Error de conexión con el servidor."),
|
||||||
|
UNKNOWN_ERROR("Ha ocurrido un error inesperado."),
|
||||||
|
SESSION_EXPIRED("Tu sesión ha expirado."),
|
||||||
|
INTEGRITY_FAIL("Fallo de integridad en el mensaje."),
|
||||||
|
INVALID_AMOUNT("Cantidad no válida."),
|
||||||
|
REPLAY_ATTACK("Intento de repetición detectado."),
|
||||||
|
RECIPIENT_NOT_FOUND("El destinatario no existe"),
|
||||||
|
REGISTERED("Se ha registrado correctamente");
|
||||||
|
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
Message(String userMessage) {
|
||||||
|
this.message = userMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package net.miarma.integridos.common.socket;
|
||||||
|
|
||||||
|
public enum SocketStatus {
|
||||||
|
OK,
|
||||||
|
ERROR,
|
||||||
|
SESSION_EXPIRED,
|
||||||
|
INTEGRITY_FAIL,
|
||||||
|
UNAUTHORIZED,
|
||||||
|
INVALID_REQUEST;
|
||||||
|
|
||||||
|
public static boolean isOk(String status) {
|
||||||
|
return OK.name().equalsIgnoreCase(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
package net.miarma.integridos.server;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import net.miarma.integridos.common.*;
|
||||||
|
import net.miarma.integridos.common.db.entities.TransactionEntity;
|
||||||
|
import net.miarma.integridos.common.security.IntegrityProvider;
|
||||||
|
import net.miarma.integridos.common.security.PasswordHasher;
|
||||||
|
import net.miarma.integridos.common.socket.SocketRequest;
|
||||||
|
import net.miarma.integridos.common.socket.SocketResponse;
|
||||||
|
import net.miarma.integridos.common.socket.SocketStatus;
|
||||||
|
import net.miarma.integridos.common.db.DBConnector;
|
||||||
|
import net.miarma.integridos.common.db.dao.SessionDAO;
|
||||||
|
import net.miarma.integridos.common.db.dao.TransactionDAO;
|
||||||
|
import net.miarma.integridos.common.db.dao.UserDAO;
|
||||||
|
import net.miarma.integridos.common.db.dto.LoginDTO;
|
||||||
|
import net.miarma.integridos.common.db.dto.TransactionDTO;
|
||||||
|
import net.miarma.integridos.common.db.entities.SessionEntity;
|
||||||
|
import net.miarma.integridos.common.db.entities.UserEntity;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class RemoteSocket {
|
||||||
|
static void main(String[] args) throws IOException {
|
||||||
|
ServerSocket serverSocket = new ServerSocket(6969);
|
||||||
|
DBConnector conn = DBConnector.getInstance();
|
||||||
|
UserDAO userDAO = new UserDAO();
|
||||||
|
SessionDAO sessionDAO = new SessionDAO();
|
||||||
|
TransactionDAO transactionDAO = new TransactionDAO();
|
||||||
|
Gson gson = new Gson();
|
||||||
|
final Logger logger = LoggerFactory.getLogger(RemoteSocket.class);
|
||||||
|
ConfigManager.getInstance().loadConfig();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Socket socket = serverSocket.accept();
|
||||||
|
logger.info("Nueva conexión desde {}:{}", socket.getInetAddress(), socket.getPort());
|
||||||
|
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
SocketRequest msg = gson.fromJson(input.readLine(), SocketRequest.class);
|
||||||
|
SocketResponse res;
|
||||||
|
|
||||||
|
switch (msg.getAction()) {
|
||||||
|
case REGISTER -> {
|
||||||
|
LoginDTO dto = gson.fromJson(gson.toJson(msg.getPayload()), LoginDTO.class);
|
||||||
|
logger.info("Procesando REGISTER para {}", dto.getUsername());
|
||||||
|
EntityManager em = conn.createEntityManager();
|
||||||
|
try {
|
||||||
|
if (userDAO.getByUserName(em, dto.getUsername()) != null) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.USER_ALREADY_EXISTS);
|
||||||
|
} else {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
UserEntity u = new UserEntity(UUID.randomUUID().toString(),
|
||||||
|
dto.getUsername(), PasswordHasher.hash(dto.getPassword()));
|
||||||
|
em.persist(u);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.REGISTERED, u);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (em.getTransaction().isActive()) em.getTransaction().rollback();
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
res = new SocketResponse(SocketStatus.ERROR, SocketResponse.Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case LOGIN -> {
|
||||||
|
LoginDTO dto = gson.fromJson(gson.toJson(msg.getPayload()), LoginDTO.class);
|
||||||
|
logger.info("Procesando LOGIN para {}", dto.getUsername());
|
||||||
|
EntityManager em = conn.createEntityManager();
|
||||||
|
try {
|
||||||
|
UserEntity user = userDAO.getByUserName(em, dto.getUsername());
|
||||||
|
if (user == null) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.USER_NOT_FOUND);
|
||||||
|
} else if (PasswordHasher.verify(dto.getPassword(), user.getPassword())) {
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.LOGGED_IN, user);
|
||||||
|
|
||||||
|
SessionEntity session = new SessionEntity();
|
||||||
|
session.setSessionId(UUID.randomUUID().toString());
|
||||||
|
session.setUserId(user.getUserId());
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(session);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
} else {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.WRONG_PASSWORD);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
res = new SocketResponse(SocketStatus.ERROR, SocketResponse.Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case LOGOUT -> {
|
||||||
|
String userId = gson.fromJson(gson.toJson(msg.getPayload()), String.class);
|
||||||
|
logger.info("Procesando LOGOUT para {}", userId);
|
||||||
|
EntityManager em = conn.createEntityManager();
|
||||||
|
try {
|
||||||
|
SessionEntity session = sessionDAO.getByUserId(em, userId);
|
||||||
|
if (session != null) {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.remove(session);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.LOGGED_OUT);
|
||||||
|
} else {
|
||||||
|
res = new SocketResponse(SocketStatus.SESSION_EXPIRED, SocketResponse.Message.SESSION_EXPIRED);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case SEND_TRANSACTION -> {
|
||||||
|
TransactionDTO dto = gson.fromJson(gson.toJson(msg.getPayload()), TransactionDTO.class);
|
||||||
|
|
||||||
|
logger.info("Procesando SEND_TRANSACTION de {} a {} | {}", dto.getFromUserName(), dto.getToUserName(), dto.getAmount());
|
||||||
|
|
||||||
|
String receivedHmac = dto.getHmac();
|
||||||
|
|
||||||
|
logger.debug("HMAC recibida: {}", receivedHmac);
|
||||||
|
|
||||||
|
dto.setHmac(null);
|
||||||
|
msg.setPayload(dto);
|
||||||
|
String jsonMsg = gson.toJson(msg);
|
||||||
|
|
||||||
|
logger.debug("Mensaje JSON para calcular HMAC: {}", jsonMsg);
|
||||||
|
|
||||||
|
String generatedHmac = IntegrityProvider.generateHMAC(
|
||||||
|
ConfigManager.getInstance().getStringProperty("secret"), jsonMsg
|
||||||
|
);
|
||||||
|
|
||||||
|
logger.debug("HMAC generada: {}", generatedHmac);
|
||||||
|
|
||||||
|
if (!generatedHmac.equals(receivedHmac)) {
|
||||||
|
res = new SocketResponse(SocketStatus.INTEGRITY_FAIL, SocketResponse.Message.INTEGRITY_FAIL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Las HMAC coinciden");
|
||||||
|
|
||||||
|
EntityManager em = conn.createEntityManager();
|
||||||
|
try {
|
||||||
|
if (transactionDAO.isNonceUsed(em, dto.getNonce())) {
|
||||||
|
res = new SocketResponse(SocketStatus.INTEGRITY_FAIL, SocketResponse.Message.REPLAY_ATTACK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
UserEntity fromUser = userDAO.getByUserName(em, dto.getFromUserName());
|
||||||
|
UserEntity toUser = userDAO.getByUserName(em, dto.getToUserName());
|
||||||
|
|
||||||
|
if (fromUser == null || !sessionDAO.isLoggedIn(em, fromUser.getUserId())) {
|
||||||
|
res = new SocketResponse(SocketStatus.SESSION_EXPIRED, SocketResponse.Message.SESSION_EXPIRED);
|
||||||
|
} else if (toUser == null) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.RECIPIENT_NOT_FOUND);
|
||||||
|
} else if (dto.getAmount() <= 0 || dto.getAmount() > fromUser.getBalance()) {
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.INVALID_AMOUNT);
|
||||||
|
} else {
|
||||||
|
TransactionEntity t = new TransactionEntity(UUID.randomUUID().toString(), fromUser, toUser, dto.getAmount());
|
||||||
|
t.setNonce(dto.getNonce());
|
||||||
|
|
||||||
|
fromUser.setBalance(fromUser.getBalance() - dto.getAmount());
|
||||||
|
toUser.setBalance(toUser.getBalance() + dto.getAmount());
|
||||||
|
|
||||||
|
em.persist(t);
|
||||||
|
em.merge(fromUser);
|
||||||
|
em.merge(toUser);
|
||||||
|
|
||||||
|
res = new SocketResponse(SocketStatus.OK, SocketResponse.Message.TRANSACTION_SENT, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (em.getTransaction().isActive()) em.getTransaction().rollback();
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
res = new SocketResponse(SocketStatus.ERROR, SocketResponse.Message.UNKNOWN_ERROR, e.getMessage());
|
||||||
|
} finally {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default -> {
|
||||||
|
logger.warn("Acción desconocida recibida: {}", msg.getAction());
|
||||||
|
res = new SocketResponse(SocketStatus.INVALID_REQUEST, SocketResponse.Message.UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.println(gson.toJson(res));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Fallo procesando solicitud", e);
|
||||||
|
} finally {
|
||||||
|
input.close();
|
||||||
|
output.close();
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Integridos/src/main/resources/META-INF/persistence.xml
Normal file
30
Integridos/src/main/resources/META-INF/persistence.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||||
|
version="2.0">
|
||||||
|
|
||||||
|
<persistence-unit name="ssii-pai1">
|
||||||
|
<description>
|
||||||
|
Persistence unit for PAI-1
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<class>net.miarma.integridos.common.db.entities.UserEntity</class>
|
||||||
|
<class>net.miarma.integridos.common.db.entities.TransactionEntity</class>
|
||||||
|
<class>net.miarma.integridos.common.db.entities.SessionEntity</class>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="jakarta.persistence.jdbc.url" value="jdbc:mariadb://miarma.net:3307/pai1" />
|
||||||
|
<property name="jakarta.persistence.jdbc.user" value="admin" />
|
||||||
|
<property name="jakarta.persistence.jdbc.password" value="55ii.P4I.1;" />
|
||||||
|
<property name="jakarta.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/>
|
||||||
|
<property name="hibernate.dialect" value="org.hibernate.dialect.MariaDBDialect" />
|
||||||
|
|
||||||
|
<property name="hibernate.show_sql" value="true" />
|
||||||
|
<property name="hibernate.format_sql" value="true" />
|
||||||
|
<property name="hibernate.highlight_sql" value="true" />
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</persistence-unit>
|
||||||
|
|
||||||
|
</persistence>
|
||||||
|
|
||||||
1
Integridos/src/main/resources/default.properties
Normal file
1
Integridos/src/main/resources/default.properties
Normal file
@@ -0,0 +1 @@
|
|||||||
|
secret=
|
||||||
BIN
Integridos/src/main/resources/images/banco.png
Normal file
BIN
Integridos/src/main/resources/images/banco.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
53
Integridos/src/main/resources/logback.xml
Normal file
53
Integridos/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="CLIENT" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/client.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/client-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="SERVER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>log/server.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>log/server-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="net.miarma.integridos.ui" level="INFO" additivity="false">
|
||||||
|
<appender-ref ref="CLIENT"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="net.miarma.integridos.client.ClientSocket" level="INFO" additivity="false">
|
||||||
|
<appender-ref ref="CLIENT"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="net.miarma.integridos.server.RemoteSocket" level="DEBUG" additivity="false">
|
||||||
|
<appender-ref ref="SERVER"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
<logger name="net.miarma.integridos.db" level="INFO" additivity="false">
|
||||||
|
<appender-ref ref="SERVER"/>
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
77
Integridos/src/main/resources/scripts/db.sql
Normal file
77
Integridos/src/main/resources/scripts/db.sql
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
USE pai1;
|
||||||
|
|
||||||
|
-- Cleanup
|
||||||
|
DROP TABLE IF EXISTS sessions;
|
||||||
|
DROP TABLE IF EXISTS transactions;
|
||||||
|
DROP TABLE IF EXISTS users;
|
||||||
|
-- END Cleanup
|
||||||
|
|
||||||
|
-- DDL
|
||||||
|
CREATE TABLE users (
|
||||||
|
userId UUID NOT NULL,
|
||||||
|
userName VARCHAR(64) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(256) NOT NULL,
|
||||||
|
balance DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (userId)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE transactions (
|
||||||
|
transactionId UUID NOT NULL,
|
||||||
|
fromUser UUID NOT NULL,
|
||||||
|
toUser UUID NOT NULL,
|
||||||
|
transactionAmount DECIMAL(12,2) NOT NULL,
|
||||||
|
nonce TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (transactionId),
|
||||||
|
FOREIGN KEY (fromUser) REFERENCES users (userId) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (toUser) REFERENCES users (userId) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sessions (
|
||||||
|
sessionId UUID NOT NULL,
|
||||||
|
userId UUID NOT NULL,
|
||||||
|
createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
expiresAt TIMESTAMP AS (createdAt + INTERVAL 15 MINUTE) STORED,
|
||||||
|
PRIMARY KEY (sessionId),
|
||||||
|
FOREIGN KEY (userId) REFERENCES users(userId) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE EVENT IF NOT EXISTS clear_expired_sessions
|
||||||
|
ON SCHEDULE EVERY 1 MINUTE
|
||||||
|
DO
|
||||||
|
DELETE FROM sessions WHERE expiresAt <= NOW();
|
||||||
|
|
||||||
|
CREATE OR REPLACE TRIGGER tr_subtract_amount
|
||||||
|
AFTER INSERT ON transactions
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE users
|
||||||
|
SET balance = balance - NEW.transactionAmount
|
||||||
|
WHERE userId = NEW.fromUser;
|
||||||
|
END;
|
||||||
|
-- END DDL
|
||||||
|
|
||||||
|
-- DML
|
||||||
|
INSERT INTO users (userId, userName, password, balance)
|
||||||
|
VALUES
|
||||||
|
(UUID(), 'pepe', 'pass123', 100.50),
|
||||||
|
(UUID(), 'lola', 'secreto', 250.00);
|
||||||
|
|
||||||
|
INSERT INTO transactions (transactionId, fromUser, toUser, transactionAmount)
|
||||||
|
VALUES (
|
||||||
|
UUID(),
|
||||||
|
(SELECT userId FROM users WHERE userName = 'pepe'),
|
||||||
|
(SELECT userId FROM users WHERE userName = 'lola'),
|
||||||
|
25.75
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO sessions (sessionId, userId)
|
||||||
|
VALUES (
|
||||||
|
UUID(),
|
||||||
|
(SELECT userId FROM users WHERE userName = 'pepe')
|
||||||
|
);
|
||||||
|
-- END DML
|
||||||
|
|
||||||
|
-- DQL
|
||||||
|
SELECT * FROM sessions;
|
||||||
|
|
||||||
|
-- END DQL
|
||||||
0
RedTeamPro/.gitkeep
Normal file
0
RedTeamPro/.gitkeep
Normal file
0
Vulnaweb/.gitkeep
Normal file
0
Vulnaweb/.gitkeep
Normal file
Reference in New Issue
Block a user