turbo-express-js 1.0.11 → 1.0.12
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 +5 -1
- package/index.test.js +5 -2
- package/lib/middlewares/cors_middleware.js +31 -7
- package/lib/services/FormDataService.js +104 -6
- package/package.json +1 -1
package/changelog.md
CHANGED
package/index.test.js
CHANGED
|
@@ -6,6 +6,9 @@ const app = new TurboExpress();
|
|
|
6
6
|
|
|
7
7
|
// console.log("testing development...")
|
|
8
8
|
|
|
9
|
-
app.get("
|
|
9
|
+
app.get("/", ()=>{ })
|
|
10
|
+
app.post("/test", TurboExpress.Cors({ origins: ["*"] }), async (req, res) => {
|
|
11
|
+
res.json({ query: req.queriesObj(), params: req.paramsObj(), body: await req.body() })
|
|
12
|
+
})
|
|
10
13
|
|
|
11
|
-
app.listen(
|
|
14
|
+
app.listen(3000, () => console.log("Service is running"));
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @PerfecTEvolutioN
|
|
5
5
|
* @project - TurboExpress
|
|
6
6
|
* @name TurboExpress
|
|
7
|
-
* @namespace TurboExpress::middlewares::
|
|
7
|
+
* @namespace TurboExpress::middlewares::cors_middleware
|
|
8
8
|
* @license - MIT
|
|
9
9
|
* @author - Mike Karypidis
|
|
10
10
|
* @version - 1.0.0
|
|
@@ -23,14 +23,34 @@ const ResponseInterface = require("../types/ResponseInterface");
|
|
|
23
23
|
* @param {ResponseInterface} res
|
|
24
24
|
* @param {*} next
|
|
25
25
|
*/
|
|
26
|
-
module.exports = function cors_middleware
|
|
26
|
+
module.exports = function cors_middleware(req, res, next)
|
|
27
27
|
{
|
|
28
|
-
const
|
|
28
|
+
const config = this || {};
|
|
29
|
+
const origins = Array.isArray(config.origins) && config.origins.length ? config.origins : ["*"];
|
|
30
|
+
const methods = Array.isArray(config.methods) && config.methods.length ? config.methods : ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE", "OPTIONS"];
|
|
31
|
+
const headers = Array.isArray(config.headers) ? config.headers : [];
|
|
32
|
+
const credentials = config.credentials === true;
|
|
33
|
+
const maxAge = Number.isSafeInteger(config.maxAge) ? config.maxAge : 3600;
|
|
34
|
+
|
|
35
|
+
const requestHeaders = req.headers();
|
|
36
|
+
const requestOrigin = requestHeaders.origin;
|
|
37
|
+
const requestedHeaders = requestHeaders["access-control-request-headers"];
|
|
38
|
+
const requestMethod = String(req.IncomingMessage?.method || "GET").toUpperCase();
|
|
39
|
+
const wildcard = origins.includes("*");
|
|
40
|
+
|
|
41
|
+
if(requestOrigin && !wildcard && !origins.includes(requestOrigin)) return next();
|
|
42
|
+
|
|
43
|
+
if(wildcard && !credentials) {
|
|
44
|
+
res.header("Access-Control-Allow-Origin", "*");
|
|
45
|
+
} else if(requestOrigin) {
|
|
46
|
+
res.header("Access-Control-Allow-Origin", requestOrigin);
|
|
47
|
+
res.header("Vary", "Origin");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if(credentials) res.header("Access-Control-Allow-Credentials", "true");
|
|
29
51
|
|
|
30
|
-
res.header("Access-Control-Allow-Origin", origins.join(","));
|
|
31
|
-
res.header("Access-Control-Allow-Credentials", credentials);
|
|
32
52
|
res.header("Access-Control-Allow-Methods", methods.join(","));
|
|
33
|
-
res.header("Access-Control-Max-Age",
|
|
53
|
+
res.header("Access-Control-Max-Age", String(maxAge));
|
|
34
54
|
|
|
35
55
|
let allowedHeaders = "";
|
|
36
56
|
const headers_req = req.headers();
|
|
@@ -45,6 +65,10 @@ module.exports = function cors_middleware (req, res, next)
|
|
|
45
65
|
0, (allowedHeaders + headers.join(",")).length - 1
|
|
46
66
|
));
|
|
47
67
|
|
|
48
|
-
|
|
68
|
+
if(requestMethod === "OPTIONS") {
|
|
69
|
+
res.status(204);
|
|
70
|
+
return res.send("");
|
|
71
|
+
}
|
|
49
72
|
|
|
73
|
+
return next();
|
|
50
74
|
}
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
const multiparty = require("multiparty")
|
|
20
20
|
const FileType = require("../types/FileType");
|
|
21
21
|
|
|
22
|
+
const INTEGER_PATTERN = /^-?(?:0|[1-9]\d*)$/;
|
|
23
|
+
const DECIMAL_PATTERN = /^-?(?:0|[1-9]\d*)\.\d+(?:[eE][+-]?\d+)?$/;
|
|
24
|
+
const SCIENTIFIC_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?[eE][+-]?\d+$/;
|
|
25
|
+
const MAX_JSON_FIELD_LENGTH = 1024 * 1024; // 1 MB
|
|
22
26
|
|
|
23
27
|
module.exports = class FormDataService
|
|
24
28
|
{
|
|
@@ -71,16 +75,110 @@ module.exports = class FormDataService
|
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
|
|
74
|
-
#getValueByType
|
|
78
|
+
#getValueByType(value)
|
|
75
79
|
{
|
|
76
|
-
|
|
77
|
-
if
|
|
78
|
-
if(value
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
// Multiparty normally returns strings, but do not destroy
|
|
81
|
+
// unexpected values if its behavior changes in the future.
|
|
82
|
+
if (typeof value !== "string") {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Preserve empty strings and whitespace exactly.
|
|
87
|
+
if (value === "" || value.trim() === "") {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Do not trim before conversion. Whitespace may be meaningful.
|
|
92
|
+
if (value !== value.trim()) {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const normalized = value.toLowerCase();
|
|
97
|
+
|
|
98
|
+
switch (normalized) {
|
|
99
|
+
case "true":
|
|
100
|
+
return true;
|
|
101
|
+
|
|
102
|
+
case "false":
|
|
103
|
+
return false;
|
|
104
|
+
|
|
105
|
+
case "null":
|
|
106
|
+
case "nil":
|
|
107
|
+
return null;
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Strict integer conversion.
|
|
114
|
+
if (INTEGER_PATTERN.test(value)) {
|
|
115
|
+
const parsed = Number(value);
|
|
116
|
+
|
|
117
|
+
// Prevent database identifiers and large integers from being corrupted.
|
|
118
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// "-0" has special behavior in JavaScript; preserve it as entered.
|
|
123
|
+
if (Object.is(parsed, -0)) {
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return parsed;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Strict decimal and scientific-notation conversion.
|
|
131
|
+
if (
|
|
132
|
+
DECIMAL_PATTERN.test(value) ||
|
|
133
|
+
SCIENTIFIC_PATTERN.test(value)
|
|
134
|
+
) {
|
|
135
|
+
const parsed = Number(value);
|
|
136
|
+
|
|
137
|
+
if (!Number.isFinite(parsed)) {
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Avoid converting high-precision decimal values that Number
|
|
142
|
+
// cannot represent reliably.
|
|
143
|
+
if (this.#countSignificantDigits(value) > 15) {
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return parsed;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Parse explicitly structured JSON values.
|
|
151
|
+
if (
|
|
152
|
+
value.length <= MAX_JSON_FIELD_LENGTH &&
|
|
153
|
+
(
|
|
154
|
+
(value.startsWith("{") && value.endsWith("}")) ||
|
|
155
|
+
(value.startsWith("[") && value.endsWith("]"))
|
|
156
|
+
)
|
|
157
|
+
) {
|
|
158
|
+
try {
|
|
159
|
+
return JSON.parse(value);
|
|
160
|
+
} catch {
|
|
161
|
+
// Invalid JSON remains the original string.
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Dates, UUIDs, AFMs, phone numbers, postal codes,
|
|
167
|
+
// hexadecimal values and ordinary text remain strings.
|
|
81
168
|
return value;
|
|
82
169
|
}
|
|
83
170
|
|
|
171
|
+
#countSignificantDigits(value)
|
|
172
|
+
{
|
|
173
|
+
const coefficient = value
|
|
174
|
+
.replace(/^[+-]/, "")
|
|
175
|
+
.split(/[eE]/, 1)[0]
|
|
176
|
+
.replace(".", "")
|
|
177
|
+
.replace(/^0+/, "");
|
|
178
|
+
|
|
179
|
+
return coefficient.length;
|
|
180
|
+
}
|
|
181
|
+
|
|
84
182
|
}
|
|
85
183
|
|
|
86
184
|
|