jerkjs 2.0.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/LICENSE +200 -0
- package/README.md +171 -0
- package/doc/EXTENSION_MANUAL.md +958 -0
- package/doc/FIREWALL_MANUAL.md +419 -0
- package/doc/HOOKS_REFERENCE_IMPROVED.md +599 -0
- package/doc/MANUAL_API_SDK.md +539 -0
- package/doc/MANUAL_MVC.md +397 -0
- package/doc/MARIADB_TOKENS_IMPLEMENTATION.md +113 -0
- package/doc/MIDDLEWARE_MANUAL.md +521 -0
- package/doc/OAUTH2_GOOGLE_MANUAL.md +408 -0
- package/doc/frontend-and-sessions.md +356 -0
- package/examples/advanced/controllers/productController.js +64 -0
- package/examples/advanced/controllers/userController.js +85 -0
- package/examples/advanced/routes.json +51 -0
- package/examples/advanced_example.js +93 -0
- package/examples/basic/controllers/userController.js +85 -0
- package/examples/basic_example.js +72 -0
- package/examples/frontend/README.md +71 -0
- package/examples/frontend/app.js +71 -0
- package/examples/frontend/controllers/apiController.js +39 -0
- package/examples/frontend/controllers/authController.js +220 -0
- package/examples/frontend/controllers/formController.js +47 -0
- package/examples/frontend/controllers/messageController.js +96 -0
- package/examples/frontend/controllers/pageController.js +178 -0
- package/examples/frontend/controllers/staticController.js +167 -0
- package/examples/frontend/routes.json +90 -0
- package/examples/mvc_example/app.js +138 -0
- package/examples/mvc_example/views/home/index.html +26 -0
- package/examples/mvc_example/views/home/simple.html +3 -0
- package/examples/mvc_example/views/layout.html +23 -0
- package/examples/mvc_example/views/test.html +3 -0
- package/examples/mvc_example/views/user/invalid.html +6 -0
- package/examples/mvc_example/views/user/list.html +36 -0
- package/examples/mvc_example/views/user/notfound.html +6 -0
- package/examples/mvc_example/views/user/profile.html +11 -0
- package/examples/mvc_routes_example/app.js +34 -0
- package/examples/mvc_routes_example/controllers/mainController.js +27 -0
- package/examples/mvc_routes_example/controllers/productController.js +47 -0
- package/examples/mvc_routes_example/controllers/userController.js +76 -0
- package/examples/mvc_routes_example/routes.json +30 -0
- package/examples/mvc_routes_example/views/layout.html +31 -0
- package/examples/mvc_routes_example/views/main/index.html +11 -0
- package/examples/mvc_routes_example/views/product/catalog.html +24 -0
- package/examples/mvc_routes_example/views/user/invalid.html +6 -0
- package/examples/mvc_routes_example/views/user/list.html +40 -0
- package/examples/mvc_routes_example/views/user/notfound.html +6 -0
- package/examples/mvc_routes_example/views/user/profile.html +18 -0
- package/examples/public/README.md +92 -0
- package/examples/public/app.js +72 -0
- package/examples/public/controllers/healthController.js +20 -0
- package/examples/public/controllers/mainController.js +22 -0
- package/examples/public/controllers/userController.js +139 -0
- package/examples/public/routes.json +51 -0
- package/examples/v2/README.md +72 -0
- package/examples/v2/app.js +74 -0
- package/examples/v2/app_fixed.js +74 -0
- package/examples/v2/controllers/authController.js +64 -0
- package/examples/v2/controllers/mainController.js +24 -0
- package/examples/v2/controllers/protectedController.js +12 -0
- package/examples/v2/controllers/userController.js +16 -0
- package/examples/v2/package.json +27 -0
- package/examples/v2/routes.json +30 -0
- package/examples/v2/test_api.sh +47 -0
- package/examples/v2/tokens_example.sqlite +0 -0
- package/examples/v2.1_firewall_demo/README.md +113 -0
- package/examples/v2.1_firewall_demo/app.js +182 -0
- package/examples/v2.1_firewall_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/README.md +85 -0
- package/examples/v2.1_hooks_demo/app.js +101 -0
- package/examples/v2.1_hooks_demo/controllers/hooksController.js +29 -0
- package/examples/v2.1_hooks_demo/controllers/mainController.js +18 -0
- package/examples/v2.1_hooks_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/routes.json +16 -0
- package/examples/v2.1_openapi_demo/README.md +82 -0
- package/examples/v2.1_openapi_demo/app.js +296 -0
- package/examples/v2.1_openapi_demo/package.json +26 -0
- package/examples/v2_cors/README.md +82 -0
- package/examples/v2_cors/app.js +108 -0
- package/examples/v2_cors/package.json +23 -0
- package/examples/v2_json_auth/README.md +83 -0
- package/examples/v2_json_auth/app.js +72 -0
- package/examples/v2_json_auth/controllers/authController.js +67 -0
- package/examples/v2_json_auth/controllers/mainController.js +16 -0
- package/examples/v2_json_auth/controllers/protectedController.js +12 -0
- package/examples/v2_json_auth/controllers/tokenController.js +28 -0
- package/examples/v2_json_auth/controllers/userController.js +15 -0
- package/examples/v2_json_auth/package.json +26 -0
- package/examples/v2_json_auth/routes.json +37 -0
- package/examples/v2_json_auth/tokens.json +20 -0
- package/examples/v2_mariadb_auth/README.md +94 -0
- package/examples/v2_mariadb_auth/app.js +81 -0
- package/examples/v2_mariadb_auth/controllers/authController.js +95 -0
- package/examples/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/examples/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/examples/v2_mariadb_auth/controllers/userController.js +17 -0
- package/examples/v2_mariadb_auth/package.json +27 -0
- package/examples/v2_mariadb_auth/routes.json +37 -0
- package/examples/v2_no_auth/README.md +75 -0
- package/examples/v2_no_auth/app.js +72 -0
- package/examples/v2_no_auth/controllers/healthController.js +14 -0
- package/examples/v2_no_auth/controllers/mainController.js +19 -0
- package/examples/v2_no_auth/controllers/productController.js +31 -0
- package/examples/v2_no_auth/controllers/publicController.js +16 -0
- package/examples/v2_no_auth/package.json +22 -0
- package/examples/v2_no_auth/routes.json +37 -0
- package/examples/v2_oauth/README.md +70 -0
- package/examples/v2_oauth/app.js +90 -0
- package/examples/v2_oauth/controllers/mainController.js +45 -0
- package/examples/v2_oauth/controllers/oauthController.js +247 -0
- package/examples/v2_oauth/controllers/protectedController.js +13 -0
- package/examples/v2_oauth/controllers/userController.js +17 -0
- package/examples/v2_oauth/package.json +26 -0
- package/examples/v2_oauth/routes.json +44 -0
- package/examples/v2_openapi/README.md +77 -0
- package/examples/v2_openapi/app.js +222 -0
- package/examples/v2_openapi/controllers/authController.js +52 -0
- package/examples/v2_openapi/controllers/mainController.js +26 -0
- package/examples/v2_openapi/controllers/productController.js +17 -0
- package/examples/v2_openapi/controllers/userController.js +27 -0
- package/examples/v2_openapi/package.json +26 -0
- package/examples/v2_openapi/routes.json +37 -0
- package/generate_token.js +10 -0
- package/index.js +85 -0
- package/jerk.jpg +0 -0
- package/lib/core/handler.js +86 -0
- package/lib/core/hooks.js +224 -0
- package/lib/core/router.js +204 -0
- package/lib/core/securityEnhancedServer.js +752 -0
- package/lib/core/server.js +369 -0
- package/lib/loader/controllerLoader.js +175 -0
- package/lib/loader/routeLoader.js +341 -0
- package/lib/middleware/auditLogger.js +208 -0
- package/lib/middleware/authenticator.js +565 -0
- package/lib/middleware/compressor.js +218 -0
- package/lib/middleware/cors.js +135 -0
- package/lib/middleware/firewall.js +443 -0
- package/lib/middleware/rateLimiter.js +210 -0
- package/lib/middleware/session.js +301 -0
- package/lib/middleware/validator.js +193 -0
- package/lib/mvc/controllerBase.js +207 -0
- package/lib/mvc/viewEngine.js +752 -0
- package/lib/utils/configParser.js +223 -0
- package/lib/utils/logger.js +145 -0
- package/lib/utils/mariadbTokenAdapter.js +226 -0
- package/lib/utils/openapiGenerator.js +140 -0
- package/lib/utils/sqliteTokenAdapter.js +224 -0
- package/lib/utils/tokenManager.js +254 -0
- package/package.json +47 -0
- package/v2examplle/v2_json_auth/README.md +83 -0
- package/v2examplle/v2_json_auth/app.js +72 -0
- package/v2examplle/v2_json_auth/controllers/authController.js +67 -0
- package/v2examplle/v2_json_auth/controllers/mainController.js +16 -0
- package/v2examplle/v2_json_auth/controllers/protectedController.js +12 -0
- package/v2examplle/v2_json_auth/controllers/tokenController.js +28 -0
- package/v2examplle/v2_json_auth/controllers/userController.js +15 -0
- package/v2examplle/v2_json_auth/package.json +26 -0
- package/v2examplle/v2_json_auth/routes.json +37 -0
- package/v2examplle/v2_json_auth/tokens.json +20 -0
- package/v2examplle/v2_mariadb_auth/README.md +94 -0
- package/v2examplle/v2_mariadb_auth/app.js +81 -0
- package/v2examplle/v2_mariadb_auth/controllers/authController.js +95 -0
- package/v2examplle/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/v2examplle/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/v2examplle/v2_mariadb_auth/controllers/userController.js +17 -0
- package/v2examplle/v2_mariadb_auth/package.json +27 -0
- package/v2examplle/v2_mariadb_auth/routes.json +37 -0
- package/v2examplle/v2_sqlite_auth/README.md +72 -0
- package/v2examplle/v2_sqlite_auth/app.js +74 -0
- package/v2examplle/v2_sqlite_auth/app_fixed.js +74 -0
- package/v2examplle/v2_sqlite_auth/controllers/authController.js +64 -0
- package/v2examplle/v2_sqlite_auth/controllers/mainController.js +24 -0
- package/v2examplle/v2_sqlite_auth/controllers/protectedController.js +12 -0
- package/v2examplle/v2_sqlite_auth/controllers/userController.js +16 -0
- package/v2examplle/v2_sqlite_auth/package.json +27 -0
- package/v2examplle/v2_sqlite_auth/routes.json +30 -0
- package/v2examplle/v2_sqlite_auth/test_api.sh +47 -0
- package/v2examplle/v2_sqlite_auth/tokens_example.sqlite +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware de compresión para el framework API SDK
|
|
3
|
+
* Implementación del componente middleware/compressor.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const zlib = require('zlib');
|
|
7
|
+
|
|
8
|
+
class Compressor {
|
|
9
|
+
/**
|
|
10
|
+
* Constructor del compresor
|
|
11
|
+
* @param {Object} options - Opciones de configuración
|
|
12
|
+
* @param {Array} options.encodings - Tipos de compresión soportados
|
|
13
|
+
* @param {number} options.threshold - Tamaño mínimo en bytes para comprimir
|
|
14
|
+
* @param {Object} options.gzipOptions - Opciones para compresión gzip
|
|
15
|
+
* @param {Object} options.deflateOptions - Opciones para compresión deflate
|
|
16
|
+
*/
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.encodings = options.encodings || ['gzip', 'deflate'];
|
|
19
|
+
this.threshold = options.threshold || 1024; // 1KB por defecto
|
|
20
|
+
this.gzipOptions = options.gzipOptions || {};
|
|
21
|
+
this.deflateOptions = options.deflateOptions || {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Middleware de compresión
|
|
26
|
+
* @returns {Function} - Middleware de compresión
|
|
27
|
+
*/
|
|
28
|
+
middleware() {
|
|
29
|
+
return (req, res, next) => {
|
|
30
|
+
// Verificar si el cliente acepta compresión
|
|
31
|
+
const acceptEncoding = req.headers['accept-encoding'];
|
|
32
|
+
if (!acceptEncoding) {
|
|
33
|
+
if (next) next();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Determinar el método de compresión preferido
|
|
38
|
+
let compressionMethod = null;
|
|
39
|
+
|
|
40
|
+
if (acceptEncoding.includes('gzip')) {
|
|
41
|
+
compressionMethod = 'gzip';
|
|
42
|
+
} else if (acceptEncoding.includes('deflate')) {
|
|
43
|
+
compressionMethod = 'deflate';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Si no se soporta ningún método, continuar sin comprimir
|
|
47
|
+
if (!compressionMethod || !this.encodings.includes(compressionMethod)) {
|
|
48
|
+
if (next) next();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Guardar el método original de res.end
|
|
53
|
+
const originalEnd = res.end;
|
|
54
|
+
const originalWriteHead = res.writeHead;
|
|
55
|
+
|
|
56
|
+
// Variable para almacenar el cuerpo de la respuesta
|
|
57
|
+
let responseBody = '';
|
|
58
|
+
|
|
59
|
+
// Sobrescribir res.write para capturar el cuerpo
|
|
60
|
+
res.write = (chunk, encoding) => {
|
|
61
|
+
responseBody += chunk;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Sobrescribir res.end para comprimir antes de enviar
|
|
65
|
+
res.end = (chunk, encoding) => {
|
|
66
|
+
// Añadir el chunk final al cuerpo si existe
|
|
67
|
+
if (chunk) {
|
|
68
|
+
responseBody += chunk;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Si el cuerpo es menor que el umbral, enviar sin comprimir
|
|
72
|
+
if (Buffer.byteLength(responseBody) < this.threshold) {
|
|
73
|
+
res.removeHeader('Content-Encoding'); // Asegurar que no haya encabezado de codificación
|
|
74
|
+
originalWriteHead.call(res);
|
|
75
|
+
originalEnd.call(res, responseBody, encoding);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Aplicar compresión según el método seleccionado
|
|
80
|
+
let compressedBody;
|
|
81
|
+
let compressPromise;
|
|
82
|
+
|
|
83
|
+
if (compressionMethod === 'gzip') {
|
|
84
|
+
compressPromise = new Promise((resolve, reject) => {
|
|
85
|
+
zlib.gzip(responseBody, this.gzipOptions, (err, buffer) => {
|
|
86
|
+
if (err) {
|
|
87
|
+
reject(err);
|
|
88
|
+
} else {
|
|
89
|
+
resolve(buffer);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
} else if (compressionMethod === 'deflate') {
|
|
94
|
+
compressPromise = new Promise((resolve, reject) => {
|
|
95
|
+
zlib.deflate(responseBody, this.deflateOptions, (err, buffer) => {
|
|
96
|
+
if (err) {
|
|
97
|
+
reject(err);
|
|
98
|
+
} else {
|
|
99
|
+
resolve(buffer);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Esperar a que se complete la compresión y enviar la respuesta
|
|
106
|
+
compressPromise
|
|
107
|
+
.then(compressed => {
|
|
108
|
+
// Establecer encabezados apropiados
|
|
109
|
+
res.setHeader('Content-Encoding', compressionMethod);
|
|
110
|
+
res.removeHeader('Content-Length'); // Eliminar Content-Length original
|
|
111
|
+
|
|
112
|
+
// Llamar al writeHead original
|
|
113
|
+
originalWriteHead.call(res);
|
|
114
|
+
|
|
115
|
+
// Enviar el cuerpo comprimido
|
|
116
|
+
originalEnd.call(res, compressed, encoding);
|
|
117
|
+
})
|
|
118
|
+
.catch(err => {
|
|
119
|
+
console.error('Error comprimiendo la respuesta:', err);
|
|
120
|
+
// Si ocurre un error, enviar sin comprimir
|
|
121
|
+
res.removeHeader('Content-Encoding');
|
|
122
|
+
originalWriteHead.call(res);
|
|
123
|
+
originalEnd.call(res, responseBody, encoding);
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Continuar con el siguiente middleware
|
|
128
|
+
if (next) {
|
|
129
|
+
next();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Middleware para comprimir solo respuestas JSON
|
|
136
|
+
* @returns {Function} - Middleware de compresión para JSON
|
|
137
|
+
*/
|
|
138
|
+
jsonOnly() {
|
|
139
|
+
return (req, res, next) => {
|
|
140
|
+
const originalSend = res.send; // Suponiendo que hay un método send
|
|
141
|
+
|
|
142
|
+
res.send = (data) => {
|
|
143
|
+
// Verificar si el tipo de contenido es JSON
|
|
144
|
+
const contentType = res.getHeader('Content-Type');
|
|
145
|
+
if (contentType && contentType.includes('application/json')) {
|
|
146
|
+
// Convertir a string si no lo es
|
|
147
|
+
const jsonString = typeof data === 'string' ? data : JSON.stringify(data);
|
|
148
|
+
|
|
149
|
+
// Continuar con la lógica de compresión
|
|
150
|
+
// (similar a la implementación en middleware())
|
|
151
|
+
const acceptEncoding = req.headers['accept-encoding'];
|
|
152
|
+
if (!acceptEncoding) {
|
|
153
|
+
res.setHeader('Content-Type', 'application/json');
|
|
154
|
+
originalSend.call(res, jsonString);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let compressionMethod = null;
|
|
159
|
+
if (acceptEncoding.includes('gzip')) {
|
|
160
|
+
compressionMethod = 'gzip';
|
|
161
|
+
} else if (acceptEncoding.includes('deflate')) {
|
|
162
|
+
compressionMethod = 'deflate';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!compressionMethod || !this.encodings.includes(compressionMethod)) {
|
|
166
|
+
res.setHeader('Content-Type', 'application/json');
|
|
167
|
+
originalSend.call(res, jsonString);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (Buffer.byteLength(jsonString) < this.threshold) {
|
|
172
|
+
res.setHeader('Content-Type', 'application/json');
|
|
173
|
+
res.removeHeader('Content-Encoding');
|
|
174
|
+
originalSend.call(res, jsonString);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (compressionMethod === 'gzip') {
|
|
179
|
+
zlib.gzip(jsonString, this.gzipOptions, (err, compressed) => {
|
|
180
|
+
if (err) {
|
|
181
|
+
console.error('Error comprimiendo JSON:', err);
|
|
182
|
+
res.setHeader('Content-Type', 'application/json');
|
|
183
|
+
originalSend.call(res, jsonString);
|
|
184
|
+
} else {
|
|
185
|
+
res.setHeader('Content-Encoding', compressionMethod);
|
|
186
|
+
res.removeHeader('Content-Length');
|
|
187
|
+
res.setHeader('Content-Type', 'application/json');
|
|
188
|
+
originalSend.call(res, compressed);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
} else if (compressionMethod === 'deflate') {
|
|
192
|
+
zlib.deflate(jsonString, this.deflateOptions, (err, compressed) => {
|
|
193
|
+
if (err) {
|
|
194
|
+
console.error('Error comprimiendo JSON:', err);
|
|
195
|
+
res.setHeader('Content-Type', 'application/json');
|
|
196
|
+
originalSend.call(res, jsonString);
|
|
197
|
+
} else {
|
|
198
|
+
res.setHeader('Content-Encoding', compressionMethod);
|
|
199
|
+
res.removeHeader('Content-Length');
|
|
200
|
+
res.setHeader('Content-Type', 'application/json');
|
|
201
|
+
originalSend.call(res, compressed);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
// Si no es JSON, enviar normalmente
|
|
207
|
+
originalSend.call(res, data);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
if (next) {
|
|
212
|
+
next();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = Compressor;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware de CORS para el framework API SDK
|
|
3
|
+
* Implementación del componente middleware/cors.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class Cors {
|
|
7
|
+
/**
|
|
8
|
+
* Constructor del middleware CORS
|
|
9
|
+
* @param {Object} options - Opciones de configuración de CORS
|
|
10
|
+
* @param {Array|string} options.origin - Orígenes permitidos
|
|
11
|
+
* @param {Array} options.methods - Métodos HTTP permitidos
|
|
12
|
+
* @param {Array} options.allowedHeaders - Headers permitidos
|
|
13
|
+
* @param {Array} options.exposedHeaders - Headers expuestos al cliente
|
|
14
|
+
* @param {boolean} options.credentials - Permitir credenciales
|
|
15
|
+
* @param {number} options.maxAge - Tiempo máximo para preflight cache
|
|
16
|
+
*/
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.options = {
|
|
19
|
+
origin: options.origin || '*',
|
|
20
|
+
methods: options.methods || ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
|
|
21
|
+
allowedHeaders: options.allowedHeaders || [
|
|
22
|
+
'Authorization',
|
|
23
|
+
'Content-Type',
|
|
24
|
+
'Accept',
|
|
25
|
+
'X-Requested-With',
|
|
26
|
+
'Access-Control-Allow-Origin'
|
|
27
|
+
],
|
|
28
|
+
exposedHeaders: options.exposedHeaders || [],
|
|
29
|
+
credentials: options.credentials !== undefined ? options.credentials : false,
|
|
30
|
+
maxAge: options.maxAge || 86400 // 24 hours
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Convertir métodos a mayúsculas
|
|
34
|
+
this.options.methods = this.options.methods.map(method => method.toUpperCase());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Middleware de CORS
|
|
39
|
+
* @returns {Function} - Middleware de CORS
|
|
40
|
+
*/
|
|
41
|
+
middleware() {
|
|
42
|
+
return (req, res, next) => {
|
|
43
|
+
// Determinar el origen permitido
|
|
44
|
+
const origin = this.determineOrigin(req);
|
|
45
|
+
|
|
46
|
+
if (origin) {
|
|
47
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
48
|
+
} else {
|
|
49
|
+
// Si no está permitido y no es wildcard, no establecer encabezado
|
|
50
|
+
if (this.options.origin !== '*') {
|
|
51
|
+
res.setHeader('Access-Control-Allow-Origin', 'null');
|
|
52
|
+
} else {
|
|
53
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Métodos permitidos
|
|
58
|
+
res.setHeader('Access-Control-Allow-Methods', this.options.methods.join(','));
|
|
59
|
+
|
|
60
|
+
// Headers permitidos
|
|
61
|
+
res.setHeader('Access-Control-Allow-Headers', this.options.allowedHeaders.join(','));
|
|
62
|
+
|
|
63
|
+
// Headers expuestos
|
|
64
|
+
if (this.options.exposedHeaders.length > 0) {
|
|
65
|
+
res.setHeader('Access-Control-Expose-Headers', this.options.exposedHeaders.join(','));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Credenciales
|
|
69
|
+
if (this.options.credentials) {
|
|
70
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Max age para preflight
|
|
74
|
+
res.setHeader('Access-Control-Max-Age', this.options.maxAge);
|
|
75
|
+
|
|
76
|
+
// Manejar solicitud preflight (OPTIONS)
|
|
77
|
+
if (req.method === 'OPTIONS') {
|
|
78
|
+
// Solo responder con 204 si el origen es válido o es wildcard
|
|
79
|
+
if (origin || this.options.origin === '*') {
|
|
80
|
+
res.writeHead(204); // No content
|
|
81
|
+
res.end();
|
|
82
|
+
} else {
|
|
83
|
+
// Si el origen no es válido, responder con 403 o permitir que la solicitud continúe
|
|
84
|
+
// para que otros middlewares o handlers puedan manejarla
|
|
85
|
+
if (next) {
|
|
86
|
+
next();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Continuar con el siguiente middleware
|
|
93
|
+
if (next) {
|
|
94
|
+
next();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Determina el origen permitido para la solicitud
|
|
101
|
+
* @param {Object} req - Objeto de solicitud HTTP
|
|
102
|
+
* @returns {string|boolean} - Origen permitido o falso si no está permitido
|
|
103
|
+
*/
|
|
104
|
+
determineOrigin(req) {
|
|
105
|
+
const requestOrigin = req.headers.origin;
|
|
106
|
+
|
|
107
|
+
if (!requestOrigin) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Si el origen es wildcard, permitir cualquier origen
|
|
112
|
+
if (this.options.origin === '*') {
|
|
113
|
+
return requestOrigin;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Si es un string, comparar directamente
|
|
117
|
+
if (typeof this.options.origin === 'string') {
|
|
118
|
+
return requestOrigin === this.options.origin ? requestOrigin : false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Si es un array, verificar si está incluido
|
|
122
|
+
if (Array.isArray(this.options.origin)) {
|
|
123
|
+
return this.options.origin.includes(requestOrigin) ? requestOrigin : false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Si es una función, llamarla para determinar el origen
|
|
127
|
+
if (typeof this.options.origin === 'function') {
|
|
128
|
+
return this.options.origin(requestOrigin);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = Cors;
|