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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanta-api",
3
- "version": "1.1.5",
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"
@@ -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.toLowerCase() : opt.path.toLowerCase();
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
- _parseQueryFilters() {
219
- const obj = { ...this.query };
220
- ["page", "limit", "sort", "fields", "populate"].forEach(
221
- (k) => delete obj[k]
222
- );
223
-
224
- // Whitelist operators
225
- const out = {};
226
- for (const [k, v] of Object.entries(obj)) {
227
- if (["or", "and"].includes(k)) {
228
- out[`$${k}`] = Array.isArray(v) ? v : [v];
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[k] = typeof v === "string" && v.includes(",") ? v.split(",") : v;
247
+ out[rawKey] = rawVal;
231
248
  }
232
249
  }
233
- return out;
234
250
  }
235
251
 
236
- _sanitizeFilters(filters) {
237
- // Simple deep clone with ObjectId and boolean parsing
252
+ return out;
253
+ }
254
+
255
+
256
+ _sanitizeFilters(filters) {
238
257
  return JSON.parse(JSON.stringify(filters), (key, val) => {
239
- if (key.endsWith("Id") && mongoose.isValidObjectId(val))
240
- return new mongoose.Types.ObjectId(val);
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
- if (/^[0-9]+$/.test(val)) return parseInt(val, 10);
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
@@ -8,7 +8,6 @@ try {
8
8
  const userPath = path.resolve(process.cwd(), "security-config.js");
9
9
  userConfig = (await import(userPath))?.securityConfig || {};
10
10
  } catch (err) {
11
- // کاربر security-config نداشت، مشکلی نیست
12
11
  }
13
12
 
14
13
  export const securityConfig = {