jerkjs 2.5.6 → 2.6.1
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 +167 -79
- package/README.md +134 -146
- package/RESULTADOS_WAF.md +63 -0
- package/doc-2.5/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
- package/doc-2.5/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
- package/doc-2.5/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
- package/doc-2.5/CACHE_SYSTEM_MAP.md +206 -0
- package/doc-2.5/MANUAL_MODULOS_ADMIN.md +287 -0
- package/doc-2.5/QUEUE_CLI_MODULE_MANUAL.md +289 -0
- package/doc-2.5/QUEUE_SYSTEM_MANUAL.md +320 -0
- package/doc-2.5/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
- package/doc-2.5/WAF_MODULE_MANUAL.md +229 -0
- package/index.js +19 -4
- package/jerk-admin-client/README.md +69 -0
- package/jerk-admin-client/package.json +23 -0
- package/jerk-admin-client.js +257 -0
- package/lib/admin/AdminExtension.js +491 -0
- package/lib/admin/ModuleLoader.js +77 -0
- package/lib/admin/config.js +21 -0
- package/lib/admin/modules/CacheModule.js +145 -0
- package/lib/admin/modules/ControllerGeneratorModule.js +414 -0
- package/lib/admin/modules/QueueManagementModule.js +265 -0
- package/lib/admin/modules/RouteCacheModule.js +227 -0
- package/lib/admin/modules/RouteManagerModule.js +468 -0
- package/lib/admin/modules/STATS_MODULE_README.md +113 -0
- package/lib/admin/modules/StatsModule.js +140 -0
- package/lib/admin/modules/SystemModule.js +140 -0
- package/lib/admin/modules/TimeModule.js +95 -0
- package/lib/admin/modules/ViewCacheStatsModule.js +92 -0
- package/lib/admin/modules/WAFModule.js +737 -0
- package/lib/cache/CacheHooks.js +141 -0
- package/lib/core/server.js +223 -77
- package/lib/middleware/firewall.js +112 -17
- package/lib/mvc/viewEngine.js +89 -5
- package/lib/queue/GlobalQueueStorage.js +38 -0
- package/lib/queue/QueueSystem.js +451 -0
- package/lib/queue/admin_example.js +114 -0
- package/lib/queue/example.js +268 -0
- package/lib/queue/integration.js +109 -0
- package/lib/router/RouteMatcher.js +242 -54
- package/lib/utils/globalStats.js +16 -0
- package/lib/utils/globalViewCacheInfo.js +16 -0
- package/lib/utils/globalWAFStats.js +54 -0
- package/package.json +2 -2
- package/test-colors.js +46 -0
- package/test-help-alias.js +31 -0
|
@@ -1,31 +1,79 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Componente especializado para la lógica de enrutado
|
|
2
|
+
* Componente especializado para la lógica de enrutado optimizado
|
|
3
3
|
* Implementación del componente router/RouteMatcher.js
|
|
4
|
-
* JERK Framework v2.
|
|
4
|
+
* JERK Framework v2.5.7 - Optimización de rendimiento con índices y pre-filtrado
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
class RouteMatcher {
|
|
8
8
|
/**
|
|
9
|
-
* Constructor del matcher de rutas
|
|
9
|
+
* Constructor del matcher de rutas optimizado
|
|
10
10
|
*/
|
|
11
11
|
constructor() {
|
|
12
12
|
// Cache de expresiones regulares para rutas parametrizadas
|
|
13
13
|
this.routeRegexCache = new Map();
|
|
14
|
+
|
|
15
|
+
// Índices para optimización
|
|
16
|
+
this.exactRoutes = new Map(); // Rutas exactas indexadas por método y path
|
|
17
|
+
this.routeBuckets = {}; // Rutas organizadas por método, número de segmentos y primer segmento
|
|
18
|
+
this.indexesValid = false;
|
|
19
|
+
|
|
20
|
+
// Referencia al sistema de hooks (se establecerá externamente)
|
|
21
|
+
this.hooks = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Actualiza los índices basados en el conjunto actual de rutas
|
|
26
|
+
* @param {Array} routes - Array de rutas registradas
|
|
27
|
+
*/
|
|
28
|
+
updateIndexes(routes) {
|
|
29
|
+
// Limpiar índices existentes
|
|
30
|
+
this.exactRoutes.clear();
|
|
31
|
+
this.routeBuckets = {};
|
|
32
|
+
|
|
33
|
+
// Reconstruir índices
|
|
34
|
+
for (const route of routes) {
|
|
35
|
+
// Indexar rutas exactas
|
|
36
|
+
const methodPathKey = `${route.method}:${route.path}`;
|
|
37
|
+
this.exactRoutes.set(methodPathKey, route);
|
|
38
|
+
|
|
39
|
+
// Organizar rutas en buckets por método, número de segmentos y primer segmento
|
|
40
|
+
const segments = route.path.split('/').filter(s => s !== '');
|
|
41
|
+
const segmentCount = segments.length;
|
|
42
|
+
const firstSegment = segments.length > 0 ? segments[0] : '';
|
|
43
|
+
|
|
44
|
+
// Inicializar estructura de buckets si no existe
|
|
45
|
+
if (!this.routeBuckets[route.method]) {
|
|
46
|
+
this.routeBuckets[route.method] = {};
|
|
47
|
+
}
|
|
48
|
+
if (!this.routeBuckets[route.method][segmentCount]) {
|
|
49
|
+
this.routeBuckets[route.method][segmentCount] = {};
|
|
50
|
+
}
|
|
51
|
+
if (!this.routeBuckets[route.method][segmentCount][firstSegment]) {
|
|
52
|
+
this.routeBuckets[route.method][segmentCount][firstSegment] = [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Agregar ruta al bucket correspondiente
|
|
56
|
+
this.routeBuckets[route.method][segmentCount][firstSegment].push(route);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.indexesValid = true;
|
|
14
60
|
}
|
|
15
61
|
|
|
16
62
|
/**
|
|
17
|
-
* Método para encontrar una ruta coincidente
|
|
63
|
+
* Método para encontrar una ruta coincidente con optimizaciones
|
|
18
64
|
* @param {Array} routes - Array de rutas registradas
|
|
19
65
|
* @param {string} method - Método HTTP
|
|
20
66
|
* @param {string} pathname - Ruta a buscar
|
|
21
67
|
* @returns {Object|null} - Objeto de ruta encontrado o null
|
|
22
68
|
*/
|
|
23
69
|
findRoute(routes, method, pathname) {
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
70
|
+
// Actualizar índices si es necesario
|
|
71
|
+
if (!this.indexesValid || routes.length !== this.getStoredRoutesCount()) {
|
|
72
|
+
this.updateIndexes(routes);
|
|
73
|
+
}
|
|
28
74
|
|
|
75
|
+
// Búsqueda por ruta exacta (más rápida)
|
|
76
|
+
const exactMatch = this.findExactMatch(method, pathname);
|
|
29
77
|
if (exactMatch) {
|
|
30
78
|
return {
|
|
31
79
|
route: exactMatch,
|
|
@@ -33,45 +81,143 @@ class RouteMatcher {
|
|
|
33
81
|
};
|
|
34
82
|
}
|
|
35
83
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
84
|
+
// Pre-filtrar rutas candidatas usando índices
|
|
85
|
+
const pathnameSegments = pathname.split('/').filter(s => s !== '');
|
|
86
|
+
const segmentCount = pathnameSegments.length;
|
|
87
|
+
const firstSegment = pathnameSegments.length > 0 ? pathnameSegments[0] : '';
|
|
88
|
+
|
|
89
|
+
// Obtener rutas candidatas basadas en número de segmentos y primer segmento
|
|
90
|
+
const candidateRoutes = this.getCandidateRoutes(method, segmentCount, firstSegment, pathname);
|
|
91
|
+
|
|
92
|
+
// Buscar rutas estáticas que coincidan exactamente
|
|
93
|
+
const staticExactMatch = this.findStaticExactMatch(candidateRoutes, pathname);
|
|
94
|
+
if (staticExactMatch) {
|
|
95
|
+
return {
|
|
96
|
+
route: staticExactMatch,
|
|
97
|
+
params: {}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Buscar rutas parametrizadas entre los candidatos
|
|
102
|
+
const parametrizedMatch = this.findParametrizedMatch(candidateRoutes, pathname);
|
|
103
|
+
if (parametrizedMatch) {
|
|
104
|
+
return parametrizedMatch;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Buscar rutas estáticas (prefijos) entre los candidatos
|
|
108
|
+
const staticPrefixMatch = this.findStaticPrefixMatch(candidateRoutes, pathname);
|
|
109
|
+
if (staticPrefixMatch) {
|
|
110
|
+
return staticPrefixMatch;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Busca rutas exactas usando el índice
|
|
118
|
+
* @param {string} method - Método HTTP
|
|
119
|
+
* @param {string} pathname - Ruta a buscar
|
|
120
|
+
* @returns {Object|null} - Ruta exacta encontrada o null
|
|
121
|
+
*/
|
|
122
|
+
findExactMatch(method, pathname) {
|
|
123
|
+
const methodPathKey = `${method}:${pathname}`;
|
|
124
|
+
return this.exactRoutes.get(methodPathKey) || null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Obtiene rutas candidatas basadas en número de segmentos y primer segmento
|
|
129
|
+
* @param {string} method - Método HTTP
|
|
130
|
+
* @param {number} segmentCount - Número de segmentos de la ruta buscada
|
|
131
|
+
* @param {string} firstSegment - Primer segmento de la ruta buscada
|
|
132
|
+
* @param {string} pathname - Ruta completa buscada
|
|
133
|
+
* @returns {Array} - Array de rutas candidatas
|
|
134
|
+
*/
|
|
135
|
+
getCandidateRoutes(method, segmentCount, firstSegment, pathname) {
|
|
136
|
+
const candidates = [];
|
|
137
|
+
|
|
138
|
+
// Si existe un bucket para este método, número de segmentos y primer segmento
|
|
139
|
+
if (this.routeBuckets[method] &&
|
|
140
|
+
this.routeBuckets[method][segmentCount] &&
|
|
141
|
+
this.routeBuckets[method][segmentCount][firstSegment]) {
|
|
142
|
+
candidates.push(...this.routeBuckets[method][segmentCount][firstSegment]);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// También agregar rutas de otros primeros segmentos para este método y número de segmentos
|
|
146
|
+
// (por si hay rutas parametrizadas que también podrían coincidir)
|
|
147
|
+
if (this.routeBuckets[method] && this.routeBuckets[method][segmentCount]) {
|
|
148
|
+
for (const segment in this.routeBuckets[method][segmentCount]) {
|
|
149
|
+
if (segment !== firstSegment) {
|
|
150
|
+
candidates.push(...this.routeBuckets[method][segmentCount][segment]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Agregar rutas estáticas que podrían coincidir por prefijo
|
|
156
|
+
if (this.routeBuckets[method]) {
|
|
157
|
+
for (const count in this.routeBuckets[method]) {
|
|
158
|
+
for (const segment in this.routeBuckets[method][count]) {
|
|
159
|
+
const routes = this.routeBuckets[method][count][segment];
|
|
160
|
+
for (const route of routes) {
|
|
161
|
+
if (route.isStatic && pathname.startsWith(route.path)) {
|
|
162
|
+
candidates.push(route);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return candidates;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Busca rutas estáticas con coincidencia exacta entre candidatos
|
|
174
|
+
* @param {Array} candidateRoutes - Rutas candidatas
|
|
175
|
+
* @param {string} pathname - Ruta a buscar
|
|
176
|
+
* @returns {Object|null} - Ruta estática exacta encontrada o null
|
|
177
|
+
*/
|
|
178
|
+
findStaticExactMatch(candidateRoutes, pathname) {
|
|
179
|
+
for (const route of candidateRoutes) {
|
|
42
180
|
if (route.isStatic && route.path === pathname) {
|
|
43
|
-
return
|
|
44
|
-
route: route,
|
|
45
|
-
params: {}
|
|
46
|
-
};
|
|
181
|
+
return route;
|
|
47
182
|
}
|
|
48
183
|
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
49
186
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
params
|
|
65
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Busca rutas parametrizadas entre candidatos
|
|
189
|
+
* @param {Array} candidateRoutes - Rutas candidatas
|
|
190
|
+
* @param {string} pathname - Ruta a buscar
|
|
191
|
+
* @returns {Object|null} - Ruta parametrizada encontrada o null
|
|
192
|
+
*/
|
|
193
|
+
findParametrizedMatch(candidateRoutes, pathname) {
|
|
194
|
+
for (const route of candidateRoutes) {
|
|
195
|
+
if (this.isParametrizedRoute(route.path)) {
|
|
196
|
+
// Convertir ruta parametrizada a expresión regular
|
|
197
|
+
const routeRegex = this.pathToRegex(route.path);
|
|
198
|
+
const match = pathname.match(routeRegex);
|
|
199
|
+
|
|
200
|
+
if (match) {
|
|
201
|
+
const params = this.extractParams(route.path, pathname);
|
|
202
|
+
return {
|
|
203
|
+
route: route,
|
|
204
|
+
params: params
|
|
205
|
+
};
|
|
206
|
+
}
|
|
66
207
|
}
|
|
67
208
|
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
68
211
|
|
|
69
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Busca rutas estáticas por prefijo entre candidatos
|
|
214
|
+
* @param {Array} candidateRoutes - Rutas candidatas
|
|
215
|
+
* @param {string} pathname - Ruta a buscar
|
|
216
|
+
* @returns {Object|null} - Ruta estática por prefijo encontrada o null
|
|
217
|
+
*/
|
|
218
|
+
findStaticPrefixMatch(candidateRoutes, pathname) {
|
|
70
219
|
const staticMatches = [];
|
|
71
|
-
for (const route of
|
|
72
|
-
if (route.method !== method) continue;
|
|
73
|
-
|
|
74
|
-
// Para rutas estáticas, verificar si la ruta solicitada comienza con el prefijo de la ruta estática
|
|
220
|
+
for (const route of candidateRoutes) {
|
|
75
221
|
if (route.isStatic && pathname.startsWith(route.path)) {
|
|
76
222
|
// Verificar que sea exactamente el prefijo o que haya una barra después del prefijo
|
|
77
223
|
const remainingPath = pathname.substring(route.path.length);
|
|
@@ -85,27 +231,40 @@ class RouteMatcher {
|
|
|
85
231
|
}
|
|
86
232
|
}
|
|
87
233
|
|
|
88
|
-
|
|
89
|
-
// (tiene extensión), dar prioridad a la ruta estática más específica
|
|
90
|
-
const hasFileExtension = /\.[^.]+$/.test(pathname);
|
|
91
|
-
|
|
92
|
-
if (hasFileExtension && staticMatches.length > 0) {
|
|
234
|
+
if (staticMatches.length > 0) {
|
|
93
235
|
// Ordenar por especificidad (longitud del prefijo, descendente) y tomar la más específica
|
|
94
236
|
staticMatches.sort((a, b) => b.specificity - a.specificity);
|
|
95
|
-
// Para solicitudes de archivos, dar prioridad a rutas estáticas más específicas
|
|
96
|
-
return staticMatches[0]; // Devolver la coincidencia estática más específica
|
|
97
|
-
} else if (parametrizedMatches.length > 0) {
|
|
98
|
-
// Para solicitudes sin extensión o rutas API, dar prioridad a rutas parametrizadas
|
|
99
|
-
return parametrizedMatches[0]; // Devolver la primera coincidencia parametrizada
|
|
100
|
-
} else if (staticMatches.length > 0) {
|
|
101
|
-
// Si no hay coincidencias parametrizadas, usar la estática más específica
|
|
102
|
-
staticMatches.sort((a, b) => b.specificity - a.specificity);
|
|
103
237
|
return staticMatches[0];
|
|
104
238
|
}
|
|
105
239
|
|
|
106
240
|
return null;
|
|
107
241
|
}
|
|
108
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Determina si una ruta es parametrizada
|
|
245
|
+
* @param {string} path - Ruta a verificar
|
|
246
|
+
* @returns {boolean} - True si la ruta contiene parámetros
|
|
247
|
+
*/
|
|
248
|
+
isParametrizedRoute(path) {
|
|
249
|
+
return path.includes(':');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Obtiene el conteo total de rutas almacenadas en índices
|
|
254
|
+
* @returns {number} - Número total de rutas indexadas
|
|
255
|
+
*/
|
|
256
|
+
getStoredRoutesCount() {
|
|
257
|
+
let count = 0;
|
|
258
|
+
for (const method in this.routeBuckets) {
|
|
259
|
+
for (const segmentCount in this.routeBuckets[method]) {
|
|
260
|
+
for (const firstSegment in this.routeBuckets[method][segmentCount]) {
|
|
261
|
+
count += this.routeBuckets[method][segmentCount][firstSegment].length;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return count;
|
|
266
|
+
}
|
|
267
|
+
|
|
109
268
|
/**
|
|
110
269
|
* Convierte una ruta con parámetros a expresión regular
|
|
111
270
|
* @param {string} path - Ruta con posibles parámetros
|
|
@@ -131,8 +290,20 @@ class RouteMatcher {
|
|
|
131
290
|
const regexPath = escapedPath.replace(/:([a-zA-Z0-9_]+)/g, '([^/]+?)');
|
|
132
291
|
const regex = new RegExp(`^${regexPath}$`);
|
|
133
292
|
|
|
134
|
-
//
|
|
135
|
-
this.
|
|
293
|
+
// Verificar con hook si se debe cachear esta expresión regular
|
|
294
|
+
const shouldCache = this.hooks ?
|
|
295
|
+
this.hooks.applyFilters('should_cache_route_regex', true, path, regex) : true;
|
|
296
|
+
|
|
297
|
+
if (shouldCache) {
|
|
298
|
+
// Almacenar en caché
|
|
299
|
+
this.routeRegexCache.set(path, regex);
|
|
300
|
+
|
|
301
|
+
// Disparar hook después de cachear
|
|
302
|
+
if (this.hooks) {
|
|
303
|
+
this.hooks.doAction('route_regex_cached', path, regex);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
136
307
|
return regex;
|
|
137
308
|
}
|
|
138
309
|
|
|
@@ -169,6 +340,23 @@ class RouteMatcher {
|
|
|
169
340
|
|
|
170
341
|
return params;
|
|
171
342
|
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Limpia el caché de expresiones regulares
|
|
346
|
+
*/
|
|
347
|
+
clearCache() {
|
|
348
|
+
// Disparar hook antes de limpiar el caché
|
|
349
|
+
if (this.hooks) {
|
|
350
|
+
this.hooks.doAction('before_route_regex_cache_clear', this);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
this.routeRegexCache.clear();
|
|
354
|
+
|
|
355
|
+
// Disparar hook después de limpiar el caché
|
|
356
|
+
if (this.hooks) {
|
|
357
|
+
this.hooks.doAction('route_regex_cache_cleared');
|
|
358
|
+
}
|
|
359
|
+
}
|
|
172
360
|
}
|
|
173
361
|
|
|
174
362
|
module.exports = RouteMatcher;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Almacenamiento global de estadísticas para el framework JERK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Crear un objeto global para almacenar estadísticas
|
|
6
|
+
const globalStats = {
|
|
7
|
+
requestsProcessed: 0,
|
|
8
|
+
responsesSent: 0,
|
|
9
|
+
requestBytes: 0,
|
|
10
|
+
responseBytes: 0,
|
|
11
|
+
routeAccesses: new Map(), // Contador de accesos por ruta
|
|
12
|
+
endpointHits: new Map(), // Contador de hits por endpoint
|
|
13
|
+
lastRequests: [] // Últimas solicitudes para análisis
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = { globalStats };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Almacenamiento global de información del caché de vistas para el framework JERK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Crear un objeto global para almacenar información del caché de vistas
|
|
6
|
+
const globalViewCacheInfo = {
|
|
7
|
+
viewCache: new Map(), // Cache de vistas compiladas
|
|
8
|
+
cacheStats: {
|
|
9
|
+
hits: 0,
|
|
10
|
+
misses: 0,
|
|
11
|
+
totalViews: 0
|
|
12
|
+
},
|
|
13
|
+
viewDependencies: new Map() // Registro de dependencias entre vistas (inclusiones)
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = { globalViewCacheInfo };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sistema de Almacenamiento Global de Estadísticas del WAF (Web Application Firewall)
|
|
3
|
+
* Almacenamiento centralizado de datos del firewall para acceso eficiente
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Objeto global para almacenar estadísticas del WAF
|
|
7
|
+
const globalWAFStats = {
|
|
8
|
+
// Contadores de solicitudes
|
|
9
|
+
requestsProcessed: 0,
|
|
10
|
+
responsesSent: 0,
|
|
11
|
+
|
|
12
|
+
// Contadores de bytes
|
|
13
|
+
requestBytes: 0,
|
|
14
|
+
responseBytes: 0,
|
|
15
|
+
|
|
16
|
+
// Registro de accesos a rutas
|
|
17
|
+
routeAccesses: new Map(), // Mapa de rutas y número de accesos
|
|
18
|
+
|
|
19
|
+
// Registro de hits a endpoints
|
|
20
|
+
endpointHits: new Map(), // Mapa de endpoints y número de hits
|
|
21
|
+
|
|
22
|
+
// IPs bloqueadas temporalmente
|
|
23
|
+
blockedIPs: new Map(), // Mapa de IPs bloqueadas con información de bloqueo
|
|
24
|
+
|
|
25
|
+
// IPs en lista blanca (nunca bloqueadas)
|
|
26
|
+
whitelist: new Set(),
|
|
27
|
+
|
|
28
|
+
// IPs en lista negra (siempre bloqueadas)
|
|
29
|
+
blacklist: new Set(),
|
|
30
|
+
|
|
31
|
+
// Reglas de seguridad activas
|
|
32
|
+
securityRules: new Map(), // Mapa de reglas de seguridad
|
|
33
|
+
|
|
34
|
+
// Reglas de headers X-
|
|
35
|
+
xHeaderRules: new Map(), // Mapa de reglas de headers X-
|
|
36
|
+
|
|
37
|
+
// Tipos de ataques detectados
|
|
38
|
+
attackTypes: new Set(), // Conjunto de tipos de ataques detectados
|
|
39
|
+
|
|
40
|
+
// Contador de intentos de ataque
|
|
41
|
+
attackAttempts: 0,
|
|
42
|
+
|
|
43
|
+
// Registros de seguridad
|
|
44
|
+
securityLogs: [],
|
|
45
|
+
|
|
46
|
+
// Estadísticas de rendimiento
|
|
47
|
+
performanceStats: {
|
|
48
|
+
startTime: new Date().toISOString(),
|
|
49
|
+
requestProcessingTime: 0,
|
|
50
|
+
averageResponseTime: 0
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = { globalWAFStats };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jerkjs",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "JERK Framework v2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
|
+
"description": "JERK Framework v2.6.1 - A comprehensive framework for building secure and scalable APIs with frontend support, sessions, template engine, integration with qbuilderjs, complete MVC architecture with models, enhanced route loading from directory, improved model loading system, administration extension, queue management system, route cache management module, and fixed routing issues with static and parametrized routes",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
package/test-colors.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Script de prueba para verificar que los colores funcionan en el módulo de cache de rutas
|
|
5
|
+
* Este script simula la interacción con el módulo para verificar la visualización de comandos en color
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Simulación de socket para probar la funcionalidad de color
|
|
9
|
+
const mockSocket = {
|
|
10
|
+
data: '',
|
|
11
|
+
write: function(text) {
|
|
12
|
+
this.data += text;
|
|
13
|
+
// En un entorno real, esto escribiría en el socket
|
|
14
|
+
process.stdout.write(text);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Importar el módulo
|
|
19
|
+
const RouteCacheModule = require('./lib/admin/modules/RouteCacheModule');
|
|
20
|
+
|
|
21
|
+
// Crear una instancia simulada de adminExtension
|
|
22
|
+
const mockAdminExtension = {
|
|
23
|
+
frameworkInstance: {
|
|
24
|
+
routeMatcher: {
|
|
25
|
+
routeRegexCache: new Map([
|
|
26
|
+
['/users/:id', /^\/users\/([^\/]+?)$/],
|
|
27
|
+
['/posts/:slug', /^\/posts\/([^\/]+?)$/]
|
|
28
|
+
]),
|
|
29
|
+
exactRoutes: new Map([
|
|
30
|
+
['GET:/api/users', { handler: { name: 'getUserHandler' }, isStatic: false }],
|
|
31
|
+
['POST:/api/users', { handler: { name: 'createUserHandler' }, isStatic: false }]
|
|
32
|
+
]),
|
|
33
|
+
indexesValid: true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Crear instancia del módulo
|
|
39
|
+
const routeCacheModule = new RouteCacheModule(mockAdminExtension);
|
|
40
|
+
|
|
41
|
+
console.log('Probando el módulo de cache de rutas con colores...\n');
|
|
42
|
+
|
|
43
|
+
// Probar el manejo de un comando desconocido para ver el mensaje con comandos en verde
|
|
44
|
+
routeCacheModule.handleCommand('comando-invalido', mockSocket);
|
|
45
|
+
|
|
46
|
+
console.log('\nFin de la prueba.');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Script de prueba para verificar que el alias '?' funciona en el sistema de administración
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { APIServer } = require('./index.js');
|
|
8
|
+
|
|
9
|
+
// Crear instancia del servidor
|
|
10
|
+
const server = new APIServer({ port: 3001 }); // Usar un puerto diferente para evitar conflictos
|
|
11
|
+
|
|
12
|
+
// Agregar una ruta de ejemplo
|
|
13
|
+
server.addRoute('GET', '/', (req, res) => {
|
|
14
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
15
|
+
res.end('Hola Mundo!');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Inicializar la extensión de administración
|
|
19
|
+
server.initializeAdminExtension({
|
|
20
|
+
port: 9998, // Usar un puerto diferente para evitar conflictos
|
|
21
|
+
host: '127.0.0.1'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log('Servidor de prueba iniciado en http://localhost:3001');
|
|
25
|
+
console.log('Servidor de administración en tcp://localhost:9998');
|
|
26
|
+
console.log('\nPara probar el alias "?":');
|
|
27
|
+
console.log('- Conéctate al servidor de administración con: telnet localhost 9998 o nc localhost 9998');
|
|
28
|
+
console.log('- Escribe "?" y presiona Enter para ver la ayuda');
|
|
29
|
+
|
|
30
|
+
// Iniciar el servidor
|
|
31
|
+
server.start();
|