blackcoffee2 2.1.0 → 2.1.2
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/.env.example +67 -0
- package/CHANGELOG.md +167 -0
- package/README.md +1 -3
- package/config/database.json +11 -0
- package/controllers/admin/AuthController.js +2 -1
- package/core/ViewHelper.js +75 -0
- package/core/hotReload.js +1 -1
- package/data/blackcoffee_admin.db-shm +0 -0
- package/data/blackcoffee_admin.db-wal +0 -0
- package/includes/adminAuth.js +5 -3
- package/includes/sessions.js +1 -1
- package/otrack.tar.gz +0 -0
- package/package.json +4 -2
- package/programatically/initFlow.js +2 -2
- package/test-aplicacion.con-logisession/BlackCoffee.js +0 -226
- package/test-aplicacion.con-logisession/SSL_SETUP.md +0 -53
- package/test-aplicacion.con-logisession/certs/ca-certificate.pem +0 -32
- package/test-aplicacion.con-logisession/certs/ca-private-key.pem +0 -52
- package/test-aplicacion.con-logisession/certs/certificate-2048.pem +0 -22
- package/test-aplicacion.con-logisession/certs/certificate.pem +0 -32
- package/test-aplicacion.con-logisession/certs/private-key-2048.pem +0 -28
- package/test-aplicacion.con-logisession/certs/private-key.pem +0 -52
- package/test-aplicacion.con-logisession/config/iaQueueSetup.js +0 -84
- package/test-aplicacion.con-logisession/config/qwen-rules.json +0 -39
- package/test-aplicacion.con-logisession/controllers/analyticsController.js +0 -117
- package/test-aplicacion.con-logisession/controllers/auth/AdminAuthController.js +0 -142
- package/test-aplicacion.con-logisession/controllers/auth/AuthController.js +0 -439
- package/test-aplicacion.con-logisession/controllers/auth/AuthViewController.js +0 -223
- package/test-aplicacion.con-logisession/controllers/endpointController.js +0 -66
- package/test-aplicacion.con-logisession/controllers/example.js +0 -183
- package/test-aplicacion.con-logisession/controllers/iaQueueController.js +0 -367
- package/test-aplicacion.con-logisession/controllers/queueController.js +0 -206
- package/test-aplicacion.con-logisession/controllers/qwenQueueController.js +0 -197
- package/test-aplicacion.con-logisession/controllers/test.js +0 -0
- package/test-aplicacion.con-logisession/controllers/tracking/EventsNoFinishController.js +0 -78
- package/test-aplicacion.con-logisession/controllers/tracking/TrackingController.js +0 -412
- package/test-aplicacion.con-logisession/controllers/tracking/TrackingControllerWithLoadModel.js +0 -437
- package/test-aplicacion.con-logisession/hooks/admin-hooks.js +0 -20
- package/test-aplicacion.con-logisession/hooks/general-hooks.js +0 -97
- package/test-aplicacion.con-logisession/hooks/queue-hooks.js +0 -64
- package/test-aplicacion.con-logisession/hooks/route-directory-hooks.js +0 -38
- package/test-aplicacion.con-logisession/hooks/security-hooks.js +0 -24
- package/test-aplicacion.con-logisession/insitu-admin-client/README.md +0 -69
- package/test-aplicacion.con-logisession/insitu-admin-client/package.json +0 -23
- package/test-aplicacion.con-logisession/insitu-admin-client.js +0 -257
- package/test-aplicacion.con-logisession/models/ExampleModel.js +0 -88
- package/test-aplicacion.con-logisession/models/QueueJobModel.js +0 -263
- package/test-aplicacion.con-logisession/models/TokenModel.js +0 -207
- package/test-aplicacion.con-logisession/models/auth/AuthModel.js +0 -66
- package/test-aplicacion.con-logisession/models/auth/UserModel.js +0 -189
- package/test-aplicacion.con-logisession/models/tracking/CompletedCartModel.js +0 -213
- package/test-aplicacion.con-logisession/models/tracking/EventModel.js +0 -366
- package/test-aplicacion.con-logisession/models/tracking/EventsNoFinishModel.js +0 -131
- package/test-aplicacion.con-logisession/models/tracking/SessionModel.js +0 -360
- package/test-aplicacion.con-logisession/models/tracking/SiteFlowModel.js +0 -286
- package/test-aplicacion.con-logisession/models/tracking/TokenModel.js +0 -207
- package/test-aplicacion.con-logisession/package-lock.json +0 -3313
- package/test-aplicacion.con-logisession/package.json +0 -32
- package/test-aplicacion.con-logisession/public/blackcoffee-welcome/index.html +0 -1339
- package/test-aplicacion.con-logisession/public/css/style.css +0 -64
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/index.html +0 -18
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/script.js +0 -16
- package/test-aplicacion.con-logisession/public/ejemplo-estatica/styles.css +0 -43
- package/test-aplicacion.con-logisession/public/images/logo.svg +0 -7
- package/test-aplicacion.con-logisession/public/js/main.js +0 -67
- package/test-aplicacion.con-logisession/routes/analytics-routes.json +0 -8
- package/test-aplicacion.con-logisession/routes/auth-routes.json +0 -98
- package/test-aplicacion.con-logisession/routes/blackcoffee-welcome-routes.json +0 -20
- package/test-aplicacion.con-logisession/routes/duplicate-test-routes.json.disabled +0 -16
- package/test-aplicacion.con-logisession/routes/ejemplo-estatica-routes.json +0 -11
- package/test-aplicacion.con-logisession/routes/endpoints-routes.json +0 -8
- package/test-aplicacion.con-logisession/routes/ia-queue-routes.json +0 -26
- package/test-aplicacion.con-logisession/routes/product-routes.json.disabled +0 -20
- package/test-aplicacion.con-logisession/routes/queue-routes.json +0 -32
- package/test-aplicacion.con-logisession/routes/qwen-routes.json +0 -14
- package/test-aplicacion.con-logisession/routes/static-routes.json +0 -29
- package/test-aplicacion.con-logisession/routes/tracking-routes.json +0 -58
- package/test-aplicacion.con-logisession/routes/tracking-with-loadmodel-routes.json +0 -51
- package/test-aplicacion.con-logisession/utils/dbAdapter.js +0 -88
- package/test-aplicacion.con-logisession/utils/qbWrapper.js +0 -4
- package/test-aplicacion.con-logisession/utils/queueProcessor.js +0 -305
- package/test-aplicacion.con-logisession/utils/qwenRulesService.js +0 -131
- package/test-aplicacion.con-logisession/utils/tokenHelper.js +0 -22
- package/test-aplicacion.con-logisession/views/auth/dashboard.html +0 -443
- package/test-aplicacion.con-logisession/views/auth/forgot-password.html +0 -200
- package/test-aplicacion.con-logisession/views/auth/login.html +0 -213
- package/test-aplicacion.con-logisession/views/auth/register.html +0 -294
- package/test-aplicacion.con-logisession/views/contact/form.html +0 -47
- package/test-aplicacion.con-logisession/views/products/index.html +0 -39
package/.env.example
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# ============================================
|
|
2
|
+
# BlackCoffee - Variables de Entorno
|
|
3
|
+
# ============================================
|
|
4
|
+
# Copia este archivo a .env y ajusta los valores
|
|
5
|
+
# cp .env.example .env
|
|
6
|
+
|
|
7
|
+
# ============================================
|
|
8
|
+
# Servidor
|
|
9
|
+
# ============================================
|
|
10
|
+
PORT=9791
|
|
11
|
+
HOST=localhost
|
|
12
|
+
|
|
13
|
+
# ============================================
|
|
14
|
+
# HTTPS / SSL
|
|
15
|
+
# ============================================
|
|
16
|
+
SSL_KEY=key-2048.pem
|
|
17
|
+
SSL_CERT=cert-2048.pem
|
|
18
|
+
|
|
19
|
+
# ============================================
|
|
20
|
+
# Sesiones - Core BlackCoffee
|
|
21
|
+
# ============================================
|
|
22
|
+
# Nombre de la cookie de sesión
|
|
23
|
+
SESSION_COOKIE_NAME=blackcoffee_session
|
|
24
|
+
|
|
25
|
+
# Secret para firmar las sesiones (CAMBIAR EN PRODUCCIÓN)
|
|
26
|
+
SESSION_SECRET=cambia-esto-en-produccion-12345
|
|
27
|
+
|
|
28
|
+
# Timeout de sesión en milisegundos (default: 3600000 = 1 hora)
|
|
29
|
+
SESSION_TIMEOUT=3600000
|
|
30
|
+
|
|
31
|
+
# ============================================
|
|
32
|
+
# Sesiones - Admin Dashboard
|
|
33
|
+
# ============================================
|
|
34
|
+
# Nombre de la cookie para el admin (opcional, usa SESSION_COOKIE_NAME si no se define)
|
|
35
|
+
ADMIN_COOKIE_NAME=blackcoffee_admin_session
|
|
36
|
+
|
|
37
|
+
# Secret para sesiones del admin (opcional, usa SESSION_SECRET si no se define)
|
|
38
|
+
ADMIN_SESSION_SECRET=admin-secreto-cambiar-en-produccion-67890
|
|
39
|
+
|
|
40
|
+
# ============================================
|
|
41
|
+
# Consola Administrativa TCP
|
|
42
|
+
# ============================================
|
|
43
|
+
ADMIN_PORT=9999
|
|
44
|
+
ADMIN_HOST=127.0.0.1
|
|
45
|
+
|
|
46
|
+
# ============================================
|
|
47
|
+
# Hot Reload
|
|
48
|
+
# ============================================
|
|
49
|
+
HOT_RELOAD=true
|
|
50
|
+
|
|
51
|
+
# ============================================
|
|
52
|
+
# Database Pool Manager
|
|
53
|
+
# ============================================
|
|
54
|
+
DB_AUTO_CONNECT=true
|
|
55
|
+
|
|
56
|
+
# ============================================
|
|
57
|
+
# WAF (Web Application Firewall)
|
|
58
|
+
# ============================================
|
|
59
|
+
WAF_ENABLED=true
|
|
60
|
+
WAF_MAX_ATTEMPTS=5
|
|
61
|
+
WAF_BLOCK_DURATION=900000
|
|
62
|
+
|
|
63
|
+
# ============================================
|
|
64
|
+
# Logging
|
|
65
|
+
# ============================================
|
|
66
|
+
LOG_LEVEL=info
|
|
67
|
+
LOG_FILE=debug.log
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,173 @@ All notable changes to BlackCoffee will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.2] - 2026-02-18
|
|
9
|
+
|
|
10
|
+
### 🔧 Variables de Entorno para Sesiones
|
|
11
|
+
|
|
12
|
+
#### Added
|
|
13
|
+
- **Configuración mediante variables de entorno** para sesiones de BlackCoffee
|
|
14
|
+
- `SESSION_COOKIE_NAME` - Nombre personalizado de la cookie
|
|
15
|
+
- `SESSION_SECRET` - Secret para firmar sesiones
|
|
16
|
+
- `SESSION_TIMEOUT` - Timeout de sesión en milisegundos
|
|
17
|
+
- `ADMIN_COOKIE_NAME` - Nombre de cookie para admin dashboard
|
|
18
|
+
- `ADMIN_SESSION_SECRET` - Secret para sesiones del admin
|
|
19
|
+
|
|
20
|
+
- **Archivo `.env.example`** - Plantilla de referencia con todas las variables
|
|
21
|
+
|
|
22
|
+
#### Changed
|
|
23
|
+
- **`includes/sessions.js`** - Ahora soporta `SESSION_COOKIE_NAME` y `SESSION_TIMEOUT` desde ENV
|
|
24
|
+
- **`programatically/initFlow.js`** - Soporta todas las variables de sesión
|
|
25
|
+
- **`includes/adminAuth.js`** - Soporta `ADMIN_COOKIE_NAME` y `ADMIN_SESSION_SECRET`
|
|
26
|
+
- **`controllers/admin/AuthController.js`** - Usa `ADMIN_COOKIE_NAME` dinámico en logout
|
|
27
|
+
|
|
28
|
+
#### Security
|
|
29
|
+
- ✅ Secrets configurables desde entorno (no hardcodeados)
|
|
30
|
+
- ✅ Nombres de cookies personalizables
|
|
31
|
+
- ✅ Cada aplicación puede tener sus propias variables
|
|
32
|
+
|
|
33
|
+
#### Usage
|
|
34
|
+
```bash
|
|
35
|
+
# Variables disponibles
|
|
36
|
+
export SESSION_COOKIE_NAME="mi_app_session"
|
|
37
|
+
export SESSION_SECRET="mi-secreto-super-seguro"
|
|
38
|
+
export SESSION_TIMEOUT=7200000 # 2 horas
|
|
39
|
+
export ADMIN_COOKIE_NAME="admin_area_session"
|
|
40
|
+
export ADMIN_SESSION_SECRET="admin-secreto-12345"
|
|
41
|
+
|
|
42
|
+
# Iniciar servidor
|
|
43
|
+
node server.js
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Files Modified
|
|
47
|
+
- `includes/sessions.js` - Agregado soporte para `SESSION_COOKIE_NAME` y `SESSION_TIMEOUT`
|
|
48
|
+
- `programatically/initFlow.js` - Agregado soporte para variables de entorno
|
|
49
|
+
- `includes/adminAuth.js` - Agregado `ADMIN_COOKIE_NAME` y `ADMIN_SESSION_SECRET`
|
|
50
|
+
- `controllers/admin/AuthController.js` - Logout usa cookie name dinámica
|
|
51
|
+
- `.env.example` - Nuevo archivo con plantilla de variables
|
|
52
|
+
|
|
53
|
+
#### Default Values
|
|
54
|
+
| Variable | Default | Descripción |
|
|
55
|
+
|----------|---------|-------------|
|
|
56
|
+
| `SESSION_COOKIE_NAME` | `blackcoffee_session` | Cookie de sesión core |
|
|
57
|
+
| `SESSION_SECRET` | `blackcoffee-secret...` | Secret para sesiones |
|
|
58
|
+
| `SESSION_TIMEOUT` | `3600000` (1 hora) | Timeout en ms |
|
|
59
|
+
| `ADMIN_COOKIE_NAME` | `blackcoffee_admin_session` | Cookie del admin |
|
|
60
|
+
| `ADMIN_SESSION_SECRET` | `SESSION_SECRET` | Secret del admin |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## [2.1.1] - 2026-02-18
|
|
65
|
+
|
|
66
|
+
### 🎯 OTrack Application - Sistema de Tracking con EJS
|
|
67
|
+
|
|
68
|
+
#### Added
|
|
69
|
+
- **Aplicación OTrack completa** (`apps/otrack/1-0-0/`)
|
|
70
|
+
- Sistema de gestión de usuarios con CRUD completo
|
|
71
|
+
- Autenticación JWT con tokens almacenados en MariaDB
|
|
72
|
+
- Vistas con **EJS Template Engine**
|
|
73
|
+
- Pool de base de datos independiente `otrack-db`
|
|
74
|
+
|
|
75
|
+
- **Modelos de Datos**
|
|
76
|
+
- `UserModel` - Gestión de usuarios con bcryptjs para hash de contraseñas
|
|
77
|
+
- `JwtTokenModel` - Tokens JWT con uuid para generación única
|
|
78
|
+
- `SessionModel` - Sesiones persistentes en base de datos
|
|
79
|
+
- Validaciones con `validator` library
|
|
80
|
+
|
|
81
|
+
- **Controladores**
|
|
82
|
+
- `OtrackController` - CRUD de usuarios y vistas dashboard/users
|
|
83
|
+
- `AuthController` - Login, logout, registro con sesiones en BD
|
|
84
|
+
|
|
85
|
+
- **Middleware Independiente** (`middleware/OtrackAuth.js`)
|
|
86
|
+
- Autenticación por cookie `otrack_session_token`
|
|
87
|
+
- Verificación de sesiones en base de datos
|
|
88
|
+
- Soporte para JWT tokens
|
|
89
|
+
- **Aislamiento total** de sesiones de BlackCoffee admin
|
|
90
|
+
|
|
91
|
+
- **Vistas EJS**
|
|
92
|
+
- `login.ejs` - Formulario de login con registro
|
|
93
|
+
- `dashboard.ejs` - Dashboard con estadísticas
|
|
94
|
+
- `users.ejs` - Manager de usuarios con modal CRUD
|
|
95
|
+
- `index.ejs` - Landing page
|
|
96
|
+
|
|
97
|
+
- **ViewHelper con EJS** (`core/ViewHelper.js`)
|
|
98
|
+
- Motor de plantillas EJS independiente
|
|
99
|
+
- Soporte para `.ejs` y `.html`
|
|
100
|
+
- Renderizado desde aplicaciones sin modificar el core
|
|
101
|
+
|
|
102
|
+
- **Hot Reload para OTrack**
|
|
103
|
+
- Detección automática de cambios en controllers/models/views
|
|
104
|
+
- Recarga sin reiniciar servidor
|
|
105
|
+
|
|
106
|
+
#### Changed
|
|
107
|
+
- **Sesiones Independientes** - OTrack usa su propia BD y cookies
|
|
108
|
+
- Cookie: `otrack_session_token` (diferente de `blackcoffee_admin_session`)
|
|
109
|
+
- BD: MariaDB `tracking.sessions` (diferente de SQLite admin)
|
|
110
|
+
- **Sin cruce de sesiones** entre aplicaciones
|
|
111
|
+
|
|
112
|
+
- **Formato de versión BSD** - `1-0-0` en lugar de `1.0.0`
|
|
113
|
+
- Evita problemas con ViewEngine y puntos en rutas
|
|
114
|
+
|
|
115
|
+
- **UserModel actualizado**
|
|
116
|
+
- Método `getById()` agregado
|
|
117
|
+
- bcryptjs para hash de contraseñas
|
|
118
|
+
- validator para emails y usernames
|
|
119
|
+
|
|
120
|
+
#### Security
|
|
121
|
+
- ✅ Contraseñas con bcryptjs (salt rounds: 10)
|
|
122
|
+
- ✅ Tokens UUID v4 únicos por sesión
|
|
123
|
+
- ✅ Cookies HttpOnly con SameSite=Lax
|
|
124
|
+
- ✅ Verificación de sesiones en base de datos
|
|
125
|
+
- ✅ Aislamiento de sesiones entre aplicaciones
|
|
126
|
+
|
|
127
|
+
#### Files Added
|
|
128
|
+
- `apps/otrack/1-0-0/manifest.json`
|
|
129
|
+
- `apps/otrack/1-0-0/package.json` (con dependencias propias)
|
|
130
|
+
- `apps/otrack/1-0-0/controllers/OtrackController.js`
|
|
131
|
+
- `apps/otrack/1-0-0/controllers/AuthController.js`
|
|
132
|
+
- `apps/otrack/1-0-0/models/UserModel.js`
|
|
133
|
+
- `apps/otrack/1-0-0/models/JwtTokenModel.js`
|
|
134
|
+
- `apps/otrack/1-0-0/models/SessionModel.js`
|
|
135
|
+
- `apps/otrack/1-0-0/middleware/OtrackAuth.js`
|
|
136
|
+
- `apps/otrack/1-0-0/views/otrack/*.ejs` (4 vistas)
|
|
137
|
+
- `apps/otrack/1-0-0/routes/static.json`
|
|
138
|
+
- `apps/otrack/1-0-0/scripts/init-db.sql`
|
|
139
|
+
- `core/ViewHelper.js`
|
|
140
|
+
|
|
141
|
+
#### Files Modified
|
|
142
|
+
- `config/database.json` - Agregado pool `otrack-db`
|
|
143
|
+
- `core/hotReload.js` - Fix: `manifestPath` no estaba definido
|
|
144
|
+
|
|
145
|
+
#### Dependencies (OTrack)
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"uuid": "^9.0.0",
|
|
149
|
+
"validator": "^13.11.0",
|
|
150
|
+
"bcryptjs": "^2.4.3",
|
|
151
|
+
"ejs": "^3.1.x"
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### Endpoints
|
|
156
|
+
| Método | Endpoint | Descripción |
|
|
157
|
+
|--------|----------|-------------|
|
|
158
|
+
| GET | `/otrack/1-0-0/` | Landing page |
|
|
159
|
+
| GET | `/otrack/1-0-0/dashboard` | Dashboard (protegido) |
|
|
160
|
+
| GET | `/otrack/1-0-0/users/view` | Users Manager (protegido) |
|
|
161
|
+
| GET | `/otrack/1-0-0/users` | API lista de usuarios |
|
|
162
|
+
| POST | `/otrack/1-0-0/users` | API crear usuario |
|
|
163
|
+
| PUT | `/otrack/1-0-0/users/:id` | API actualizar usuario |
|
|
164
|
+
| DELETE | `/otrack/1-0-0/users/:id` | API eliminar usuario |
|
|
165
|
+
| POST | `/otrack/1-0-0/auth/login` | Login |
|
|
166
|
+
| POST | `/otrack/1-0-0/auth/logout` | Logout |
|
|
167
|
+
| POST | `/otrack/1-0-0/auth/register` | Registro |
|
|
168
|
+
|
|
169
|
+
#### Default Credentials
|
|
170
|
+
- **Username:** `admin` | **Password:** `admin123`
|
|
171
|
+
- **Username:** `testuser` | **Password:** `user123`
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
8
175
|
## [2.1.0] - 2026-02-18
|
|
9
176
|
|
|
10
177
|
### 🔐 Sistema de Autenticación para Dashboard Admin
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ☕ BlackCoffee v2.
|
|
1
|
+
# ☕ BlackCoffee v2.1.x - App Server
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|

|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
**✅ Fases 0-5 COMPLETADAS** - App Server funcional con Database Pools y Hot Reload.
|
|
10
|
-
|
|
11
9
|
---
|
|
12
10
|
|
|
13
11
|
## 🎯 ¿Qué es BlackCoffee?
|
package/config/database.json
CHANGED
|
@@ -23,6 +23,17 @@
|
|
|
23
23
|
"password": "",
|
|
24
24
|
"database": "otrack_db",
|
|
25
25
|
"connectionLimit": 10
|
|
26
|
+
},
|
|
27
|
+
"otrack-db": {
|
|
28
|
+
"type": "mariadb",
|
|
29
|
+
"connected": false,
|
|
30
|
+
"host": "localhost",
|
|
31
|
+
"port": 3306,
|
|
32
|
+
"user": "root",
|
|
33
|
+
"password": "",
|
|
34
|
+
"database": "tracking",
|
|
35
|
+
"connectionLimit": 10,
|
|
36
|
+
"timezone": "Z"
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
}
|
|
@@ -104,7 +104,8 @@ class AuthController {
|
|
|
104
104
|
static async logout(req, res) {
|
|
105
105
|
try {
|
|
106
106
|
// Limpiar cookie de sesión
|
|
107
|
-
|
|
107
|
+
const cookieName = process.env.ADMIN_COOKIE_NAME || 'blackcoffee_admin_session';
|
|
108
|
+
res.setHeader('Set-Cookie', `${cookieName}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly`);
|
|
108
109
|
|
|
109
110
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
110
111
|
res.end(JSON.stringify({
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewHelper - Helper de BlackCoffee para renderizado de vistas
|
|
3
|
+
* Usa EJS como motor de plantillas
|
|
4
|
+
*
|
|
5
|
+
* Proporciona un método render personalizado que funciona con la estructura
|
|
6
|
+
* de aplicaciones de BlackCoffee (apps/{name}/{version}/views/)
|
|
7
|
+
*
|
|
8
|
+
* Uso en controladores:
|
|
9
|
+
* const ViewHelper = require('../../core/ViewHelper');
|
|
10
|
+
* ViewHelper.render(res, 'otrack/1-0-0/views/otrack/index', data);
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const ejs = require('ejs');
|
|
16
|
+
|
|
17
|
+
class ViewHelper {
|
|
18
|
+
/**
|
|
19
|
+
* Renderiza una vista con datos usando EJS
|
|
20
|
+
* @param {Object} res - Response object
|
|
21
|
+
* @param {string} viewPath - Ruta de la vista relativa a apps/
|
|
22
|
+
* @param {Object} data - Datos para pasar a la vista
|
|
23
|
+
* @param {number} statusCode - Código de estado HTTP (default: 200)
|
|
24
|
+
*/
|
|
25
|
+
static render(res, viewPath, data = {}, statusCode = 200) {
|
|
26
|
+
try {
|
|
27
|
+
// Construir ruta completa: apps/{viewPath}.ejs o .html
|
|
28
|
+
const appsDir = path.join(__dirname, '..', 'apps');
|
|
29
|
+
|
|
30
|
+
// Intentar con extensión .ejs primero, luego .html
|
|
31
|
+
let fullPath = path.join(appsDir, `${viewPath}.ejs`);
|
|
32
|
+
if (!fs.existsSync(fullPath)) {
|
|
33
|
+
fullPath = path.join(appsDir, `${viewPath}.html`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Verificar si la vista existe
|
|
37
|
+
if (!fs.existsSync(fullPath)) {
|
|
38
|
+
throw new Error(`Vista no encontrada: ${fullPath}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Leer el contenido de la vista
|
|
42
|
+
const template = fs.readFileSync(fullPath, 'utf8');
|
|
43
|
+
|
|
44
|
+
// Renderizar con EJS
|
|
45
|
+
const renderedHtml = ejs.render(template, data, {
|
|
46
|
+
filename: fullPath,
|
|
47
|
+
root: appsDir
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Enviar respuesta
|
|
51
|
+
res.writeHead(statusCode, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
52
|
+
res.end(renderedHtml);
|
|
53
|
+
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(`[ViewHelper] Error renderizando ${viewPath}:`, error.message);
|
|
56
|
+
|
|
57
|
+
// Enviar página de error
|
|
58
|
+
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
59
|
+
res.end(`
|
|
60
|
+
<!DOCTYPE html>
|
|
61
|
+
<html>
|
|
62
|
+
<head><title>Error - ViewHelper</title></head>
|
|
63
|
+
<body style="font-family: monospace; padding: 2rem; background: #1a1a2e; color: #fff;">
|
|
64
|
+
<h1 style="color: #ff5252;">❌ Error de Vista</h1>
|
|
65
|
+
<p><strong>Vista:</strong> ${viewPath}</p>
|
|
66
|
+
<p><strong>Error:</strong> ${error.message}</p>
|
|
67
|
+
<pre style="background: rgba(0,0,0,0.3); padding: 1rem; border-radius: 5px; overflow-x: auto;">${error.stack}</pre>
|
|
68
|
+
</body>
|
|
69
|
+
</html>
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = ViewHelper;
|
package/core/hotReload.js
CHANGED
|
@@ -219,7 +219,7 @@ class HotReloadManager {
|
|
|
219
219
|
|
|
220
220
|
const appsDir = path.join(__dirname, '..', 'apps');
|
|
221
221
|
const appPath = path.join(appsDir, appName, version);
|
|
222
|
-
const
|
|
222
|
+
const manifestPath = path.join(appPath, 'manifest.json');
|
|
223
223
|
|
|
224
224
|
try {
|
|
225
225
|
// 1. Limpiar caché de módulos de la app
|
|
Binary file
|
|
Binary file
|
package/includes/adminAuth.js
CHANGED
|
@@ -99,8 +99,8 @@ function authMiddleware() {
|
|
|
99
99
|
*/
|
|
100
100
|
async function initAdminAuth(server) {
|
|
101
101
|
const config = {
|
|
102
|
-
cookieName: 'blackcoffee_admin_session',
|
|
103
|
-
secret: process.env.SESSION_SECRET || 'blackcoffee-session-secret-change-in-production',
|
|
102
|
+
cookieName: process.env.ADMIN_COOKIE_NAME || 'blackcoffee_admin_session',
|
|
103
|
+
secret: process.env.ADMIN_SESSION_SECRET || process.env.SESSION_SECRET || 'blackcoffee-admin-session-secret-change-in-production',
|
|
104
104
|
timeout: 3600000, // 1 hora
|
|
105
105
|
secure: false, // Cambiar a true en producción con HTTPS
|
|
106
106
|
httpOnly: true,
|
|
@@ -114,9 +114,11 @@ async function initAdminAuth(server) {
|
|
|
114
114
|
|
|
115
115
|
// Registrar middleware de sesión PRIMERO
|
|
116
116
|
server.use(sessionManager.middleware());
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
server.sessionManager = sessionManager;
|
|
119
119
|
console.log('🔐 Session Manager inicializado\n');
|
|
120
|
+
console.log(` Cookie: ${config.cookieName}`);
|
|
121
|
+
console.log(` Secret: ${config.secret.substring(0, 10)}...\n`);
|
|
120
122
|
|
|
121
123
|
// ============================================
|
|
122
124
|
// Rutas estáticas para CSS y JS (ANTES del middleware de auth)
|
package/includes/sessions.js
CHANGED
|
@@ -26,7 +26,7 @@ function init(server, options = {}) {
|
|
|
26
26
|
|
|
27
27
|
// Configuración por defecto
|
|
28
28
|
const config = {
|
|
29
|
-
cookieName: options.cookieName || 'blackcoffee_session',
|
|
29
|
+
cookieName: options.cookieName || process.env.SESSION_COOKIE_NAME || 'blackcoffee_session',
|
|
30
30
|
secret: options.secret || process.env.SESSION_SECRET || 'blackcoffee-secret-change-in-production',
|
|
31
31
|
timeout: options.timeout || parseInt(process.env.SESSION_TIMEOUT, 10) || 3600000, // 1 hora
|
|
32
32
|
...options
|
package/otrack.tar.gz
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blackcoffee2",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "A app server built with Insitu Framework",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"author": "Benjamin Sanchez Cardenas <bytedogssyndicate@gmail.com>",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"better-sqlite3": "^12.6.2",
|
|
24
24
|
"chokidar": "^5.0.0",
|
|
25
|
+
"ejs": "^4.0.1",
|
|
25
26
|
"gtk3-node": "^1.3.0",
|
|
26
27
|
"insitu-js": "^1.3.0"
|
|
27
28
|
},
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"backend",
|
|
41
42
|
"framework",
|
|
42
43
|
"microservices",
|
|
43
|
-
"api-server"
|
|
44
|
+
"api-server",
|
|
45
|
+
"mvc"
|
|
44
46
|
]
|
|
45
47
|
}
|
|
@@ -29,8 +29,8 @@ function register(server) {
|
|
|
29
29
|
console.log('📦 Componente: Sesiones');
|
|
30
30
|
const sessions = require('../includes/sessions');
|
|
31
31
|
sessions.init(server, {
|
|
32
|
-
cookieName: 'blackcoffee_session',
|
|
33
|
-
timeout: 3600000, // 1 hora
|
|
32
|
+
cookieName: process.env.SESSION_COOKIE_NAME || 'blackcoffee_session',
|
|
33
|
+
timeout: parseInt(process.env.SESSION_TIMEOUT, 10) || 3600000, // 1 hora
|
|
34
34
|
secret: process.env.SESSION_SECRET || 'cambia-esto-en-produccion'
|
|
35
35
|
});
|
|
36
36
|
console.log('');
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
#!/bin/node
|
|
2
|
-
/**
|
|
3
|
-
* Aplicación BlackCoffee con insitu-js
|
|
4
|
-
* Servidor backend para construir aplicaciones web
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Cargar variables de entorno desde archivo .env
|
|
8
|
-
require('dotenv').config();
|
|
9
|
-
|
|
10
|
-
const jerk = require('insitu-js');
|
|
11
|
-
const {
|
|
12
|
-
APIServer,
|
|
13
|
-
Logger,
|
|
14
|
-
RouteLoader,
|
|
15
|
-
RouteDirectoryLoader,
|
|
16
|
-
Firewall, // Importar el Firewall
|
|
17
|
-
hooks
|
|
18
|
-
} = jerk;
|
|
19
|
-
|
|
20
|
-
// Importar los módulos de hooks
|
|
21
|
-
const { registerGeneralHooks } = require('./hooks/general-hooks');
|
|
22
|
-
const { registerSecurityHooks } = require('./hooks/security-hooks');
|
|
23
|
-
const { registerQueueHooks } = require('./hooks/queue-hooks');
|
|
24
|
-
const { registerRouteDirectoryHooks } = require('./hooks/route-directory-hooks');
|
|
25
|
-
const { registerAdminHooks } = require('./hooks/admin-hooks');
|
|
26
|
-
|
|
27
|
-
// Importar el procesador de colas
|
|
28
|
-
const { queueProcessor } = require('./utils/queueProcessor');
|
|
29
|
-
|
|
30
|
-
// Importar y configurar el sistema de colas global
|
|
31
|
-
const { QueueIntegration } = require('insitu-js');
|
|
32
|
-
const globalQueueIntegration = new QueueIntegration();
|
|
33
|
-
|
|
34
|
-
// Crear instancia del logger
|
|
35
|
-
const logger = new Logger({ level: 'debug' });
|
|
36
|
-
|
|
37
|
-
// Crear instancia del Firewall con opciones personalizadas
|
|
38
|
-
const firewall = new Firewall({
|
|
39
|
-
maxAttempts: 5, // Máximo de intentos fallidos antes de bloquear
|
|
40
|
-
blockDuration: 900000, // Duración del bloqueo en ms (15 minutos)
|
|
41
|
-
whitelist: ['127.0.0.1'], // IPs que no deben ser bloqueadas
|
|
42
|
-
blacklist: [], // IPs que siempre deben ser bloqueadas
|
|
43
|
-
logger: logger // Instancia de logger para eventos de seguridad
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Array para almacenar los controladores disponibles
|
|
47
|
-
let availableControllers = [];
|
|
48
|
-
|
|
49
|
-
// Instancia del cargador de rutas desde directorio
|
|
50
|
-
let routeDirectoryLoader = null;
|
|
51
|
-
|
|
52
|
-
// Registrar todos los hooks
|
|
53
|
-
registerGeneralHooks(hooks, logger, availableControllers);
|
|
54
|
-
registerSecurityHooks(hooks, logger);
|
|
55
|
-
registerQueueHooks(hooks, logger);
|
|
56
|
-
registerRouteDirectoryHooks(hooks, logger);
|
|
57
|
-
registerAdminHooks(hooks);
|
|
58
|
-
|
|
59
|
-
async function startApp() {
|
|
60
|
-
// Configurar opciones del servidor
|
|
61
|
-
const serverOptions = {
|
|
62
|
-
port: parseInt(process.env.PORT) || 3000,
|
|
63
|
-
host: '0.0.0.0',
|
|
64
|
-
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT) || 300000, // 5 minutos por defecto (era 2 minutos)
|
|
65
|
-
connectionTimeout: parseInt(process.env.CONNECTION_TIMEOUT) || 300000 // 5 minutos por defecto (era 2 minutos)
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Agregar soporte para SSL basado en variables de entorno
|
|
69
|
-
if (process.env.ENABLE_SSL === 'true') {
|
|
70
|
-
serverOptions.https = true;
|
|
71
|
-
|
|
72
|
-
if (process.env.SSL_KEY_PATH && process.env.SSL_CERT_PATH) {
|
|
73
|
-
serverOptions.key = process.env.SSL_KEY_PATH;
|
|
74
|
-
serverOptions.cert = process.env.SSL_CERT_PATH;
|
|
75
|
-
|
|
76
|
-
// Opcional: soporte para certificado CA
|
|
77
|
-
if (process.env.SSL_CA_PATH) {
|
|
78
|
-
serverOptions.ca = process.env.SSL_CA_PATH;
|
|
79
|
-
}
|
|
80
|
-
} else {
|
|
81
|
-
console.error('ERROR: ENABLE_SSL está activado pero faltan las variables SSL_KEY_PATH o SSL_CERT_PATH');
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Crear instancia del servidor
|
|
87
|
-
const server = new APIServer(serverOptions);
|
|
88
|
-
|
|
89
|
-
// Exponer el servidor y el sistema de colas globalmente para que otros módulos puedan acceder a ellos
|
|
90
|
-
global.apiServer = server;
|
|
91
|
-
global.queueIntegration = globalQueueIntegration;
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
// Aplicar middleware del Firewall ANTES de cualquier otro middleware
|
|
95
|
-
server.use(firewall.middleware());
|
|
96
|
-
|
|
97
|
-
// Inicializar SessionManager
|
|
98
|
-
const { SessionManager } = require('insitu-js');
|
|
99
|
-
const sessionManager = new SessionManager({
|
|
100
|
-
cookieName: 'blackcoffee_session',
|
|
101
|
-
secret: process.env.SESSION_SECRET || 'blackcoffee-session-secret-change-in-production',
|
|
102
|
-
timeout: 3600000 // 1 hora por defecto
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Aplicar middleware de sesión
|
|
106
|
-
server.use(sessionManager.middleware());
|
|
107
|
-
server.sessionManager = sessionManager;
|
|
108
|
-
|
|
109
|
-
// Middleware para capturar inicio de solicitudes
|
|
110
|
-
server.use((req, res, next) => {
|
|
111
|
-
// Disparar hook de solicitud recibida
|
|
112
|
-
hooks.doAction('request_received', req, res);
|
|
113
|
-
|
|
114
|
-
// Guardar la función original de res.end
|
|
115
|
-
const originalEnd = res.end;
|
|
116
|
-
|
|
117
|
-
// Sobrescribir res.end para capturar cuando se completa la solicitud
|
|
118
|
-
res.end = function(chunk, encoding, callback) {
|
|
119
|
-
// Llamar a la función original
|
|
120
|
-
const result = originalEnd.call(this, chunk, encoding, callback);
|
|
121
|
-
|
|
122
|
-
// Disparar hook de solicitud completada
|
|
123
|
-
hooks.doAction('request_completed', req, res);
|
|
124
|
-
|
|
125
|
-
return result;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
next();
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Determinar si se deben cargar rutas desde archivo o directorio
|
|
132
|
-
// Si la variable de entorno USE_FILE_ROUTES está definida como 'true', se usa el archivo en lugar del directorio
|
|
133
|
-
if (process.env.USE_FILE_ROUTES === 'true') {
|
|
134
|
-
// Determinar qué archivo de rutas usar basado en variables de entorno
|
|
135
|
-
// Prioridad: CUSTOM_ROUTES_PATH > USE_DEFAULT_ROUTES > routes.json por defecto
|
|
136
|
-
let routesFilePath = './routes.json'; // Valor por defecto
|
|
137
|
-
|
|
138
|
-
if (process.env.CUSTOM_ROUTES_PATH) {
|
|
139
|
-
routesFilePath = process.env.CUSTOM_ROUTES_PATH;
|
|
140
|
-
logger.info(`Usando ruta personalizada para rutas: ${routesFilePath}`);
|
|
141
|
-
} else if (process.env.USE_DEFAULT_ROUTES === 'true') {
|
|
142
|
-
routesFilePath = './routes-default.json';
|
|
143
|
-
logger.info(`Usando rutas por defecto: ${routesFilePath}`);
|
|
144
|
-
} else {
|
|
145
|
-
logger.info(`Usando rutas estándar: ${routesFilePath}`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Cargar rutas desde archivo JSON
|
|
149
|
-
const routeLoader = new RouteLoader();
|
|
150
|
-
await routeLoader.loadRoutes(server, routesFilePath);
|
|
151
|
-
} else {
|
|
152
|
-
logger.info('Usando carga de rutas desde directorio (modo predeterminado)');
|
|
153
|
-
|
|
154
|
-
// Crear instancia del cargador de rutas desde directorio
|
|
155
|
-
routeDirectoryLoader = new RouteDirectoryLoader();
|
|
156
|
-
|
|
157
|
-
// Directorio que contiene los archivos JSON de rutas
|
|
158
|
-
const routesDirectory = process.env.ROUTES_DIRECTORY || './routes';
|
|
159
|
-
logger.info(`Cargando rutas desde directorio: ${routesDirectory}`);
|
|
160
|
-
|
|
161
|
-
// Cargar rutas desde el directorio
|
|
162
|
-
const loadedRoutes = await routeDirectoryLoader.loadRoutesFromDirectory(server, routesDirectory);
|
|
163
|
-
logger.info(`${loadedRoutes.length} rutas cargadas exitosamente desde el directorio`);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Mostrar los controladores disponibles (usando hooks)
|
|
167
|
-
logger.info('\n=== CONTROLADORES DISPONIBLES ===');
|
|
168
|
-
availableControllers.forEach((controller, index) => {
|
|
169
|
-
// logger.info(`[[CONTROLLER ${index + 1}]] - Nombre: ${controller.name}`);
|
|
170
|
-
// logger.info(`[[PATH]] - Ruta: ${controller.path}`);
|
|
171
|
-
// logger.info(`[[HANDLERS]] - Funciones: ${controller.handlers.join(', ')}`);
|
|
172
|
-
// logger.info('---');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
// Iniciar el servidor
|
|
177
|
-
server.start();
|
|
178
|
-
|
|
179
|
-
// Mostrar el protocolo correcto según si está usando SSL o no
|
|
180
|
-
const protocol = (process.env.ENABLE_SSL === 'true') ? 'https' : 'http';
|
|
181
|
-
const host = process.env.HOST || 'localhost';
|
|
182
|
-
const port = process.env.PORT || '9791'; // Usar el puerto predeterminado 9791
|
|
183
|
-
logger.info(`\nServidor BlackCoffee iniciado en ${protocol}://${host}:${server.port}`);
|
|
184
|
-
logger.info('La aplicación está lista para servir peticiones web');
|
|
185
|
-
|
|
186
|
-
// Disparar hook antes de iniciar el procesador de colas
|
|
187
|
-
hooks.doAction('queue_processor_before_start');
|
|
188
|
-
|
|
189
|
-
// Iniciar el sistema de colas global
|
|
190
|
-
global.queueIntegration.start();
|
|
191
|
-
logger.info('Sistema de colas global iniciado');
|
|
192
|
-
|
|
193
|
-
// Configurar las colas de IA después de iniciar el sistema de colas
|
|
194
|
-
require('./config/iaQueueSetup.js');
|
|
195
|
-
|
|
196
|
-
// Iniciar el procesador de colas
|
|
197
|
-
queueProcessor.start();
|
|
198
|
-
logger.info('Procesador de colas iniciado');
|
|
199
|
-
|
|
200
|
-
// Disparar hook después de iniciar el procesador de colas
|
|
201
|
-
hooks.doAction('queue_processor_after_start');
|
|
202
|
-
|
|
203
|
-
} catch (error) {
|
|
204
|
-
logger.error('Error iniciando la aplicación:', error.message);
|
|
205
|
-
logger.error('Stack trace:', error.stack);
|
|
206
|
-
|
|
207
|
-
// Disparar hook antes de detener el procesador de colas en caso de error
|
|
208
|
-
hooks.doAction('queue_processor_before_stop_on_error');
|
|
209
|
-
|
|
210
|
-
// Asegurarse de detener el procesador de colas en caso de error
|
|
211
|
-
try {
|
|
212
|
-
queueProcessor.stop();
|
|
213
|
-
} catch (stopError) {
|
|
214
|
-
logger.error('Error deteniendo el procesador de colas:', stopError.message);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Disparar hook después de detener el procesador de colas en caso de error
|
|
218
|
-
hooks.doAction('queue_processor_after_stop_on_error');
|
|
219
|
-
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
startApp();
|
|
225
|
-
|
|
226
|
-
module.exports = { startApp };
|