blackcoffee2 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/CHANGELOG.md +664 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +25 -0
  4. package/README.md +246 -0
  5. package/apps.zip +0 -0
  6. package/bin/adminclient +105 -0
  7. package/bin/blackcoffee +133 -0
  8. package/cli/admin-users.js +282 -0
  9. package/cli/commands/app.js +561 -0
  10. package/cli/commands/config.js +182 -0
  11. package/cli/commands/db.js +257 -0
  12. package/cli/commands/server.js +200 -0
  13. package/config/applications.json +5 -0
  14. package/config/database.json +28 -0
  15. package/config/database.json.example +23 -0
  16. package/config/server.json +32 -0
  17. package/controllers/admin/AdminController.js +529 -0
  18. package/controllers/admin/AdminViewController.js +90 -0
  19. package/controllers/admin/AuthController.js +293 -0
  20. package/controllers/admin/DatabaseAdminController.js +218 -0
  21. package/core/SQLiteAdapter.js +333 -0
  22. package/core/appLoader.js +385 -0
  23. package/core/databasePoolManager.js +431 -0
  24. package/core/hotReload.js +363 -0
  25. package/data/ADMIN-README.md +145 -0
  26. package/data/CHANGELOG.md +48 -0
  27. package/data/GTK3-NODE-PROPOSALS.md +410 -0
  28. package/data/admin-db.js +150 -0
  29. package/data/admin-gui.js +452 -0
  30. package/data/blackcoffee_admin.db-shm +0 -0
  31. package/data/blackcoffee_admin.db-wal +0 -0
  32. package/data/migrations/001_create_admin_users.sql +33 -0
  33. package/docs/APP_HOOKS_HANDLER.md +432 -0
  34. package/docs/APP_HOOKS_REQUIREMENTS.md +588 -0
  35. package/docs/ARCHITECTURE.md +435 -0
  36. package/docs/CREAR_APP_Y_USAR_POOLS.md +1595 -0
  37. package/docs/EVENTS_APP_MANUAL.md +289 -0
  38. package/docs/INSITU_BINARY_UPLOAD_PROPOSAL.md +186 -0
  39. package/docs/INSITU_FIREWALL_EXCEPTION.md +187 -0
  40. package/docs/ROADMAP.md +242 -0
  41. package/docs/ROADMAP.md.backup +243 -0
  42. package/includes/404-hooks.js +423 -0
  43. package/includes/adminAuth.js +214 -0
  44. package/includes/adminExtension.js +53 -0
  45. package/includes/appHooks.js +302 -0
  46. package/includes/initAdminDb.js +115 -0
  47. package/includes/routeLoader.js +67 -0
  48. package/includes/sessions.js +223 -0
  49. package/issues/001-duplicate-module-loading.md +92 -0
  50. package/manuales/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
  51. package/manuales/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
  52. package/manuales/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
  53. package/manuales/CACHE_REGEX_COMMANDS.md +136 -0
  54. package/manuales/CACHE_SYSTEM_MAP.md +206 -0
  55. package/manuales/CREACION_DE_CONTROLADORES_INSITU.md +383 -0
  56. package/manuales/QUEUE_CLI_MODULE_MANUAL.md +289 -0
  57. package/manuales/QUEUE_SYSTEM_MANUAL.md +320 -0
  58. package/manuales/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
  59. package/manuales/SESSION_MANAGER_GUIDE.md +529 -0
  60. package/manuales/SESSION_SECURITY_FLAGS.md +174 -0
  61. package/manuales/WAF_MODULE_MANUAL.md +229 -0
  62. package/manuales/after_route_handler_filter_example.md +116 -0
  63. package/manuales/after_route_handler_usage.md +130 -0
  64. package/manuales/an/303/241lisis-completo-insitu-framework.md +213 -0
  65. package/manuales/async_hooks_promises_guide.md +325 -0
  66. package/manuales/before_route_handler_filter_example.md +97 -0
  67. package/manuales/before_route_handler_usage.md +122 -0
  68. package/manuales/hooks_chaining_conditions_guide.md +261 -0
  69. package/manuales/hooks_filters_documentation.md +493 -0
  70. package/manuales/hooks_filters_documentation_en.md +493 -0
  71. package/manuales/hooks_vs_middlewares_comparison.md +87 -0
  72. package/manuales/manual-mvc-completo.md +934 -0
  73. package/manuales/modulos_administracion.md +89 -0
  74. package/manuales/router_execution_points.md +74 -0
  75. package/manuales/static_file_hooks_usage.md +222 -0
  76. package/models/AdminUserModel.js +132 -0
  77. package/package.json +45 -0
  78. package/programatically/PRoutes.js +89 -0
  79. package/programatically/initFlow.js +211 -0
  80. package/public/admin/css/db-pools.css +336 -0
  81. package/public/admin/css/styles.css +310 -0
  82. package/public/admin/database.html +312 -0
  83. package/public/admin/index.html +116 -0
  84. package/public/admin/js/app.js +470 -0
  85. package/public/admin/js/db-pools.js +253 -0
  86. package/public/admin/login.html +278 -0
  87. package/public/assets/css/styles.css +477 -0
  88. package/public/assets/js/main.js +89 -0
  89. package/public/index.html +136 -0
  90. package/public/templates/404.html +158 -0
  91. package/routes/admin-views.json +20 -0
  92. package/routes/admin.json +38 -0
  93. package/routes/auth.json +32 -0
  94. package/routes/static.json +18 -0
  95. package/server.js +299 -0
  96. package/test-aplicacion.con-logisession/BlackCoffee.js +226 -0
  97. package/test-aplicacion.con-logisession/SSL_SETUP.md +53 -0
  98. package/test-aplicacion.con-logisession/certs/ca-certificate.pem +32 -0
  99. package/test-aplicacion.con-logisession/certs/ca-private-key.pem +52 -0
  100. package/test-aplicacion.con-logisession/certs/certificate-2048.pem +22 -0
  101. package/test-aplicacion.con-logisession/certs/certificate.pem +32 -0
  102. package/test-aplicacion.con-logisession/certs/private-key-2048.pem +28 -0
  103. package/test-aplicacion.con-logisession/certs/private-key.pem +52 -0
  104. package/test-aplicacion.con-logisession/config/iaQueueSetup.js +84 -0
  105. package/test-aplicacion.con-logisession/config/qwen-rules.json +39 -0
  106. package/test-aplicacion.con-logisession/controllers/analyticsController.js +117 -0
  107. package/test-aplicacion.con-logisession/controllers/auth/AdminAuthController.js +142 -0
  108. package/test-aplicacion.con-logisession/controllers/auth/AuthController.js +439 -0
  109. package/test-aplicacion.con-logisession/controllers/auth/AuthViewController.js +223 -0
  110. package/test-aplicacion.con-logisession/controllers/endpointController.js +66 -0
  111. package/test-aplicacion.con-logisession/controllers/example.js +183 -0
  112. package/test-aplicacion.con-logisession/controllers/iaQueueController.js +367 -0
  113. package/test-aplicacion.con-logisession/controllers/queueController.js +206 -0
  114. package/test-aplicacion.con-logisession/controllers/qwenQueueController.js +197 -0
  115. package/test-aplicacion.con-logisession/controllers/test.js +0 -0
  116. package/test-aplicacion.con-logisession/controllers/tracking/EventsNoFinishController.js +78 -0
  117. package/test-aplicacion.con-logisession/controllers/tracking/TrackingController.js +412 -0
  118. package/test-aplicacion.con-logisession/controllers/tracking/TrackingControllerWithLoadModel.js +437 -0
  119. package/test-aplicacion.con-logisession/hooks/admin-hooks.js +20 -0
  120. package/test-aplicacion.con-logisession/hooks/general-hooks.js +97 -0
  121. package/test-aplicacion.con-logisession/hooks/queue-hooks.js +64 -0
  122. package/test-aplicacion.con-logisession/hooks/route-directory-hooks.js +38 -0
  123. package/test-aplicacion.con-logisession/hooks/security-hooks.js +24 -0
  124. package/test-aplicacion.con-logisession/insitu-admin-client/README.md +69 -0
  125. package/test-aplicacion.con-logisession/insitu-admin-client/package.json +23 -0
  126. package/test-aplicacion.con-logisession/insitu-admin-client.js +257 -0
  127. package/test-aplicacion.con-logisession/models/ExampleModel.js +88 -0
  128. package/test-aplicacion.con-logisession/models/QueueJobModel.js +263 -0
  129. package/test-aplicacion.con-logisession/models/TokenModel.js +207 -0
  130. package/test-aplicacion.con-logisession/models/auth/AuthModel.js +66 -0
  131. package/test-aplicacion.con-logisession/models/auth/UserModel.js +189 -0
  132. package/test-aplicacion.con-logisession/models/tracking/CompletedCartModel.js +213 -0
  133. package/test-aplicacion.con-logisession/models/tracking/EventModel.js +366 -0
  134. package/test-aplicacion.con-logisession/models/tracking/EventsNoFinishModel.js +131 -0
  135. package/test-aplicacion.con-logisession/models/tracking/SessionModel.js +360 -0
  136. package/test-aplicacion.con-logisession/models/tracking/SiteFlowModel.js +286 -0
  137. package/test-aplicacion.con-logisession/models/tracking/TokenModel.js +207 -0
  138. package/test-aplicacion.con-logisession/package-lock.json +3313 -0
  139. package/test-aplicacion.con-logisession/package.json +32 -0
  140. package/test-aplicacion.con-logisession/public/blackcoffee-welcome/index.html +1339 -0
  141. package/test-aplicacion.con-logisession/public/css/style.css +64 -0
  142. package/test-aplicacion.con-logisession/public/ejemplo-estatica/index.html +18 -0
  143. package/test-aplicacion.con-logisession/public/ejemplo-estatica/script.js +16 -0
  144. package/test-aplicacion.con-logisession/public/ejemplo-estatica/styles.css +43 -0
  145. package/test-aplicacion.con-logisession/public/images/logo.svg +7 -0
  146. package/test-aplicacion.con-logisession/public/js/main.js +67 -0
  147. package/test-aplicacion.con-logisession/routes/analytics-routes.json +8 -0
  148. package/test-aplicacion.con-logisession/routes/auth-routes.json +98 -0
  149. package/test-aplicacion.con-logisession/routes/blackcoffee-welcome-routes.json +20 -0
  150. package/test-aplicacion.con-logisession/routes/duplicate-test-routes.json.disabled +16 -0
  151. package/test-aplicacion.con-logisession/routes/ejemplo-estatica-routes.json +11 -0
  152. package/test-aplicacion.con-logisession/routes/endpoints-routes.json +8 -0
  153. package/test-aplicacion.con-logisession/routes/ia-queue-routes.json +26 -0
  154. package/test-aplicacion.con-logisession/routes/product-routes.json.disabled +20 -0
  155. package/test-aplicacion.con-logisession/routes/queue-routes.json +32 -0
  156. package/test-aplicacion.con-logisession/routes/qwen-routes.json +14 -0
  157. package/test-aplicacion.con-logisession/routes/static-routes.json +29 -0
  158. package/test-aplicacion.con-logisession/routes/tracking-routes.json +58 -0
  159. package/test-aplicacion.con-logisession/routes/tracking-with-loadmodel-routes.json +51 -0
  160. package/test-aplicacion.con-logisession/utils/dbAdapter.js +88 -0
  161. package/test-aplicacion.con-logisession/utils/qbWrapper.js +4 -0
  162. package/test-aplicacion.con-logisession/utils/queueProcessor.js +305 -0
  163. package/test-aplicacion.con-logisession/utils/qwenRulesService.js +131 -0
  164. package/test-aplicacion.con-logisession/utils/tokenHelper.js +22 -0
  165. package/test-aplicacion.con-logisession/views/auth/dashboard.html +443 -0
  166. package/test-aplicacion.con-logisession/views/auth/forgot-password.html +200 -0
  167. package/test-aplicacion.con-logisession/views/auth/login.html +213 -0
  168. package/test-aplicacion.con-logisession/views/auth/register.html +294 -0
  169. package/test-aplicacion.con-logisession/views/contact/form.html +47 -0
  170. package/test-aplicacion.con-logisession/views/products/index.html +39 -0
