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.
- package/CHANGELOG.md +664 -0
- package/LICENSE +201 -0
- package/NOTICE +25 -0
- package/README.md +246 -0
- package/apps.zip +0 -0
- package/bin/adminclient +105 -0
- package/bin/blackcoffee +133 -0
- package/cli/admin-users.js +282 -0
- package/cli/commands/app.js +561 -0
- package/cli/commands/config.js +182 -0
- package/cli/commands/db.js +257 -0
- package/cli/commands/server.js +200 -0
- package/config/applications.json +5 -0
- package/config/database.json +28 -0
- package/config/database.json.example +23 -0
- package/config/server.json +32 -0
- package/controllers/admin/AdminController.js +529 -0
- package/controllers/admin/AdminViewController.js +90 -0
- package/controllers/admin/AuthController.js +293 -0
- package/controllers/admin/DatabaseAdminController.js +218 -0
- package/core/SQLiteAdapter.js +333 -0
- package/core/appLoader.js +385 -0
- package/core/databasePoolManager.js +431 -0
- package/core/hotReload.js +363 -0
- package/data/ADMIN-README.md +145 -0
- package/data/CHANGELOG.md +48 -0
- package/data/GTK3-NODE-PROPOSALS.md +410 -0
- package/data/admin-db.js +150 -0
- package/data/admin-gui.js +452 -0
- package/data/blackcoffee_admin.db-shm +0 -0
- package/data/blackcoffee_admin.db-wal +0 -0
- package/data/migrations/001_create_admin_users.sql +33 -0
- package/docs/APP_HOOKS_HANDLER.md +432 -0
- package/docs/APP_HOOKS_REQUIREMENTS.md +588 -0
- package/docs/ARCHITECTURE.md +435 -0
- package/docs/CREAR_APP_Y_USAR_POOLS.md +1595 -0
- package/docs/EVENTS_APP_MANUAL.md +289 -0
- package/docs/INSITU_BINARY_UPLOAD_PROPOSAL.md +186 -0
- package/docs/INSITU_FIREWALL_EXCEPTION.md +187 -0
- package/docs/ROADMAP.md +242 -0
- package/docs/ROADMAP.md.backup +243 -0
- package/includes/404-hooks.js +423 -0
- package/includes/adminAuth.js +214 -0
- package/includes/adminExtension.js +53 -0
- package/includes/appHooks.js +302 -0
- package/includes/initAdminDb.js +115 -0
- package/includes/routeLoader.js +67 -0
- package/includes/sessions.js +223 -0
- package/issues/001-duplicate-module-loading.md +92 -0
- package/manuales/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
- package/manuales/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
- package/manuales/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
- package/manuales/CACHE_REGEX_COMMANDS.md +136 -0
- package/manuales/CACHE_SYSTEM_MAP.md +206 -0
- package/manuales/CREACION_DE_CONTROLADORES_INSITU.md +383 -0
- package/manuales/QUEUE_CLI_MODULE_MANUAL.md +289 -0
- package/manuales/QUEUE_SYSTEM_MANUAL.md +320 -0
- package/manuales/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
- package/manuales/SESSION_MANAGER_GUIDE.md +529 -0
- package/manuales/SESSION_SECURITY_FLAGS.md +174 -0
- package/manuales/WAF_MODULE_MANUAL.md +229 -0
- package/manuales/after_route_handler_filter_example.md +116 -0
- package/manuales/after_route_handler_usage.md +130 -0
- package/manuales/an/303/241lisis-completo-insitu-framework.md +213 -0
- package/manuales/async_hooks_promises_guide.md +325 -0
- package/manuales/before_route_handler_filter_example.md +97 -0
- package/manuales/before_route_handler_usage.md +122 -0
- package/manuales/hooks_chaining_conditions_guide.md +261 -0
- package/manuales/hooks_filters_documentation.md +493 -0
- package/manuales/hooks_filters_documentation_en.md +493 -0
- package/manuales/hooks_vs_middlewares_comparison.md +87 -0
- package/manuales/manual-mvc-completo.md +934 -0
- package/manuales/modulos_administracion.md +89 -0
- package/manuales/router_execution_points.md +74 -0
- package/manuales/static_file_hooks_usage.md +222 -0
- package/models/AdminUserModel.js +132 -0
- package/package.json +45 -0
- package/programatically/PRoutes.js +89 -0
- package/programatically/initFlow.js +211 -0
- package/public/admin/css/db-pools.css +336 -0
- package/public/admin/css/styles.css +310 -0
- package/public/admin/database.html +312 -0
- package/public/admin/index.html +116 -0
- package/public/admin/js/app.js +470 -0
- package/public/admin/js/db-pools.js +253 -0
- package/public/admin/login.html +278 -0
- package/public/assets/css/styles.css +477 -0
- package/public/assets/js/main.js +89 -0
- package/public/index.html +136 -0
- package/public/templates/404.html +158 -0
- package/routes/admin-views.json +20 -0
- package/routes/admin.json +38 -0
- package/routes/auth.json +32 -0
- package/routes/static.json +18 -0
- package/server.js +299 -0
- package/test-aplicacion.con-logisession/BlackCoffee.js +226 -0
- package/test-aplicacion.con-logisession/SSL_SETUP.md +53 -0
- package/test-aplicacion.con-logisession/certs/ca-certificate.pem +32 -0
- package/test-aplicacion.con-logisession/certs/ca-private-key.pem +52 -0
- package/test-aplicacion.con-logisession/certs/certificate-2048.pem +22 -0
- package/test-aplicacion.con-logisession/certs/certificate.pem +32 -0
- package/test-aplicacion.con-logisession/certs/private-key-2048.pem +28 -0
- package/test-aplicacion.con-logisession/certs/private-key.pem +52 -0
- package/test-aplicacion.con-logisession/config/iaQueueSetup.js +84 -0
- package/test-aplicacion.con-logisession/config/qwen-rules.json +39 -0
- package/test-aplicacion.con-logisession/controllers/analyticsController.js +117 -0
- package/test-aplicacion.con-logisession/controllers/auth/AdminAuthController.js +142 -0
- package/test-aplicacion.con-logisession/controllers/auth/AuthController.js +439 -0
- package/test-aplicacion.con-logisession/controllers/auth/AuthViewController.js +223 -0
- package/test-aplicacion.con-logisession/controllers/endpointController.js +66 -0
- package/test-aplicacion.con-logisession/controllers/example.js +183 -0
- package/test-aplicacion.con-logisession/controllers/iaQueueController.js +367 -0
- package/test-aplicacion.con-logisession/controllers/queueController.js +206 -0
- package/test-aplicacion.con-logisession/controllers/qwenQueueController.js +197 -0
- package/test-aplicacion.con-logisession/controllers/test.js +0 -0
- package/test-aplicacion.con-logisession/controllers/tracking/EventsNoFinishController.js +78 -0
- package/test-aplicacion.con-logisession/controllers/tracking/TrackingController.js +412 -0
- package/test-aplicacion.con-logisession/controllers/tracking/TrackingControllerWithLoadModel.js +437 -0
- package/test-aplicacion.con-logisession/hooks/admin-hooks.js +20 -0
- package/test-aplicacion.con-logisession/hooks/general-hooks.js +97 -0
- package/test-aplicacion.con-logisession/hooks/queue-hooks.js +64 -0
- package/test-aplicacion.con-logisession/hooks/route-directory-hooks.js +38 -0
- package/test-aplicacion.con-logisession/hooks/security-hooks.js +24 -0
- package/test-aplicacion.con-logisession/insitu-admin-client/README.md +69 -0
- package/test-aplicacion.con-logisession/insitu-admin-client/package.json +23 -0
- package/test-aplicacion.con-logisession/insitu-admin-client.js +257 -0
- package/test-aplicacion.con-logisession/models/ExampleModel.js +88 -0
- package/test-aplicacion.con-logisession/models/QueueJobModel.js +263 -0
- package/test-aplicacion.con-logisession/models/TokenModel.js +207 -0
- package/test-aplicacion.con-logisession/models/auth/AuthModel.js +66 -0
- package/test-aplicacion.con-logisession/models/auth/UserModel.js +189 -0
- package/test-aplicacion.con-logisession/models/tracking/CompletedCartModel.js +213 -0
- package/test-aplicacion.con-logisession/models/tracking/EventModel.js +366 -0
- package/test-aplicacion.con-logisession/models/tracking/EventsNoFinishModel.js +131 -0
- package/test-aplicacion.con-logisession/models/tracking/SessionModel.js +360 -0
- package/test-aplicacion.con-logisession/models/tracking/SiteFlowModel.js +286 -0
- package/test-aplicacion.con-logisession/models/tracking/TokenModel.js +207 -0
- package/test-aplicacion.con-logisession/package-lock.json +3313 -0
- package/test-aplicacion.con-logisession/package.json +32 -0
- package/test-aplicacion.con-logisession/public/blackcoffee-welcome/index.html +1339 -0
- package/test-aplicacion.con-logisession/public/css/style.css +64 -0
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/index.html +18 -0
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/script.js +16 -0
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/styles.css +43 -0
- package/test-aplicacion.con-logisession/public/images/logo.svg +7 -0
- package/test-aplicacion.con-logisession/public/js/main.js +67 -0
- package/test-aplicacion.con-logisession/routes/analytics-routes.json +8 -0
- package/test-aplicacion.con-logisession/routes/auth-routes.json +98 -0
- package/test-aplicacion.con-logisession/routes/blackcoffee-welcome-routes.json +20 -0
- package/test-aplicacion.con-logisession/routes/duplicate-test-routes.json.disabled +16 -0
- package/test-aplicacion.con-logisession/routes/ejemplo-estatica-routes.json +11 -0
- package/test-aplicacion.con-logisession/routes/endpoints-routes.json +8 -0
- package/test-aplicacion.con-logisession/routes/ia-queue-routes.json +26 -0
- package/test-aplicacion.con-logisession/routes/product-routes.json.disabled +20 -0
- package/test-aplicacion.con-logisession/routes/queue-routes.json +32 -0
- package/test-aplicacion.con-logisession/routes/qwen-routes.json +14 -0
- package/test-aplicacion.con-logisession/routes/static-routes.json +29 -0
- package/test-aplicacion.con-logisession/routes/tracking-routes.json +58 -0
- package/test-aplicacion.con-logisession/routes/tracking-with-loadmodel-routes.json +51 -0
- package/test-aplicacion.con-logisession/utils/dbAdapter.js +88 -0
- package/test-aplicacion.con-logisession/utils/qbWrapper.js +4 -0
- package/test-aplicacion.con-logisession/utils/queueProcessor.js +305 -0
- package/test-aplicacion.con-logisession/utils/qwenRulesService.js +131 -0
- package/test-aplicacion.con-logisession/utils/tokenHelper.js +22 -0
- package/test-aplicacion.con-logisession/views/auth/dashboard.html +443 -0
- package/test-aplicacion.con-logisession/views/auth/forgot-password.html +200 -0
- package/test-aplicacion.con-logisession/views/auth/login.html +213 -0
- package/test-aplicacion.con-logisession/views/auth/register.html +294 -0
- package/test-aplicacion.con-logisession/views/contact/form.html +47 -0
- 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
|
+
};
|