vortez 5.0.0-dev.18 → 5.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/.gitignore +11 -4
- package/README.md +699 -177
- package/build/Template/Compiler.d.ts +70 -0
- package/build/Template/Compiler.js +135 -0
- package/build/Template/Compiler.js.map +1 -0
- package/build/Template/StreamCompiler.d.ts +16 -0
- package/build/Template/StreamCompiler.js +54 -0
- package/build/Template/StreamCompiler.js.map +1 -0
- package/build/Template/Template.d.ts +49 -0
- package/build/Template/Template.js +77 -0
- package/build/Template/Template.js.map +1 -0
- package/build/Vortez.d.ts +2 -1
- package/build/Vortez.js +2 -1
- package/build/Vortez.js.map +1 -1
- package/build/beta/JwtManager/JwtError.d.ts +8 -0
- package/build/beta/JwtManager/JwtError.js +10 -0
- package/build/beta/JwtManager/JwtError.js.map +1 -0
- package/build/beta/JwtManager/JwtManager.d.ts +3 -0
- package/build/beta/JwtManager/JwtManager.js +24 -7
- package/build/beta/JwtManager/JwtManager.js.map +1 -1
- package/build/server/BodyParser.d.ts +6 -0
- package/build/server/BodyParser.js +18 -3
- package/build/server/BodyParser.js.map +1 -1
- package/build/server/Request.d.ts +6 -4
- package/build/server/Request.js +15 -10
- package/build/server/Request.js.map +1 -1
- package/build/server/Response.d.ts +25 -10
- package/build/server/Response.js +161 -75
- package/build/server/Response.js.map +1 -1
- package/build/server/Server.d.ts +4 -4
- package/build/server/Server.js +34 -11
- package/build/server/Server.js.map +1 -1
- package/build/server/ServerDebug.d.ts +10 -1
- package/build/server/ServerDebug.js +85 -17
- package/build/server/ServerDebug.js.map +1 -1
- package/build/server/config/Config.d.ts +276 -47
- package/build/server/config/Config.js +70 -47
- package/build/server/config/Config.js.map +1 -1
- package/build/server/config/{ConfigLoader.d.ts → Loader.d.ts} +4 -5
- package/build/server/config/{ConfigLoader.js → Loader.js} +8 -11
- package/build/server/config/Loader.js.map +1 -0
- package/build/server/router/Router.d.ts +88 -31
- package/build/server/router/Router.js +113 -51
- package/build/server/router/Router.js.map +1 -1
- package/build/server/router/algorithm/Algorithm.d.ts +39 -0
- package/build/server/router/algorithm/Algorithm.js +20 -0
- package/build/server/router/algorithm/Algorithm.js.map +1 -0
- package/build/server/router/algorithm/FIFO.d.ts +15 -0
- package/build/server/router/algorithm/FIFO.js +24 -0
- package/build/server/router/algorithm/FIFO.js.map +1 -0
- package/build/server/router/algorithm/Tree.d.ts +38 -0
- package/build/server/router/algorithm/Tree.js +126 -0
- package/build/server/router/algorithm/Tree.js.map +1 -0
- package/build/server/router/middleware/HttpMiddleware.js +1 -1
- package/build/server/router/middleware/HttpMiddleware.js.map +1 -1
- package/build/server/router/middleware/WsMiddleware.js +1 -1
- package/build/server/router/middleware/WsMiddleware.js.map +1 -1
- package/build/server/security/PathSecurity.d.ts +45 -0
- package/build/server/security/PathSecurity.js +108 -0
- package/build/server/security/PathSecurity.js.map +1 -0
- package/build/server/websocket/Websocket.js +4 -1
- package/build/server/websocket/Websocket.js.map +1 -1
- package/build/utilities/ConsoleUI.d.ts +2 -1
- package/build/utilities/ConsoleUI.js +2 -1
- package/build/utilities/ConsoleUI.js.map +1 -1
- package/build/utilities/DebugUI.d.ts +1 -1
- package/build/utilities/DebugUI.js +1 -1
- package/build/utilities/Encoding.d.ts +22 -0
- package/build/utilities/Encoding.js +26 -0
- package/build/utilities/Encoding.js.map +1 -0
- package/build/utilities/Env.js +7 -2
- package/build/utilities/Env.js.map +1 -1
- package/build/utilities/File.d.ts +10 -0
- package/build/utilities/File.js +19 -0
- package/build/utilities/File.js.map +1 -0
- package/build/utilities/Flatten.d.ts +73 -0
- package/build/utilities/Flatten.js +76 -0
- package/build/utilities/Flatten.js.map +1 -0
- package/build/utilities/Object.d.ts +16 -0
- package/build/utilities/Object.js +48 -0
- package/build/utilities/Object.js.map +1 -0
- package/build/utilities/Path.d.ts +31 -11
- package/build/utilities/Path.js +48 -15
- package/build/utilities/Path.js.map +1 -1
- package/build/utilities/Time.d.ts +21 -0
- package/build/utilities/Time.js +25 -0
- package/build/utilities/Time.js.map +1 -0
- package/build/utilities/Utilities.d.ts +50 -92
- package/build/utilities/Utilities.js +56 -71
- package/build/utilities/Utilities.js.map +1 -1
- package/build/utilities/schema/Introspection.d.ts +24 -0
- package/build/utilities/schema/Introspection.js +87 -0
- package/build/utilities/schema/Introspection.js.map +1 -0
- package/build/utilities/schema/JSONSchema.d.ts +68 -0
- package/build/utilities/schema/JSONSchema.js +13 -0
- package/build/utilities/schema/JSONSchema.js.map +1 -0
- package/build/utilities/schema/Schema.d.ts +253 -0
- package/build/utilities/schema/Schema.js +241 -0
- package/build/utilities/schema/Schema.js.map +1 -0
- package/build/utilities/schema/SchemaError.d.ts +10 -0
- package/build/utilities/schema/SchemaError.js +13 -0
- package/build/utilities/schema/SchemaError.js.map +1 -0
- package/build/utilities/schema/Validator.d.ts +94 -0
- package/build/utilities/schema/Validator.js +246 -0
- package/build/utilities/schema/Validator.js.map +1 -0
- package/changes.md +4 -0
- package/docs/ARCHITECTURE.md +142 -0
- package/global/style/template/error.css +29 -0
- package/global/style/template/folder.css +79 -0
- package/global/{Style/Template/Template.css → style/template/template.css} +60 -68
- package/global/template/error.vhtml +29 -0
- package/global/template/folder.vhtml +54 -0
- package/package.json +2 -2
- package/build/Template.d.ts +0 -46
- package/build/Template.js +0 -81
- package/build/Template.js.map +0 -1
- package/build/server/config/ConfigLoader.js.map +0 -1
- package/build/server/config/ConfigValidator.d.ts +0 -71
- package/build/server/config/ConfigValidator.js +0 -131
- package/build/server/config/ConfigValidator.js.map +0 -1
- package/examples/in-docs.js +0 -96
- package/global/Style/Template/Error.css +0 -30
- package/global/Style/Template/Folder.css +0 -77
- package/global/Template/Error.vhtml +0 -29
- package/global/Template/Folder.vhtml +0 -41
- package/tests/Template/template.js +0 -18
- package/tests/Template/template.txt +0 -13
- package/tests/Template/template.vhtml +0 -23
- package/tests/debug.js +0 -34
- package/tests/jwtManager/jwtManager.js +0 -342
- package/tests/test.js +0 -131
- package/tests/test.vhtml +0 -14
- package/tests/utilities.js +0 -28
- package/tests/websocket.vhtml +0 -86
- /package/global/{Source/Logo_960.png → source/logo_960.png} +0 -0
- /package/global/{Source/Logo_SM_960.png → source/logo_SM_960.png} +0 -0
|
@@ -41,8 +41,9 @@ export class BodyParser {
|
|
|
41
41
|
this.httpRequest.on('end', () => resolve(Buffer.concat(chunks)));
|
|
42
42
|
this.httpRequest.on('error', (error) => reject(Error('fail parsing request body', { cause: error })));
|
|
43
43
|
this.httpRequest.on('data', (chunk) => {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
const size = chunks.reduce((total, current) => total + current.length, 0) + chunk.length;
|
|
45
|
+
if (size > 1e+8)
|
|
46
|
+
return void this.httpRequest.destroy(Error('Request body is too large'));
|
|
46
47
|
chunks.push(chunk);
|
|
47
48
|
});
|
|
48
49
|
});
|
|
@@ -90,7 +91,8 @@ export class BodyParser {
|
|
|
90
91
|
const fragments = decoded.split('&');
|
|
91
92
|
fragments.forEach((pair) => {
|
|
92
93
|
const [key, value] = pair.split('=');
|
|
93
|
-
|
|
94
|
+
const normalizedKey = this.safeDecodeURIComponent(key.replace(/\+/g, ' '));
|
|
95
|
+
content[normalizedKey] = this.safeDecodeURIComponent((value ?? '').replace(/\+/g, ' '));
|
|
94
96
|
});
|
|
95
97
|
return {
|
|
96
98
|
mimeType: 'application/x-www-form-urlencoded',
|
|
@@ -157,6 +159,19 @@ export class BodyParser {
|
|
|
157
159
|
return null;
|
|
158
160
|
return result[1];
|
|
159
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Safely decodes a URI component, returning the original value if decoding fails.
|
|
164
|
+
* @param value - The value to decode.
|
|
165
|
+
* @returns The decoded value or the original if decoding fails.
|
|
166
|
+
*/
|
|
167
|
+
safeDecodeURIComponent(value) {
|
|
168
|
+
try {
|
|
169
|
+
return decodeURIComponent(value);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
160
175
|
}
|
|
161
176
|
export default BodyParser;
|
|
162
177
|
//# sourceMappingURL=BodyParser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BodyParser.js","sourceRoot":"","sources":["../../src/server/BodyParser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,OAAO,UAAU;IAGI;IACA;IAHf,MAAM,CAAC,uBAAuB,GAAG,oHAAoH,CAAC;IAC9J,YACuB,OAAiC,EACjC,WAAiC;QADjC,YAAO,GAAP,OAAO,CAA0B;QACjC,gBAAW,GAAX,WAAW,CAAsB;IACrD,CAAC;IACJ;;;;OAIA;IACO,KAAK,CAAC,KAAK;QACd,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC;QACzD,IAAI,CAAC,WAAW;YAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACxE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3D,QAAO,MAAM,EAAE,CAAC;YACrB,KAAK,YAAY,CAAC,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACjD,KAAK,kBAAkB,CAAC,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACvD,KAAK,mCAAmC,CAAC,CAAC,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAC9E,KAAK,qBAAqB,CAAC,CAAC,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACvE,OAAO,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACrE,CAAC;IACC,CAAC;IACD;;;;OAIA;IACQ,KAAK,CAAC,WAAW;QACrB,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YACtG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBAClC,
|
|
1
|
+
{"version":3,"file":"BodyParser.js","sourceRoot":"","sources":["../../src/server/BodyParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,15 +13,15 @@ export declare class Request {
|
|
|
13
13
|
headers: Request.Headers;
|
|
14
14
|
/** Contains the request cookies. */
|
|
15
15
|
cookies: Cookie;
|
|
16
|
-
/** Contains the
|
|
16
|
+
/** Contains the query string parameters sent. */
|
|
17
17
|
searchParams: Request.SearchParams;
|
|
18
18
|
/** Contains the IP address of the requester. */
|
|
19
19
|
ip?: string | string[];
|
|
20
20
|
/** Contains the request method. */
|
|
21
21
|
method: Request.Method;
|
|
22
|
-
/** Contains the POSTParser. */
|
|
23
|
-
session: Session;
|
|
24
22
|
/** Contains the session of the device that made the request. */
|
|
23
|
+
session: Session;
|
|
24
|
+
/** Contains the request body parser. */
|
|
25
25
|
private body;
|
|
26
26
|
/** Contains the HTTP request received by the server. */
|
|
27
27
|
private httpRequest;
|
|
@@ -45,6 +45,7 @@ export declare class Request {
|
|
|
45
45
|
* @param Url - The URL received from the HTTP request.
|
|
46
46
|
*/
|
|
47
47
|
private getSearchParams;
|
|
48
|
+
private normalizeUrl;
|
|
48
49
|
}
|
|
49
50
|
export declare namespace Request {
|
|
50
51
|
export import BodyParser = _BodyParser;
|
|
@@ -58,6 +59,7 @@ export declare namespace Request {
|
|
|
58
59
|
}
|
|
59
60
|
interface SearchParams extends Document {
|
|
60
61
|
}
|
|
61
|
-
type
|
|
62
|
+
type KnownMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'ALL';
|
|
63
|
+
type Method = KnownMethod | (string & {});
|
|
62
64
|
}
|
|
63
65
|
export default Request;
|
package/build/server/Request.js
CHANGED
|
@@ -13,15 +13,15 @@ export class Request {
|
|
|
13
13
|
headers;
|
|
14
14
|
/** Contains the request cookies. */
|
|
15
15
|
cookies;
|
|
16
|
-
/** Contains the
|
|
16
|
+
/** Contains the query string parameters sent. */
|
|
17
17
|
searchParams;
|
|
18
18
|
/** Contains the IP address of the requester. */
|
|
19
19
|
ip;
|
|
20
20
|
/** Contains the request method. */
|
|
21
21
|
method;
|
|
22
|
-
/** Contains the POSTParser. */
|
|
23
|
-
session;
|
|
24
22
|
/** Contains the session of the device that made the request. */
|
|
23
|
+
session;
|
|
24
|
+
/** Contains the request body parser. */
|
|
25
25
|
body;
|
|
26
26
|
/** Contains the HTTP request received by the server. */
|
|
27
27
|
httpRequest;
|
|
@@ -37,12 +37,12 @@ export class Request {
|
|
|
37
37
|
const forwardedIP = httpRequest.headers['x-forwarded-for'];
|
|
38
38
|
const remoteIP = httpRequest.socket.remoteAddress;
|
|
39
39
|
const method = httpRequest.method ?? 'GET';
|
|
40
|
-
|
|
40
|
+
let url = httpRequest.url ?? '/';
|
|
41
41
|
this.httpRequest = httpRequest;
|
|
42
42
|
this.ip = forwardedIP ? forwardedIP : remoteIP ? remoteIP : '0.0.0.0';
|
|
43
43
|
this.method = this.getMethod(method);
|
|
44
44
|
this.url = url.split('?')[0];
|
|
45
|
-
this.url =
|
|
45
|
+
this.url = this.normalizeUrl(this.url);
|
|
46
46
|
this.headers = httpRequest.headers;
|
|
47
47
|
this.cookies = new Cookie(this.headers.cookie);
|
|
48
48
|
this.session = Session.get(this.cookies);
|
|
@@ -55,11 +55,9 @@ export class Request {
|
|
|
55
55
|
* @param method - The method used for the request.
|
|
56
56
|
*/
|
|
57
57
|
getMethod(method) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
: method == 'DELETE' ? 'DELETE'
|
|
62
|
-
: 'GET';
|
|
58
|
+
method = method.trim().toUpperCase();
|
|
59
|
+
method = method.length > 0 ? method : 'GET';
|
|
60
|
+
return method;
|
|
63
61
|
}
|
|
64
62
|
/**
|
|
65
63
|
* Retrieves the data sent via URL QUERY.
|
|
@@ -71,6 +69,13 @@ export class Request {
|
|
|
71
69
|
UrlObject.searchParams.forEach((value, name) => searchParams[name] = value);
|
|
72
70
|
return searchParams;
|
|
73
71
|
}
|
|
72
|
+
normalizeUrl(url) {
|
|
73
|
+
url = url.split('?')[0];
|
|
74
|
+
url = decodeURI(url.endsWith('/') ? url : url + '/');
|
|
75
|
+
url = url.length > 1 && url.endsWith('/') ? url.slice(0, -1) : url;
|
|
76
|
+
url = url.startsWith('/') ? url : '/' + url;
|
|
77
|
+
return url;
|
|
78
|
+
}
|
|
74
79
|
}
|
|
75
80
|
(function (Request) {
|
|
76
81
|
Request.BodyParser = _BodyParser;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Request.js","sourceRoot":"","sources":["../../src/server/Request.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,OAAO,OAAO;IACnB,oCAAoC;IAC7B,OAAO,CAAkB;IAChC,oCAAoC;IAC7B,OAAO,CAAS;IACvB,
|
|
1
|
+
{"version":3,"file":"Request.js","sourceRoot":"","sources":["../../src/server/Request.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import HTTP from 'http';
|
|
7
7
|
import FS from 'fs';
|
|
8
|
+
import { Readable } from 'stream';
|
|
8
9
|
import Request from './Request.js';
|
|
9
10
|
import Config from './config/Config.js';
|
|
10
11
|
export declare class Response {
|
|
12
|
+
static readonly contentTypeMap: Response.contentTypeMap;
|
|
13
|
+
static readonly acceptRangeFormats: string[];
|
|
14
|
+
private static readonly version;
|
|
11
15
|
/** Contains the request received by the server. */
|
|
12
16
|
request: Request;
|
|
13
17
|
/** Contains the list of server response templates. */
|
|
@@ -21,7 +25,7 @@ export declare class Response {
|
|
|
21
25
|
* @param httpResponse - The response to be sent by the server.
|
|
22
26
|
* @param templates - The list of server response templates.
|
|
23
27
|
*/
|
|
24
|
-
constructor(request: Request, httpResponse: HTTP.ServerResponse, templates
|
|
28
|
+
constructor(request: Request, httpResponse: HTTP.ServerResponse, templates: Config['data']['templates']);
|
|
25
29
|
/** Checks if the response has been sent. */
|
|
26
30
|
get isSended(): boolean;
|
|
27
31
|
/**
|
|
@@ -29,7 +33,7 @@ export declare class Response {
|
|
|
29
33
|
* More types will be supported over time.
|
|
30
34
|
* @param extension - The file extension.
|
|
31
35
|
*/
|
|
32
|
-
generateHeaders(extension: string):
|
|
36
|
+
generateHeaders(extension: string): HTTP.OutgoingHttpHeaders;
|
|
33
37
|
/**
|
|
34
38
|
* Sends response headers.
|
|
35
39
|
* @param code - The HTTP status code.
|
|
@@ -41,7 +45,17 @@ export declare class Response {
|
|
|
41
45
|
* @param data - The data to be sent.
|
|
42
46
|
* @param encode - The encoding used for the response.
|
|
43
47
|
*/
|
|
44
|
-
send(data: Response.data, options?: Response.options): void
|
|
48
|
+
send(data: Response.data, options?: Response.options): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Sends a readable stream as a response.
|
|
51
|
+
* @param data - The readable stream to be sent.
|
|
52
|
+
* @param options - The response options.
|
|
53
|
+
* @throws If an error occurs while sending the stream.
|
|
54
|
+
* @returns A promise that resolves when the stream has been sent.
|
|
55
|
+
* @remarks This method is used for sending large data, such as files or templates, without loading them entirely into memory.
|
|
56
|
+
* It handles backpressure and ensures efficient streaming of data to the client.
|
|
57
|
+
*/
|
|
58
|
+
private sendReadable;
|
|
45
59
|
/**
|
|
46
60
|
* Sends a file as a response.
|
|
47
61
|
* @param path - The file path to send.
|
|
@@ -51,11 +65,11 @@ export declare class Response {
|
|
|
51
65
|
sendFile(path: string, options?: Response.options): Promise<void>;
|
|
52
66
|
/**
|
|
53
67
|
* Sends the listing of a folder as a response.
|
|
54
|
-
* @param
|
|
55
|
-
* @param
|
|
68
|
+
* @param base - The routing rule base path.
|
|
69
|
+
* @param plus - The relative path received in the request.
|
|
56
70
|
* @throws If the folder does not exist or is invalid.
|
|
57
71
|
*/
|
|
58
|
-
sendFolder(
|
|
72
|
+
sendFolder(base: string, plus?: string): Promise<void>;
|
|
59
73
|
/**
|
|
60
74
|
* Sends a `.vhtml` template as a response.
|
|
61
75
|
* @param path - The template file path.
|
|
@@ -69,25 +83,26 @@ export declare class Response {
|
|
|
69
83
|
* @param data - The data to send.
|
|
70
84
|
* @param options - The response options.
|
|
71
85
|
*/
|
|
72
|
-
sendJson(data: any, options?: Response.options): void
|
|
86
|
+
sendJson(data: any, options?: Response.options): Promise<void>;
|
|
73
87
|
/**
|
|
74
88
|
* Sends an error as a response.
|
|
75
89
|
* @param status - The HTTP status code of the error.
|
|
76
90
|
* @param message - The error message.
|
|
77
91
|
*/
|
|
78
92
|
sendError(status: number, message: string): Promise<void>;
|
|
79
|
-
private
|
|
93
|
+
private getFsErrorStatus;
|
|
94
|
+
private static loadVersion;
|
|
80
95
|
}
|
|
81
96
|
export declare namespace Response {
|
|
82
97
|
interface options {
|
|
83
98
|
status?: number;
|
|
84
|
-
headers?:
|
|
99
|
+
headers?: HTTP.OutgoingHttpHeaders;
|
|
85
100
|
encode?: BufferEncoding;
|
|
86
101
|
}
|
|
87
102
|
interface contentTypeMap {
|
|
88
103
|
[key: string]: string | undefined;
|
|
89
104
|
}
|
|
90
|
-
type data = string | Buffer | FS.ReadStream;
|
|
105
|
+
type data = string | Buffer | Readable | FS.ReadStream;
|
|
91
106
|
type Extensions = ('HTML' | 'JS' | 'CSS' | 'JSON' | 'XML' | 'TXT' | 'SVG' | 'PNG' | 'JPG' | 'JPEG' | 'MP3' | 'WAV' | 'MP4');
|
|
92
107
|
}
|
|
93
108
|
export default Response;
|
package/build/server/Response.js
CHANGED
|
@@ -5,11 +5,33 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import FS from 'fs';
|
|
7
7
|
import PATH from 'path';
|
|
8
|
+
import { Readable } from 'stream';
|
|
9
|
+
import { pipeline } from 'stream/promises';
|
|
8
10
|
import Logger from '../logger/Logger.js';
|
|
9
11
|
import Utilities from '../utilities/Utilities.js';
|
|
10
|
-
import Template from '../Template.js';
|
|
12
|
+
import Template from '../Template/Template.js';
|
|
13
|
+
import PathSecurity from './security/PathSecurity.js';
|
|
11
14
|
const logger = new Logger({ prefix: 'Response' });
|
|
12
15
|
export class Response {
|
|
16
|
+
static contentTypeMap = {
|
|
17
|
+
'html': 'text/html',
|
|
18
|
+
'js': 'text/javascript',
|
|
19
|
+
'css': 'text/css',
|
|
20
|
+
'json': 'application/json',
|
|
21
|
+
'xml': 'application/xml',
|
|
22
|
+
'txt': 'text/plain',
|
|
23
|
+
'svg': 'image/svg+xml',
|
|
24
|
+
'png': 'image/png',
|
|
25
|
+
'jpg': 'image/jpeg',
|
|
26
|
+
'jpeg': 'image/jpeg',
|
|
27
|
+
'mp3': 'audio/mpeg',
|
|
28
|
+
'wav': 'audio/x-wav',
|
|
29
|
+
'mp4': 'video/mp4',
|
|
30
|
+
};
|
|
31
|
+
static acceptRangeFormats = [
|
|
32
|
+
'svg', 'png', 'jpg', 'jpeg', 'mp3', 'wav', 'mp4'
|
|
33
|
+
];
|
|
34
|
+
static version = Response.loadVersion();
|
|
13
35
|
/** Contains the request received by the server. */
|
|
14
36
|
request;
|
|
15
37
|
/** Contains the list of server response templates. */
|
|
@@ -23,12 +45,12 @@ export class Response {
|
|
|
23
45
|
* @param httpResponse - The response to be sent by the server.
|
|
24
46
|
* @param templates - The list of server response templates.
|
|
25
47
|
*/
|
|
26
|
-
constructor(request, httpResponse, templates
|
|
48
|
+
constructor(request, httpResponse, templates) {
|
|
27
49
|
this.request = request;
|
|
28
50
|
this.templates = templates;
|
|
29
51
|
this.httpResponse = httpResponse;
|
|
30
52
|
this.httpResponse.setHeader('X-Powered-By', 'MyNetFeez-Labs Vortez');
|
|
31
|
-
this.httpResponse.setHeader('X-Version',
|
|
53
|
+
this.httpResponse.setHeader('X-Version', Response.version);
|
|
32
54
|
}
|
|
33
55
|
/** Checks if the response has been sent. */
|
|
34
56
|
get isSended() { return this._isSended || this.httpResponse.writableEnded || this.httpResponse.headersSent; }
|
|
@@ -41,28 +63,10 @@ export class Response {
|
|
|
41
63
|
extension = extension.startsWith('.') ? extension.slice(1) : extension;
|
|
42
64
|
extension = extension.toLowerCase();
|
|
43
65
|
const headers = {};
|
|
44
|
-
const
|
|
45
|
-
'html': 'text/html',
|
|
46
|
-
'js': 'text/javascript',
|
|
47
|
-
'css': 'text/css',
|
|
48
|
-
'json': 'application/json',
|
|
49
|
-
'xml': 'application/xml',
|
|
50
|
-
'txt': 'text/plain',
|
|
51
|
-
'svg': 'image/svg+xml',
|
|
52
|
-
'png': 'image/png',
|
|
53
|
-
'jpg': 'image/jpeg',
|
|
54
|
-
'jpeg': 'image/jpeg',
|
|
55
|
-
'mp3': 'audio/mpeg',
|
|
56
|
-
'wav': 'audio/x-wav',
|
|
57
|
-
'mp4': 'video/mp4',
|
|
58
|
-
};
|
|
59
|
-
const acceptRangeFormats = [
|
|
60
|
-
'svg', 'png', 'jpg', 'jpeg', 'mp3', 'wav', 'mp4'
|
|
61
|
-
];
|
|
62
|
-
const type = contentTypeMap[extension];
|
|
66
|
+
const type = Response.contentTypeMap[extension];
|
|
63
67
|
if (type)
|
|
64
|
-
headers['Content-Type'] = type;
|
|
65
|
-
if (acceptRangeFormats.includes(extension)) {
|
|
68
|
+
headers['Content-Type'] = type ?? 'application/octet-stream';
|
|
69
|
+
if (Response.acceptRangeFormats.includes(extension)) {
|
|
66
70
|
headers['Accept-Ranges'] = 'bytes';
|
|
67
71
|
}
|
|
68
72
|
return headers;
|
|
@@ -83,16 +87,32 @@ export class Response {
|
|
|
83
87
|
* @param data - The data to be sent.
|
|
84
88
|
* @param encode - The encoding used for the response.
|
|
85
89
|
*/
|
|
86
|
-
send(data, options = {}) {
|
|
90
|
+
async send(data, options = {}) {
|
|
91
|
+
if (data instanceof Readable)
|
|
92
|
+
return await this.sendReadable(data, options);
|
|
87
93
|
this._isSended = true;
|
|
88
94
|
const status = options.status ?? 200;
|
|
89
95
|
const encode = options.encode || 'utf-8';
|
|
90
96
|
const headers = options.headers || this.generateHeaders('txt');
|
|
91
97
|
this.sendHeaders(status, headers);
|
|
92
|
-
if (data instanceof FS.ReadStream)
|
|
93
|
-
return void data.pipe(this.httpResponse);
|
|
94
98
|
this.httpResponse.end(data, encode);
|
|
95
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Sends a readable stream as a response.
|
|
102
|
+
* @param data - The readable stream to be sent.
|
|
103
|
+
* @param options - The response options.
|
|
104
|
+
* @throws If an error occurs while sending the stream.
|
|
105
|
+
* @returns A promise that resolves when the stream has been sent.
|
|
106
|
+
* @remarks This method is used for sending large data, such as files or templates, without loading them entirely into memory.
|
|
107
|
+
* It handles backpressure and ensures efficient streaming of data to the client.
|
|
108
|
+
*/
|
|
109
|
+
async sendReadable(data, options) {
|
|
110
|
+
this._isSended = true;
|
|
111
|
+
const status = options.status ?? 200;
|
|
112
|
+
const headers = options.headers || this.generateHeaders('txt');
|
|
113
|
+
await this.sendHeaders(status, headers);
|
|
114
|
+
await pipeline(data, this.httpResponse);
|
|
115
|
+
}
|
|
96
116
|
/**
|
|
97
117
|
* Sends a file as a response.
|
|
98
118
|
* @param path - The file path to send.
|
|
@@ -104,76 +124,118 @@ export class Response {
|
|
|
104
124
|
try {
|
|
105
125
|
const details = await FS.promises.stat(path);
|
|
106
126
|
if (!details.isFile())
|
|
107
|
-
return this.sendError(500, '[Response Error] - Provided path is not a file.');
|
|
127
|
+
return await this.sendError(500, '[Response Error] - Provided path is not a file.');
|
|
108
128
|
if (!this.request.headers.range) {
|
|
109
129
|
const stream = FS.createReadStream(path);
|
|
110
130
|
const headers = this.generateHeaders(PATH.extname(path));
|
|
111
131
|
headers['content-length'] = details.size.toString();
|
|
112
|
-
this.send(stream, { status: 200, headers });
|
|
132
|
+
await this.send(stream, { status: 200, headers });
|
|
113
133
|
}
|
|
114
134
|
else {
|
|
115
|
-
const
|
|
135
|
+
const rangeHeader = this.request.headers.range;
|
|
136
|
+
const info = /^bytes=(\d*)-(\d*)$/i.exec(rangeHeader);
|
|
116
137
|
if (!info)
|
|
117
|
-
return this.sendError(416, 'Requested range exceeds file size');
|
|
118
|
-
const [startString, endString] = info
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
138
|
+
return await this.sendError(416, 'Requested range exceeds file size');
|
|
139
|
+
const [, startString, endString] = info;
|
|
140
|
+
let start;
|
|
141
|
+
let end;
|
|
142
|
+
if (startString && endString) {
|
|
143
|
+
start = Number(startString);
|
|
144
|
+
end = Number(endString);
|
|
145
|
+
}
|
|
146
|
+
else if (startString) {
|
|
147
|
+
start = Number(startString);
|
|
148
|
+
const maxSize = start + 1024 * 1000;
|
|
149
|
+
end = maxSize >= details.size ? details.size - 1 : maxSize;
|
|
150
|
+
}
|
|
151
|
+
else if (endString) {
|
|
152
|
+
const suffixSize = Number(endString);
|
|
153
|
+
if (!Number.isInteger(suffixSize) || suffixSize <= 0) {
|
|
154
|
+
return await this.sendError(416, 'Requested range exceeds file size');
|
|
155
|
+
}
|
|
156
|
+
start = Math.max(details.size - suffixSize, 0);
|
|
157
|
+
end = details.size - 1;
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
return await this.sendError(416, 'Requested range exceeds file size');
|
|
161
|
+
if (!Number.isInteger(start) ||
|
|
162
|
+
!Number.isInteger(end) ||
|
|
163
|
+
start < 0 ||
|
|
164
|
+
end < start ||
|
|
165
|
+
start >= details.size ||
|
|
166
|
+
end >= details.size)
|
|
167
|
+
return await this.sendError(416, 'Requested range exceeds file size');
|
|
130
168
|
const size = end - start + 1;
|
|
131
169
|
const stream = FS.createReadStream(path, { start, end });
|
|
132
170
|
const headers = this.generateHeaders(PATH.extname(path));
|
|
133
171
|
headers['content-length'] = size.toString();
|
|
134
172
|
headers['content-range'] = `bytes ${start}-${end}/${details.size}`;
|
|
135
|
-
this.send(stream, { status: 206, headers });
|
|
173
|
+
await this.send(stream, { status: 206, headers });
|
|
136
174
|
}
|
|
137
175
|
}
|
|
138
176
|
catch (error) {
|
|
139
|
-
this.
|
|
177
|
+
const status = this.getFsErrorStatus(error);
|
|
178
|
+
const message = status === 404
|
|
179
|
+
? 'The requested URL was not found'
|
|
180
|
+
: status === 403
|
|
181
|
+
? 'Access denied to requested resource'
|
|
182
|
+
: error instanceof Error
|
|
183
|
+
? error.message
|
|
184
|
+
: '[Response Error] - File does not exist.';
|
|
185
|
+
await this.sendError(status, message);
|
|
140
186
|
logger.error(`error sending file ${this.request.session.id}`, error);
|
|
141
187
|
}
|
|
142
188
|
}
|
|
143
189
|
/**
|
|
144
190
|
* Sends the listing of a folder as a response.
|
|
145
|
-
* @param
|
|
146
|
-
* @param
|
|
191
|
+
* @param base - The routing rule base path.
|
|
192
|
+
* @param plus - The relative path received in the request.
|
|
147
193
|
* @throws If the folder does not exist or is invalid.
|
|
148
194
|
*/
|
|
149
|
-
async sendFolder(
|
|
150
|
-
basePath =
|
|
151
|
-
|
|
152
|
-
|
|
195
|
+
async sendFolder(base, plus = '') {
|
|
196
|
+
const basePath = Utilities.Path.resolve(base || Utilities.Path.rootDir);
|
|
197
|
+
const path = await PathSecurity.resolveInsideBase(basePath, plus);
|
|
198
|
+
if (!path) {
|
|
199
|
+
logger.warn(`&C2[Vortez Security] &C3Intento de Path Traversal bloqueado:`);
|
|
200
|
+
logger.warn(` &C3- IP: &C6${this.request.ip}`);
|
|
201
|
+
logger.warn(` &C3- Session ID: &C6${this.request.session.id}`);
|
|
202
|
+
logger.warn(` &C3- URL: &C6${this.request.url}`);
|
|
203
|
+
logger.warn(` &C3- Base: &C6${basePath}`);
|
|
204
|
+
logger.warn(` &C3- Intento: &C6${plus}`);
|
|
205
|
+
return void await this.sendError(403, 'Forbidden: Outside of sandbox');
|
|
206
|
+
}
|
|
153
207
|
try {
|
|
154
|
-
if (!await
|
|
155
|
-
return void this.sendError(404, 'The requested URL was not
|
|
208
|
+
if (!await Utilities.File.exists(path))
|
|
209
|
+
return void await this.sendError(404, 'The requested URL was not found');
|
|
156
210
|
const details = await FS.promises.stat(path);
|
|
157
211
|
if (details.isFile())
|
|
158
|
-
return this.sendFile(path);
|
|
212
|
+
return await this.sendFile(path);
|
|
159
213
|
if (!details.isDirectory())
|
|
160
|
-
return this.sendError(404, 'The requested URL was not
|
|
214
|
+
return await this.sendError(404, 'The requested URL was not found');
|
|
161
215
|
const folder = await FS.promises.readdir(path);
|
|
162
216
|
if (this.templates.folder) {
|
|
163
|
-
this.sendTemplate(this.templates.folder, {
|
|
217
|
+
await this.sendTemplate(this.templates.folder, {
|
|
164
218
|
Url: this.request.url,
|
|
165
219
|
folder
|
|
166
220
|
});
|
|
167
221
|
}
|
|
168
222
|
else {
|
|
169
|
-
this.sendTemplate(Utilities.Path.
|
|
223
|
+
await this.sendTemplate(Utilities.Path.module('global/template/folder.vhtml'), {
|
|
170
224
|
Url: this.request.url,
|
|
171
225
|
folder
|
|
172
226
|
});
|
|
173
227
|
}
|
|
174
228
|
}
|
|
175
229
|
catch (error) {
|
|
176
|
-
this.
|
|
230
|
+
const status = this.getFsErrorStatus(error);
|
|
231
|
+
const message = status === 404
|
|
232
|
+
? 'The requested URL was not found'
|
|
233
|
+
: status === 403
|
|
234
|
+
? 'Access denied to requested resource'
|
|
235
|
+
: error instanceof Error
|
|
236
|
+
? error.message
|
|
237
|
+
: '[Response Error] - File/Directory does not exist.';
|
|
238
|
+
await this.sendError(status, message);
|
|
177
239
|
logger.error(`error sending folder ${this.request.session.id}`, error);
|
|
178
240
|
}
|
|
179
241
|
}
|
|
@@ -187,13 +249,23 @@ export class Response {
|
|
|
187
249
|
async sendTemplate(path, data, options = {}) {
|
|
188
250
|
path = Utilities.Path.normalize(path);
|
|
189
251
|
try {
|
|
190
|
-
const template = await Template.
|
|
252
|
+
const template = await Template.stream(path, data);
|
|
191
253
|
const status = options.status ?? 200;
|
|
192
254
|
const headers = options.headers || this.generateHeaders('html');
|
|
193
|
-
this.send(template, { status, headers });
|
|
255
|
+
await this.send(template, { status, headers, encode: options.encode });
|
|
194
256
|
}
|
|
195
257
|
catch (error) {
|
|
196
|
-
this.
|
|
258
|
+
const status = this.getFsErrorStatus(error);
|
|
259
|
+
const message = status === 404
|
|
260
|
+
? 'Template not found'
|
|
261
|
+
: status === 403
|
|
262
|
+
? 'Access denied to template resource'
|
|
263
|
+
: error instanceof Error
|
|
264
|
+
? error.message
|
|
265
|
+
: '[Response Error] - Template does not exist.';
|
|
266
|
+
if (!this.httpResponse.headersSent && !this.httpResponse.writableEnded) {
|
|
267
|
+
await this.sendError(status, message);
|
|
268
|
+
}
|
|
197
269
|
logger.error(`error sending template ${this.request.session.id}`, error);
|
|
198
270
|
}
|
|
199
271
|
}
|
|
@@ -202,15 +274,15 @@ export class Response {
|
|
|
202
274
|
* @param data - The data to send.
|
|
203
275
|
* @param options - The response options.
|
|
204
276
|
*/
|
|
205
|
-
sendJson(data, options = {}) {
|
|
277
|
+
async sendJson(data, options = {}) {
|
|
206
278
|
try {
|
|
207
279
|
const json = JSON.stringify(data);
|
|
208
280
|
const status = options.status ?? 200;
|
|
209
281
|
const headers = options.headers || this.generateHeaders('json');
|
|
210
|
-
this.send(json, { status, headers });
|
|
282
|
+
await this.send(json, { status, headers });
|
|
211
283
|
}
|
|
212
284
|
catch (error) {
|
|
213
|
-
this.sendError(500, error instanceof Error ? error.message : '[Response Error] - Data cannot be converted to JSON.');
|
|
285
|
+
await this.sendError(500, error instanceof Error ? error.message : '[Response Error] - Data cannot be converted to JSON.');
|
|
214
286
|
logger.error(`error sending json ${this.request.session.id}`, error);
|
|
215
287
|
}
|
|
216
288
|
}
|
|
@@ -226,31 +298,45 @@ export class Response {
|
|
|
226
298
|
status, message
|
|
227
299
|
});
|
|
228
300
|
const headers = this.generateHeaders('html');
|
|
229
|
-
this.send(template, { status: status, headers });
|
|
301
|
+
await this.send(template, { status: status, headers });
|
|
230
302
|
}
|
|
231
303
|
else {
|
|
232
|
-
const template = await Template.load(Utilities.Path.
|
|
304
|
+
const template = await Template.load(Utilities.Path.module('global/template/error.vhtml'), {
|
|
233
305
|
status, message
|
|
234
306
|
});
|
|
235
307
|
const headers = this.generateHeaders('html');
|
|
236
|
-
this.send(template, { status: status, headers });
|
|
308
|
+
await this.send(template, { status: status, headers });
|
|
237
309
|
}
|
|
238
310
|
}
|
|
239
311
|
catch (error) {
|
|
240
|
-
console.error(error);
|
|
241
312
|
const headers = this.generateHeaders('txt');
|
|
242
|
-
this.send(`Error: ${status} -> ${message}`, { status: status, headers });
|
|
313
|
+
await this.send(`Error: ${status} -> ${message}`, { status: status, headers });
|
|
243
314
|
logger.error(`error sending error: ${this.request.session.id}`, error);
|
|
244
315
|
}
|
|
245
316
|
}
|
|
246
|
-
|
|
317
|
+
getFsErrorStatus(error) {
|
|
318
|
+
if (!(error instanceof Error))
|
|
319
|
+
return 500;
|
|
320
|
+
const withCode = error;
|
|
321
|
+
if (withCode.code === 'ENOENT' || withCode.code === 'ENOTDIR')
|
|
322
|
+
return 404;
|
|
323
|
+
if (withCode.code === 'EACCES' || withCode.code === 'EPERM')
|
|
324
|
+
return 403;
|
|
325
|
+
return 500;
|
|
326
|
+
}
|
|
327
|
+
static loadVersion() {
|
|
328
|
+
const envVersion = process.env.npm_package_version;
|
|
329
|
+
if (envVersion)
|
|
330
|
+
return envVersion;
|
|
247
331
|
try {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
332
|
+
const packagePath = Utilities.Path.module('package.json');
|
|
333
|
+
const raw = FS.readFileSync(packagePath, 'utf8');
|
|
334
|
+
const data = JSON.parse(raw);
|
|
335
|
+
if (typeof data.version === 'string' && data.version.length > 0)
|
|
336
|
+
return data.version;
|
|
253
337
|
}
|
|
338
|
+
catch { }
|
|
339
|
+
return 'unknown';
|
|
254
340
|
}
|
|
255
341
|
}
|
|
256
342
|
export default Response;
|