@@ -0,0 +1,117 @@
1
+ const { ControllerBase } = require('insitu-js');
2
+ const { spawn, exec } = require('child_process');
3
+
4
+ class AnalyticsController extends ControllerBase {
5
+ constructor(options = {}) {
6
+ super(options);
7
+ }
8
+
9
+ // Método para procesar datos de métricas y prompt con Qwen
10
+ async processAnalytics(req, res) {
11
+ try {
12
+ // Obtener el cuerpo de la solicitud
13
+ let requestData = {};
14
+
15
+ // Parsear el cuerpo de la solicitud
16
+ if (req.body) {
17
+ if (typeof req.body === 'string') {
18
+ requestData = JSON.parse(req.body);
19
+ } else {
20
+ requestData = req.body;
21
+ }
22
+ } else {
23
+ // Si no está en req.body, intentar parsear desde raw body si está disponible
24
+ if (req.rawBody) {
25
+ requestData = JSON.parse(req.rawBody);
26
+ } else {
27
+ // Para casos donde necesitamos leer directamente del stream
28
+ let body = '';
29
+ for await (const chunk of req) {
30
+ body += chunk.toString();
31
+ }
32
+ requestData = JSON.parse(body);
33
+ }
34
+ }
35
+
36
+ // Extraer las secciones del JSON
37
+ const { metrics, prompt } = requestData;
38
+
39
+ // Validar que ambas secciones existan
40
+ if (!metrics) {
41
+ return this.json(res, {
42
+ success: false,
43
+ error: 'Missing metrics section in request'
44
+ }, 400);
45
+ }
46
+
47
+ if (!prompt) {
48
+ return this.json(res, {
49
+ success: false,
50
+ error: 'Missing prompt section in request'
51
+ }, 400);
52
+ }
53
+
54
+ // Convertir los datos de métricas a string para el comando y escapar comillas
55
+ const metricsString = JSON.stringify(metrics).replace(/"/g, '\\"');
56
+
57
+ // Construir el comando para Qwen usando la bandera -p para modo no interactivo
58
+ const qwenCommand = `qwen -p "${prompt} ${metricsString}"`;
59
+
60
+ // Ejecutar el comando de Qwen y esperar la respuesta
61
+ const qwenResult = await this.executeQwenSync(qwenCommand);
62
+
63
+ // Devolver la respuesta completa incluyendo la respuesta de Qwen
64
+ this.json(res, {
65
+ success: true,
66
+ data: {
67
+ originalRequest: { metrics, prompt },
68
+ qwenResponse: qwenResult.stdout,
69
+ commandUsed: qwenCommand,
70
+ error: qwenResult.stderr || null
71
+ }
72
+ });
73
+
74
+ } catch (error) {
75
+ // Manejar errores de parsing u otros
76
+ this.json(res, {
77
+ success: false,
78
+ error: error.message
79
+ }, 500);
80
+ }
81
+ }
82
+
83
+ // Método para ejecutar Qwen de forma síncrona (esperando la respuesta)
84
+ async executeQwenSync(command) {
85
+ const { exec } = require('child_process');
86
+ const util = require('util');
87
+ const execAsync = util.promisify(exec);
88
+
89
+ try {
90
+ // Ejecutar el comando usando exec en lugar de spawn para manejar correctamente las comillas
91
+ const result = await execAsync(command);
92
+ return {
93
+ stdout: result.stdout,
94
+ stderr: result.stderr,
95
+ code: 0
96
+ };
97
+ } catch (error) {
98
+ // En caso de error, devolver el error con formato consistente
99
+ return {
100
+ stdout: error.stdout || '',
101
+ stderr: error.stderr || error.message,
102
+ code: error.code || 1
103
+ };
104
+ }
105
+ }
106
+ }
107
+
108
+ // Instanciar el controlador
109
+ const controllerInstance = new AnalyticsController();
110
+
111
+ // Exportar métodos individualmente para que RouteLoader pueda acceder a ellos
112
+ module.exports = {
113
+ processAnalytics: (req, res) => {
114
+ controllerInstance.setRequestResponse(req, res);
115
+ controllerInstance.processAnalytics(req, res);
116
+ }
117
+ };
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Controlador de autenticación de administración simplificado (sin roles y capacidades)
3
+ * AdminAuthController.js
4
+ */
5
+
6
+ const { ControllerBase } = require('insitu-js');
7
+
8
+ class AdminAuthController extends ControllerBase {
9
+ constructor(options = {}) {
10
+ super(options);
11
+ }
12
+
13
+ /**
14
+ * Verifica si el usuario tiene rol de administrador
15
+ * @param {Object} req - Objeto de solicitud
16
+ * @returns {Promise<boolean>} - True si es admin
17
+ */
18
+ async checkAdminRole(req) {
19
+ // En esta versión simplificada, todos los usuarios autenticados pueden acceder
20
+ // a funciones de administrador (en un entorno real, se verificaría un rol específico)
21
+ if (req.session && req.session.data && req.session.data.authenticated) {
22
+ return true;
23
+ }
24
+ return false;
25
+ }
26
+
27
+ /**
28
+ * Crea un nuevo rol
29
+ * POST /api/admin/roles
30
+ */
31
+ async createRole(req, res) {
32
+ // En esta versión simplificada, no se soporta la creación de roles
33
+ this.json(res, {
34
+ success: false,
35
+ error: 'Funcionalidad de roles y capacidades deshabilitada en esta versión'
36
+ }, 501);
37
+ }
38
+
39
+ /**
40
+ * Obtiene todos los roles
41
+ * GET /api/admin/roles
42
+ */
43
+ async getRoles(req, res) {
44
+ // En esta versión simplificada, devolvemos una lista vacía
45
+ this.json(res, {
46
+ success: true,
47
+ roles: []
48
+ });
49
+ }
50
+
51
+ /**
52
+ * Crea una nueva capability
53
+ * POST /api/admin/capabilities
54
+ */
55
+ async createCapability(req, res) {
56
+ // En esta versión simplificada, no se soporta la creación de capabilities
57
+ this.json(res, {
58
+ success: false,
59
+ error: 'Funcionalidad de roles y capacidades deshabilitada en esta versión'
60
+ }, 501);
61
+ }
62
+
63
+ /**
64
+ * Obtiene todas las capabilities
65
+ * GET /api/admin/capabilities
66
+ */
67
+ async getCapabilities(req, res) {
68
+ // En esta versión simplificada, devolvemos una lista vacía
69
+ this.json(res, {
70
+ success: true,
71
+ capabilities: []
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Asigna un rol a un usuario
77
+ * POST /api/admin/users/:userId/assign-role
78
+ */
79
+ async assignRoleToUser(req, res) {
80
+ // En esta versión simplificada, no se soporta la asignación de roles
81
+ this.json(res, {
82
+ success: false,
83
+ error: 'Funcionalidad de roles y capacidades deshabilitada en esta versión'
84
+ }, 501);
85
+ }
86
+
87
+ /**
88
+ * Asigna una capability a un usuario
89
+ * POST /api/admin/users/:userId/assign-capability
90
+ */
91
+ async assignCapabilityToUser(req, res) {
92
+ // En esta versión simplificada, no se soporta la asignación de capabilities
93
+ this.json(res, {
94
+ success: false,
95
+ error: 'Funcionalidad de roles y capacidades deshabilitada en esta versión'
96
+ }, 501);
97
+ }
98
+
99
+ /**
100
+ * Método para validar token
101
+ */
102
+ async validateToken(token) {
103
+ try {
104
+ const { validateToken } = require('../../utils/tokenHelper');
105
+ const isValid = await validateToken(token);
106
+ return isValid;
107
+ } catch (error) {
108
+ console.error('Error validando token:', error);
109
+ return false;
110
+ }
111
+ }
112
+ }
113
+
114
+ // Exportar métodos individualmente para que RouteLoader pueda acceder a ellos
115
+ const controllerInstance = new AdminAuthController();
116
+
117
+ module.exports = {
118
+ createRole: (req, res) => {
119
+ controllerInstance.setRequestResponse(req, res);
120
+ controllerInstance.createRole(req, res);
121
+ },
122
+ getRoles: (req, res) => {
123
+ controllerInstance.setRequestResponse(req, res);
124
+ controllerInstance.getRoles(req, res);
125
+ },
126
+ createCapability: (req, res) => {
127
+ controllerInstance.setRequestResponse(req, res);
128
+ controllerInstance.createCapability(req, res);
129
+ },
130
+ getCapabilities: (req, res) => {
131
+ controllerInstance.setRequestResponse(req, res);
132
+ controllerInstance.getCapabilities(req, res);
133
+ },
134
+ assignRoleToUser: (req, res) => {
135
+ controllerInstance.setRequestResponse(req, res);
136
+ controllerInstance.assignRoleToUser(req, res);
137
+ },
138
+ assignCapabilityToUser: (req, res) => {
139
+ controllerInstance.setRequestResponse(req, res);
140
+ controllerInstance.assignCapabilityToUser(req, res);
141
+ }
142
+ };
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Controlador de autenticación para el framework JERK
3
+ * AuthController.js
4
+ */
5
+
6
+ const { ControllerBase } = require('insitu-js');
7
+ const AuthModel = require('../../models/auth/AuthModel');
8
+ const { validateToken } = require('../../utils/tokenHelper');
9
+ const jwt = require('jsonwebtoken');
10
+
11
+ class AuthController extends ControllerBase {
12
+ constructor(options = {}) {
13
+ super(options);
14
+ this.authModel = new AuthModel();
15
+ }
16
+
17
+ /**
18
+ * Endpoint para login de usuarios
19
+ * POST /api/auth/login
20
+ */
21
+ async login(req, res) {
22
+ try {
23
+ const { username, password } = req.body;
24
+
25
+ if (!username || !password) {
26
+ return this.json(res, {
27
+ success: false,
28
+ error: 'Username y password son requeridos'
29
+ }, 400);
30
+ }
31
+
32
+ // Autenticar al usuario
33
+ const user = await this.authModel.authenticateUser(username, password);
34
+
35
+ if (!user) {
36
+ return this.json(res, {
37
+ success: false,
38
+ error: 'Credenciales inválidas'
39
+ }, 401);
40
+ }
41
+
42
+ // Crear sesión de usuario autenticado
43
+ if (req.session) {
44
+ req.session.create({
45
+ authenticated: true,
46
+ userId: user.id,
47
+ username: user.username,
48
+ email: user.email
49
+ });
50
+ }
51
+
52
+ // Generar token JWT para el usuario autenticado
53
+ const jwt = require('jsonwebtoken');
54
+ const secret = process.env.JWT_SECRET || 'default_secret_key_for_dev';
55
+
56
+ const tokenPayload = {
57
+ userId: user.id,
58
+ username: user.username,
59
+ email: user.email
60
+ };
61
+
62
+ const token = jwt.sign(tokenPayload, secret, { expiresIn: '24h' });
63
+
64
+ // Guardar el token en la base de datos
65
+ const TokenModel = require('../../models/tracking/TokenModel');
66
+ const tokenModel = new TokenModel();
67
+
68
+ await tokenModel.createToken({
69
+ token: token,
70
+ user_id: user.id,
71
+ store_id: 1 // ID del store predeterminado
72
+ });
73
+
74
+ // Obtener información del usuario
75
+ const userInfo = await this.authModel.getUserById(user.id);
76
+
77
+ this.json(res, {
78
+ success: true,
79
+ message: 'Inicio de sesión exitoso',
80
+ token: token, // Incluir el token en la respuesta
81
+ user: {
82
+ id: user.id,
83
+ username: user.username,
84
+ email: user.email,
85
+ roles: userInfo.roles || [],
86
+ capabilities: userInfo.capabilities || []
87
+ }
88
+ });
89
+ } catch (error) {
90
+ console.error('Error en login:', error);
91
+ this.json(res, {
92
+ success: false,
93
+ error: error.message
94
+ }, 500);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Endpoint para registro de usuarios
100
+ * POST /api/auth/register
101
+ */
102
+ async register(req, res) {
103
+ try {
104
+ const { username, password, email } = req.body;
105
+
106
+ if (!username || !password || !email) {
107
+ return this.json(res, {
108
+ success: false,
109
+ error: 'Username, password y email son requeridos'
110
+ }, 400);
111
+ }
112
+
113
+ // Verificar si el usuario ya existe
114
+ const existingUser = await this.authModel.userModel.getUserByIdentifier(username);
115
+ if (existingUser) {
116
+ return this.json(res, {
117
+ success: false,
118
+ error: 'El nombre de usuario ya existe'
119
+ }, 409);
120
+ }
121
+
122
+ // Verificar si el email ya existe
123
+ const existingEmail = await this.authModel.userModel.queryBuilder
124
+ .reset()
125
+ .select('*')
126
+ .where('email', email)
127
+ .first();
128
+
129
+ if (existingEmail) {
130
+ return this.json(res, {
131
+ success: false,
132
+ error: 'El email ya está registrado'
133
+ }, 409);
134
+ }
135
+
136
+ // Registrar al nuevo usuario
137
+ const newUser = await this.authModel.registerUser({
138
+ username,
139
+ password,
140
+ email
141
+ });
142
+
143
+ // Obtener información del usuario
144
+ const userInfo = await this.authModel.getUserById(newUser.id);
145
+
146
+ this.json(res, {
147
+ success: true,
148
+ message: 'Usuario registrado exitosamente',
149
+ user: {
150
+ id: newUser.id,
151
+ username: newUser.username,
152
+ email: newUser.email,
153
+ roles: userInfo.roles || [],
154
+ capabilities: userInfo.capabilities || []
155
+ }
156
+ });
157
+ } catch (error) {
158
+ console.error('Error en registro:', error);
159
+ this.json(res, {
160
+ success: false,
161
+ error: error.message
162
+ }, 500);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Endpoint para obtener el perfil del usuario autenticado
168
+ * GET /api/auth/profile
169
+ */
170
+ async profile(req, res) {
171
+ try {
172
+ // Verificar si el usuario está autenticado a través de la sesión
173
+ if (!req.session || !req.session.data || !req.session.data.authenticated) {
174
+ return this.json(res, {
175
+ success: false,
176
+ error: 'Usuario no autenticado'
177
+ }, 401);
178
+ }
179
+
180
+ // Obtener información del usuario desde la sesión
181
+ const sessionData = req.session.data;
182
+ const userId = sessionData.userId;
183
+
184
+ // Obtener información del usuario
185
+ const user = await this.authModel.getUserById(userId);
186
+
187
+ if (!user) {
188
+ return this.json(res, {
189
+ success: false,
190
+ error: 'Usuario no encontrado'
191
+ }, 404);
192
+ }
193
+
194
+ this.json(res, {
195
+ success: true,
196
+ user: {
197
+ id: user.id,
198
+ username: user.username,
199
+ email: user.email,
200
+ roles: user.roles,
201
+ capabilities: user.capabilities
202
+ }
203
+ });
204
+ } catch (error) {
205
+ console.error('Error en profile:', error);
206
+ this.json(res, {
207
+ success: false,
208
+ error: error.message
209
+ }, 500);
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Endpoint para verificar si un usuario tiene una capability específica
215
+ * GET /api/auth/check-capability
216
+ */
217
+ async checkCapability(req, res) {
218
+ try {
219
+ // Verificar si el usuario está autenticado a través de la sesión
220
+ if (!req.session || !req.session.data || !req.session.data.authenticated) {
221
+ return this.json(res, {
222
+ success: false,
223
+ error: 'Usuario no autenticado'
224
+ }, 401);
225
+ }
226
+
227
+ // Obtener información del usuario desde la sesión
228
+ const sessionData = req.session.data;
229
+ const userId = sessionData.userId;
230
+
231
+ // Obtener el nombre de la capability de los parámetros de consulta
232
+ const capabilityName = req.query.capability;
233
+ if (!capabilityName) {
234
+ return this.json(res, {
235
+ success: false,
236
+ error: 'Nombre de capability requerido'
237
+ }, 400);
238
+ }
239
+
240
+ // Verificar si el usuario tiene la capability
241
+ const hasCapability = await this.authModel.userHasCapability(userId, capabilityName);
242
+
243
+ this.json(res, {
244
+ success: true,
245
+ hasCapability: hasCapability,
246
+ capability: capabilityName,
247
+ userId: userId
248
+ });
249
+ } catch (error) {
250
+ console.error('Error en checkCapability:', error);
251
+ this.json(res, {
252
+ success: false,
253
+ error: error.message
254
+ }, 500);
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Endpoint para logout de usuarios
260
+ * POST /api/auth/logout
261
+ */
262
+ async logout(req, res) {
263
+ try {
264
+ // Destruir la sesión si existe
265
+ if (req.session) {
266
+ req.session.destroy();
267
+ }
268
+
269
+ // Si se proporciona un token en el header, revocarlo
270
+ const authHeader = req.headers['authorization'];
271
+ if (authHeader && authHeader.startsWith('Bearer ')) {
272
+ const token = authHeader.substring(7); // Remover 'Bearer ' del principio
273
+
274
+ // Revocar el token específico
275
+ const TokenModel = require('../../models/tracking/TokenModel');
276
+ const tokenModel = new TokenModel();
277
+
278
+ try {
279
+ await tokenModel.revokeToken(token);
280
+ } catch (revokeError) {
281
+ console.error('Error revocando token durante logout:', revokeError);
282
+ // No lanzar error si falla la revocación del token, solo registrar
283
+ }
284
+ }
285
+
286
+ this.json(res, {
287
+ success: true,
288
+ message: 'Cierre de sesión exitoso'
289
+ });
290
+ } catch (error) {
291
+ console.error('Error en logout:', error);
292
+ this.json(res, {
293
+ success: false,
294
+ error: error.message
295
+ }, 500);
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Método para validar token
301
+ */
302
+ async validateToken(token) {
303
+ try {
304
+ const isValid = await validateToken(token);
305
+ return isValid;
306
+ } catch (error) {
307
+ console.error('Error validando token:', error);
308
+ return false;
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Endpoint para verificar si un usuario tiene un rol específico
314
+ * GET /api/auth/check-role
315
+ */
316
+ async checkRole(req, res) {
317
+ try {
318
+ // Verificar si el usuario está autenticado a través de la sesión o token
319
+ const isAuthenticated = await this.checkAuthentication(req);
320
+
321
+ if (!isAuthenticated) {
322
+ return this.json(res, {
323
+ success: false,
324
+ error: 'Usuario no autenticado'
325
+ }, 401);
326
+ }
327
+
328
+ // Obtener el ID del usuario desde la sesión o token
329
+ const userId = await this.getUserIdFromRequest(req);
330
+
331
+ // Obtener el nombre del rol de los parámetros de consulta
332
+ const roleName = req.query.role;
333
+ if (!roleName) {
334
+ return this.json(res, {
335
+ success: false,
336
+ error: 'Nombre de rol requerido'
337
+ }, 400);
338
+ }
339
+
340
+ // Verificar si el usuario tiene el rol
341
+ const UserRoleModel = require('../models/UserRoleModel');
342
+ const userRoleModel = new UserRoleModel();
343
+
344
+ const hasRole = await userRoleModel.userHasRoleByName(userId, roleName);
345
+
346
+ this.json(res, {
347
+ success: true,
348
+ hasRole: hasRole,
349
+ role: roleName,
350
+ userId: userId
351
+ });
352
+ } catch (error) {
353
+ console.error('Error en checkRole:', error);
354
+ this.json(res, {
355
+ success: false,
356
+ error: error.message
357
+ }, 500);
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Método para verificar autenticación (token o sesión)
363
+ */
364
+ async checkAuthentication(req) {
365
+ // Primero verificar si hay un token de autorización
366
+ const authHeader = req.headers['authorization'];
367
+ if (authHeader && authHeader.startsWith('Bearer ')) {
368
+ const token = authHeader.substring(7); // Remover 'Bearer ' del principio
369
+ const isValidToken = await this.validateToken(token);
370
+ return isValidToken;
371
+ }
372
+
373
+ // Luego verificar si hay una sesión válida
374
+ if (req.session && req.session.data && req.session.data.authenticated) {
375
+ return true;
376
+ }
377
+
378
+ // Si no hay token ni sesión válidos
379
+ return false;
380
+ }
381
+
382
+ /**
383
+ * Método para obtener el ID del usuario desde la solicitud (token o sesión)
384
+ */
385
+ async getUserIdFromRequest(req) {
386
+ // Primero intentar obtener de token
387
+ const authHeader = req.headers['authorization'];
388
+ if (authHeader && authHeader.startsWith('Bearer ')) {
389
+ const token = authHeader.substring(7);
390
+ const jwt = require('jsonwebtoken');
391
+ const secret = process.env.JWT_SECRET || 'default_secret_key_for_dev';
392
+
393
+ try {
394
+ const decoded = jwt.verify(token, secret);
395
+ return decoded.userId;
396
+ } catch (error) {
397
+ console.error('Error decodificando token:', error);
398
+ return null;
399
+ }
400
+ }
401
+
402
+ // Luego intentar obtener de sesión
403
+ if (req.session && req.session.data && req.session.data.authenticated) {
404
+ return req.session.data.userId;
405
+ }
406
+
407
+ return null;
408
+ }
409
+ }
410
+
411
+ // Exportar métodos individualmente para que RouteLoader pueda acceder a ellos
412
+ const controllerInstance = new AuthController();
413
+
414
+ module.exports = {
415
+ login: (req, res) => {
416
+ controllerInstance.setRequestResponse(req, res);
417
+ controllerInstance.login(req, res);
418
+ },
419
+ register: (req, res) => {
420
+ controllerInstance.setRequestResponse(req, res);
421
+ controllerInstance.register(req, res);
422
+ },
423
+ profile: (req, res) => {
424
+ controllerInstance.setRequestResponse(req, res);
425
+ controllerInstance.profile(req, res);
426
+ },
427
+ checkCapability: (req, res) => {
428
+ controllerInstance.setRequestResponse(req, res);
429
+ controllerInstance.checkCapability(req, res);
430
+ },
431
+ logout: (req, res) => {
432
+ controllerInstance.setRequestResponse(req, res);
433
+ controllerInstance.logout(req, res);
434
+ },
435
+ checkRole: (req, res) => {
436
+ controllerInstance.setRequestResponse(req, res);
437
+ controllerInstance.checkRole(req, res);
438
+ }
439
+ };