vanta-api 1.1.5 → 1.1.7
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/package.json +2 -1
- package/src/api-features.js +71 -19
- package/src/config.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanta-api",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "Advanced API features and security configuration for Node.js/MongoDB.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"author": "Alireza Aghaee",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"bson": "^6.10.3",
|
|
22
23
|
"mongoose": "^7.0.0",
|
|
23
24
|
"pluralize": "^8.0.0",
|
|
24
25
|
"winston": "^3.0.0"
|
package/src/api-features.js
CHANGED
|
@@ -117,7 +117,7 @@ export class ApiFeatures {
|
|
|
117
117
|
|
|
118
118
|
// Apply lookups
|
|
119
119
|
for (const opt of final) {
|
|
120
|
-
const field = typeof opt === 'string' ? opt
|
|
120
|
+
const field = typeof opt === 'string' ? opt : opt.path;
|
|
121
121
|
const proj =
|
|
122
122
|
typeof opt === "object" && opt.select
|
|
123
123
|
? opt.select.split(" ").reduce((a, f) => {
|
|
@@ -215,35 +215,87 @@ export class ApiFeatures {
|
|
|
215
215
|
});
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
218
|
+
_parseQueryFilters() {
|
|
219
|
+
const obj = { ...this.query };
|
|
220
|
+
// پاک کردن پارامترهای سیستماتیک
|
|
221
|
+
["page", "limit", "sort", "fields", "populate"].forEach(k => delete obj[k]);
|
|
222
|
+
|
|
223
|
+
const out = {};
|
|
224
|
+
|
|
225
|
+
for (const [rawKey, rawVal] of Object.entries(obj)) {
|
|
226
|
+
if (typeof rawVal === 'object' && !Array.isArray(rawVal)) {
|
|
227
|
+
out[rawKey] = {};
|
|
228
|
+
for (let [op, val] of Object.entries(rawVal)) {
|
|
229
|
+
const cleanOp = op.replace(/^\$/, '');
|
|
230
|
+
if (securityConfig.allowedOperators.includes(cleanOp)) {
|
|
231
|
+
const v = /^[0-9]+$/.test(val) ? parseInt(val, 10) : val;
|
|
232
|
+
out[rawKey][`$${cleanOp}`] = v;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (/^\w+\[\$?\w+\]$/.test(rawKey)) {
|
|
237
|
+
const [, field, op] = rawKey.match(/^(\w+)\[\$?(\w+)\]$/);
|
|
238
|
+
if (securityConfig.allowedOperators.includes(op)) {
|
|
239
|
+
const v = /^[0-9]+$/.test(rawVal) ? parseInt(rawVal, 10) : rawVal;
|
|
240
|
+
out[field] = { [`$${op}`]: v };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
if (typeof rawVal === "string" && rawVal.includes(",")) {
|
|
245
|
+
out[rawKey] = rawVal.split(",");
|
|
229
246
|
} else {
|
|
230
|
-
out[
|
|
247
|
+
out[rawKey] = rawVal;
|
|
231
248
|
}
|
|
232
249
|
}
|
|
233
|
-
return out;
|
|
234
250
|
}
|
|
235
251
|
|
|
236
|
-
|
|
237
|
-
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
_sanitizeFilters(filters) {
|
|
238
257
|
return JSON.parse(JSON.stringify(filters), (key, val) => {
|
|
239
|
-
|
|
240
|
-
|
|
258
|
+
// اگر val شیئی حاوی $eq یا eq باشد و آن فیلد ObjectId معتبر باشد
|
|
259
|
+
if (
|
|
260
|
+
typeof val === 'object' &&
|
|
261
|
+
val !== null &&
|
|
262
|
+
(this.#isStrictObjectId(val['$eq']) || this.#isStrictObjectId(val['eq']))
|
|
263
|
+
) {
|
|
264
|
+
const newVal = { ...val };
|
|
265
|
+
if (this.#isStrictObjectId(val['$eq'])) {
|
|
266
|
+
newVal['$eq'] = new mongoose.Types.ObjectId(val['$eq']);
|
|
267
|
+
}
|
|
268
|
+
if (this.#isStrictObjectId(val['eq'])) {
|
|
269
|
+
newVal['eq'] = new mongoose.Types.ObjectId(val['eq']);
|
|
270
|
+
}
|
|
271
|
+
return newVal;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// تبدیل true/false
|
|
241
275
|
if (val === "true") return true;
|
|
242
276
|
if (val === "false") return false;
|
|
243
|
-
|
|
277
|
+
|
|
278
|
+
// تبدیل عدد صحیح
|
|
279
|
+
if (typeof val === 'string' && /^[0-9]+$/.test(val)) return parseInt(val, 10);
|
|
280
|
+
|
|
281
|
+
// اگر val یک رشته است و ObjectId معتبر باشد، به ObjectId تبدیل شود
|
|
282
|
+
if (
|
|
283
|
+
typeof val === 'string' &&
|
|
284
|
+
this.#isStrictObjectId(val)
|
|
285
|
+
) {
|
|
286
|
+
return new mongoose.Types.ObjectId(val);
|
|
287
|
+
}
|
|
288
|
+
|
|
244
289
|
return val;
|
|
245
290
|
});
|
|
246
291
|
}
|
|
292
|
+
#isStrictObjectId(id) {
|
|
293
|
+
return (
|
|
294
|
+
typeof id === 'string' &&
|
|
295
|
+
mongoose.Types.ObjectId.isValid(id) &&
|
|
296
|
+
(new mongoose.Types.ObjectId(id)).toString() === id
|
|
297
|
+
);
|
|
298
|
+
}
|
|
247
299
|
|
|
248
300
|
_applySecurityFilters(filters) {
|
|
249
301
|
let res = { ...filters };
|
package/src/config.js
CHANGED