[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