spice-js 2.6.6 → 2.6.8

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.
@@ -16,7 +16,11 @@ function _connect() {
16
16
 
17
17
  for (var key of Object.keys(spice.config.cache.providers)) {
18
18
  spice.cache_providers[key] = new spice.config.cache.providers[key](spice.config.cache.drivers[key] || {});
19
- spice.cache_providers[key].initialize();
19
+ spice.cache_providers[key].initialize().then(() => {
20
+ console.log("Redis initialized successfully");
21
+ }).catch(err => {
22
+ console.error("Error initializing Redis:", err);
23
+ });
20
24
  }
21
25
  } catch (e) {
22
26
  console.log(e.stack);
@@ -7,6 +7,8 @@ var _2 = require("..");
7
7
 
8
8
  var _ResourceLifecycleTriggered = _interopRequireDefault(require("../events/events/ResourceLifecycleTriggered"));
9
9
 
10
+ var _Security = require("../utility/Security");
11
+
10
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
13
 
12
14
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -29,6 +31,7 @@ var SDate = require("sonover-date"),
29
31
  _hooks = Symbol(),
30
32
  _disable_lifecycle_events = Symbol(),
31
33
  _external_modifier_loaded = Symbol(),
34
+ _skip_cache = Symbol(),
32
35
  _serializers = Symbol(); //const _type = Symbol("type");
33
36
 
34
37
 
@@ -51,7 +54,7 @@ class SpiceModel {
51
54
  }
52
55
 
53
56
  try {
54
- var _args$args, _args2, _args2$args;
57
+ var _args$args, _args2, _args2$args, _args3, _args3$args;
55
58
 
56
59
  var dbtype = spice.config.database.connections[args.connection].type || "couchbase";
57
60
 
@@ -63,6 +66,7 @@ class SpiceModel {
63
66
  this[_external_modifier_loaded] = false;
64
67
  this[_disable_lifecycle_events] = ((_args$args = args.args) == null ? void 0 : _args$args.disable_lifecycle_events) || false;
65
68
  this[_ctx] = (_args2 = args) == null ? void 0 : (_args2$args = _args2.args) == null ? void 0 : _args2$args.ctx;
69
+ this[_skip_cache] = ((_args3 = args) == null ? void 0 : (_args3$args = _args3.args) == null ? void 0 : _args3$args.skip_cache) || false;
66
70
  this[_hooks] = {
67
71
  create: {
68
72
  before: [],
@@ -432,10 +436,23 @@ class SpiceModel {
432
436
  return return_string;
433
437
  }
434
438
 
435
- shouldCache(resource_type) {
436
- var _spice$systemconfig, _spice$systemconfig$c;
439
+ shouldUseCache(resource_type) {
440
+ var _spice$config$cache;
441
+
442
+ // If '_skip_cache' property of this object is true, then we shouldn't cache.
443
+ if (this[_skip_cache] == true) {
444
+ return false;
445
+ } // If the system configuration for spice has a cache status set to "disable",
446
+ // then we shouldn't cache, so return false.
447
+
437
448
 
438
- return spice.cache[resource_type] != undefined || ((_spice$systemconfig = spice.systemconfig) == null ? void 0 : (_spice$systemconfig$c = _spice$systemconfig.cache) == null ? void 0 : _spice$systemconfig$c.status) == "disable";
449
+ if (((_spice$config$cache = spice.config.cache) == null ? void 0 : _spice$config$cache.status) == "disabled") {
450
+ return false;
451
+ } // If 'spice.cache[resource_type]' is not undefined,
452
+ // it implies that this resource type is already in the cache or is cacheable.
453
+
454
+
455
+ return spice.cache[resource_type] != undefined;
439
456
  }
440
457
 
441
458
  getCacheConfig(resource_type) {
@@ -480,11 +497,13 @@ class SpiceModel {
480
497
  setMonitor() {
481
498
  var current_time = new Date().getTime();
482
499
  var obj = this.getCacheProviderObject();
483
- obj.set("monitor::" + this.type, {
500
+ var key = "monitor::" + this.type;
501
+ var value = {
484
502
  time: current_time
485
- }, {
503
+ };
504
+ obj.set(key, value, {
486
505
  ttl: 0
487
- }); //console.log("Monitor Set", spice.monitor);
506
+ });
488
507
  }
489
508
 
490
509
  get(args) {
@@ -497,11 +516,14 @@ class SpiceModel {
497
516
  }
498
517
 
499
518
  if (_.isString(args.id)) {
500
- yield _this4.run_hook(args, "get", "before");
519
+ if (args.skip_hooks != true) {
520
+ yield _this4.run_hook(args, "get", "before");
521
+ }
522
+
501
523
  var key = _this4.type + "::" + args.id;
502
524
  var results = {};
503
525
 
504
- if (_this4.shouldCache(_this4.type)) {
526
+ if (_this4.shouldUseCache(_this4.type)) {
505
527
  var cached_results = yield _this4.getCacheProviderObject(_this4.type).get(key);
506
528
  results = cached_results == null ? void 0 : cached_results.value;
507
529
 
@@ -525,8 +547,14 @@ class SpiceModel {
525
547
  }
526
548
 
527
549
  if (results.deleted == undefined || results.deleted == false) {
528
- yield _this4.run_hook(results, "get", "after");
529
- results = yield _this4.do_serialize(results, "read", {}, args, (yield _this4.propsToBeRemoved(results)));
550
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
551
+ results = yield _this4.do_serialize(results, "read", {}, args, (yield _this4.propsToBeRemoved(results)));
552
+ }
553
+
554
+ if (args.skip_hooks != true) {
555
+ yield _this4.run_hook(results, "get", "after");
556
+ }
557
+
530
558
  return results;
531
559
  } else {
532
560
  throw new Error(_this4.type + " does not exist");
@@ -560,7 +588,9 @@ class SpiceModel {
560
588
  args = {};
561
589
  }
562
590
 
563
- yield _this6.run_hook(_this6, "list", "before");
591
+ if (args.skip_hooks != true) {
592
+ yield _this6.run_hook(_this6, "list", "before");
593
+ }
564
594
 
565
595
  _.remove(args.ids, o => o == undefined);
566
596
 
@@ -569,7 +599,7 @@ class SpiceModel {
569
599
  var results = [];
570
600
 
571
601
  if (args.ids.length > 0) {
572
- if (_this6.shouldCache(_this6.type)) {
602
+ if (_this6.shouldUseCache(_this6.type)) {
573
603
  var cached_results = yield _this6.getCacheProviderObject(_this6.type).get(key);
574
604
  results = cached_results == null ? void 0 : cached_results.value;
575
605
 
@@ -588,8 +618,14 @@ class SpiceModel {
588
618
 
589
619
  _.remove(results, o => o.type != _this6.type);
590
620
 
591
- yield _this6.run_hook(results, "list", "after", args.context);
592
- results = yield _this6.do_serialize(results, "read", {}, args, (yield _this6.propsToBeRemoved(results)));
621
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
622
+ results = yield _this6.do_serialize(results, "read", {}, args, (yield _this6.propsToBeRemoved(results)));
623
+ }
624
+
625
+ if (args.skip_hooks != true) {
626
+ yield _this6.run_hook(results, "list", "after", args.context);
627
+ }
628
+
593
629
  return results;
594
630
  } catch (e) {
595
631
  console.log(e.stack);
@@ -649,34 +685,33 @@ class SpiceModel {
649
685
  new: _this8,
650
686
  id: args.id
651
687
  };
652
-
653
- if (args.skip_hooks != true) {
654
- yield _this8.run_hook(cover_obj, "update", "before", results);
655
- }
656
-
657
688
  var form;
658
689
 
659
690
  if (args.skip_write_serialize != true && args.skip_serialize != true) {
660
- form = yield _this8.do_serialize(_this8, "write", cover_obj.new, args);
691
+ cover_obj.new = yield _this8.do_serialize(_this8, "write", cover_obj.new, args);
692
+ }
693
+
694
+ if (args.skip_hooks != true) {
695
+ yield _this8.run_hook(cover_obj, "update", "before", results);
661
696
  }
662
697
 
663
- var db_data = form || _this8;
698
+ var db_data = cover_obj.new || _this8;
664
699
  yield _this8.database.update(args.id, db_data);
665
700
 
666
701
  _this8.setMonitor();
667
702
 
703
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
704
+ cover_obj.new = yield _this8.do_serialize(cover_obj.new, "read", {}, args, (yield _this8.propsToBeRemoved(cover_obj.new)));
705
+ }
706
+
668
707
  if (args.skip_hooks != true) {
669
708
  yield _this8.run_hook(_extends({}, _this8, {
670
709
  id: args.id
671
710
  }), "update", "after", results);
672
711
  }
673
712
 
674
- if (args.skip_read_serialize != true && args.skip_serialize != true) {
675
- form = yield _this8.do_serialize(form, "read", {}, args, (yield _this8.propsToBeRemoved(form)));
676
- }
677
-
678
713
  _this8.id = args.id;
679
- return _extends({}, form, {
714
+ return _extends({}, cover_obj.new, {
680
715
  id: args.id
681
716
  });
682
717
  } catch (e) {
@@ -709,16 +744,28 @@ class SpiceModel {
709
744
  id = args.id;
710
745
  }
711
746
 
712
- yield _this9.run_hook(workingForm, "create", "before");
713
- workingForm = yield _this9.do_serialize(workingForm, "write", {}, args);
747
+ if (args.skip_write_serialize != true && args.skip_serialize != true) {
748
+ workingForm = yield _this9.do_serialize(workingForm, "write", {}, args);
749
+ }
750
+
751
+ if (args.skip_hooks != true) {
752
+ yield _this9.run_hook(workingForm, "create", "before");
753
+ }
754
+
714
755
  var results = yield _this9.database.insert(id, workingForm, args.expiry);
715
756
 
716
757
  _this9.setMonitor();
717
758
 
718
- yield _this9.run_hook(_extends({}, results, {
719
- id
720
- }), "create", "after");
721
- results = yield _this9.do_serialize(results, "read", {}, args, (yield _this9.propsToBeRemoved(results)));
759
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
760
+ results = yield _this9.do_serialize(results, "read", {}, args, (yield _this9.propsToBeRemoved(results)));
761
+ }
762
+
763
+ if (args.skip_hooks != true) {
764
+ yield _this9.run_hook(_extends({}, results, {
765
+ id
766
+ }), "create", "after");
767
+ }
768
+
722
769
  return _extends({}, results, {
723
770
  id
724
771
  });
@@ -742,7 +789,10 @@ class SpiceModel {
742
789
  var results = yield _this10.database.get(args.id);
743
790
 
744
791
  try {
745
- yield _this10.run_hook(args, "delete", "before");
792
+ if (args.skip_hooks != true) {
793
+ yield _this10.run_hook(args, "delete", "before");
794
+ }
795
+
746
796
  var delete_response = {};
747
797
 
748
798
  if (args.hard) {
@@ -755,7 +805,10 @@ class SpiceModel {
755
805
  delete_response = yield _this10.database.update(args.id, "");
756
806
  }
757
807
 
758
- yield _this10.run_hook(results, "delete", "after", results);
808
+ if (args.skip_hooks != true) {
809
+ yield _this10.run_hook(results, "delete", "after", results);
810
+ }
811
+
759
812
  return {};
760
813
  } catch (e) {
761
814
  console.log(e.stack);
@@ -807,6 +860,10 @@ class SpiceModel {
807
860
  }
808
861
  }
809
862
 
863
+ if ((0, _Security.hasSQLInjection)(query)) {
864
+ return [];
865
+ }
866
+
810
867
  if (args.limit) {
811
868
  args.limit = Number(args.limit);
812
869
  }
@@ -819,7 +876,9 @@ class SpiceModel {
819
876
  args.sort = "created_at DESC";
820
877
  }
821
878
 
822
- yield _this11.run_hook(_this11, "list", "before");
879
+ if (args.skip_hooks != true) {
880
+ yield _this11.run_hook(_this11, "list", "before");
881
+ }
823
882
 
824
883
  function removeSpaceAndSpecialCharacters(str) {
825
884
  return str.replace(/[^a-zA-Z0-9]/g, "");
@@ -830,7 +889,7 @@ class SpiceModel {
830
889
 
831
890
  if (args.is_custom_query && args.is_custom_query === "true") {
832
891
  if (args.ids.length > 0) {
833
- if (_this11.shouldCache(_this11.type)) {
892
+ if (_this11.shouldUseCache(_this11.type)) {
834
893
  var cached_results = yield _this11.getCacheProviderObject(_this11.type).get(key);
835
894
  results = cached_results == null ? void 0 : cached_results.value;
836
895
 
@@ -848,7 +907,7 @@ class SpiceModel {
848
907
  }
849
908
  } else {
850
909
  if (args.is_full_text && args.is_full_text === "true") {
851
- if (_this11.shouldCache(_this11.type)) {
910
+ if (_this11.shouldUseCache(_this11.type)) {
852
911
  var _cached_results = yield _this11.getCacheProviderObject(_this11.type).get(key);
853
912
 
854
913
  results = _cached_results == null ? void 0 : _cached_results.value;
@@ -865,12 +924,15 @@ class SpiceModel {
865
924
  results = yield _this11.database.full_text_search(_this11.type, query || "", args.limit, args.offset);
866
925
  }
867
926
  } else {
868
- if (_this11.shouldCache(_this11.type)) {
927
+ if (_this11.shouldUseCache(_this11.type)) {
869
928
  var _cached_results2 = yield _this11.getCacheProviderObject(_this11.type).get(key);
870
929
 
871
930
  results = _cached_results2 == null ? void 0 : _cached_results2.value;
931
+ var shouleForceRefresh = yield _this11.shouldForceRefresh(_cached_results2);
932
+ console.log("Cache Results", _this11.type, (_cached_results2 == null ? void 0 : _cached_results2.value) == undefined, shouleForceRefresh, (_cached_results2 == null ? void 0 : _cached_results2.value) == undefined || shouleForceRefresh);
872
933
 
873
- if ((_cached_results2 == null ? void 0 : _cached_results2.value) == undefined || (yield _this11.shouldForceRefresh(_cached_results2))) {
934
+ if ((_cached_results2 == null ? void 0 : _cached_results2.value) == undefined || shouleForceRefresh) {
935
+ console.log("Getting From Database With Cache", _this11.type);
874
936
  results = yield _this11.database.search(_this11.type, args.columns || "", query || "", args.limit, args.offset, args.sort, args.do_count, args.statement_consistent);
875
937
 
876
938
  _this11.getCacheProviderObject(_this11.type).set(key, {
@@ -889,8 +951,13 @@ class SpiceModel {
889
951
  }
890
952
 
891
953
  try {
892
- yield _this11.run_hook(results.data, "list", "after");
893
- results.data = yield _this11.do_serialize(results.data, "read", {}, args, (yield _this11.propsToBeRemoved(results.data)));
954
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
955
+ results.data = yield _this11.do_serialize(results.data, "read", {}, args, (yield _this11.propsToBeRemoved(results.data)));
956
+ }
957
+
958
+ if (args.skip_hooks != true) {
959
+ yield _this11.run_hook(results.data, "list", "after");
960
+ }
894
961
  } catch (e) {
895
962
  console.log(e);
896
963
  }
@@ -997,7 +1064,9 @@ class SpiceModel {
997
1064
  });
998
1065
 
999
1066
  var returned_all = yield Promise.allSettled(_.map(classes, obj => {
1000
- return new obj(_this13[_args]).getMulti({
1067
+ return new obj(_extends({}, _this13[_args], {
1068
+ skip_cache: _this13[_skip_cache]
1069
+ })).getMulti({
1001
1070
  ids: ids
1002
1071
  });
1003
1072
  }));
@@ -1048,7 +1117,9 @@ class SpiceModel {
1048
1117
 
1049
1118
  var classes = _.isArray(Class) ? Class : [Class];
1050
1119
  var returned_all = yield Promise.allSettled(_.map(classes, obj => {
1051
- return new obj(_this14[_args]).getMulti({
1120
+ return new obj(_extends({}, _this14[_args], {
1121
+ skip_cache: _this14[_skip_cache]
1122
+ })).getMulti({
1052
1123
  ids: ids
1053
1124
  });
1054
1125
  }));
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.hasSQLInjection = hasSQLInjection;
5
+
6
+ function hasSQLInjection(input) {
7
+ // Convert input to lowercase for easier pattern matching
8
+ var lowerInput = input.toLowerCase(); // List of patterns that indicate potential SQL injection
9
+
10
+ var patterns = ["--", // T-SQL comment
11
+ "/*", // Start of block comment
12
+ "*/", // End of block comment
13
+ "or 1=1", // OR statement that's always true
14
+ "or true", // OR statement that's always true (non-T-SQL databases)
15
+ "union all", // UNION statement (often used to retrieve data from another table)
16
+ "union select", // Another form of UNION statement
17
+ ";", // Commenting out the rest of a query
18
+ "drop table", // DDL statements are very suspicious
19
+ "update ", // Modification commands
20
+ "insert into", // Insertion commands
21
+ "delete from", // Deletion commands
22
+ "exec(", // Execution function in T-SQL
23
+ "execute(", // Another execution function in T-SQL
24
+ "xp_", // Extended stored procedures in T-SQL - often used in older SQL Server attacks
25
+ "0x", // Hex encoding
26
+ "benchmark(", // MySQL benchmark function - can be used for time-based blind attacks
27
+ "sleep(", // MySQL sleep function - can also be used for time-based blind attacks
28
+ "pg_sleep(", // PostgreSQL sleep function - time-based blind attack
29
+ "cast(", // Casting can be used for type-based attacks
30
+ "convert(", // Similar to the above
31
+ "waitfor delay" // SQL Server delay function - time-based blind attack
32
+ ];
33
+
34
+ for (var pattern of patterns) {
35
+ if (lowerInput.includes(pattern)) {
36
+ return true;
37
+ }
38
+ } // Additional patterns based on regular expressions for more complex detections
39
+
40
+
41
+ var regexPatterns = [/['"‘’“”][\s]*[+]+[\s]*['"‘’“”]/ // String concatenation, often used to obfuscate injections
42
+ ];
43
+
44
+ for (var regex of regexPatterns) {
45
+ if (regex.test(lowerInput)) {
46
+ return true;
47
+ }
48
+ }
49
+
50
+ return false;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spice-js",
3
- "version": "2.6.6",
3
+ "version": "2.6.8",
4
4
  "description": "spice",
5
5
  "main": "build/index.js",
6
6
  "repository": {
@@ -15,7 +15,6 @@
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
17
  "agenda": "^3.1.0",
18
- "caniuse-lite": "^1.0.30001283",
19
18
  "co": "^4.6.0",
20
19
  "dotenv": "^8.2.0",
21
20
  "flat": "^5.0.0",
@@ -8,7 +8,14 @@ async function connect() {
8
8
  spice.cache_providers[key] = new spice.config.cache.providers[key](
9
9
  spice.config.cache.drivers[key] || {}
10
10
  );
11
- spice.cache_providers[key].initialize();
11
+ spice.cache_providers[key]
12
+ .initialize()
13
+ .then(() => {
14
+ console.log("Redis initialized successfully");
15
+ })
16
+ .catch((err) => {
17
+ console.error("Error initializing Redis:", err);
18
+ });
12
19
  }
13
20
  } catch (e) {
14
21
  console.log(e.stack);
@@ -4,6 +4,7 @@ import { MapType, DataType } from "..";
4
4
  let co = require("co");
5
5
  var regeneratorRuntime = require("regenerator-runtime");
6
6
  import ResourceLifecycleTriggered from "../events/events/ResourceLifecycleTriggered";
7
+ import { hasSQLInjection } from "../utility/Security";
7
8
 
8
9
  var SDate = require("sonover-date"),
9
10
  UUID = require("uuid"),
@@ -15,6 +16,7 @@ var SDate = require("sonover-date"),
15
16
  _hooks = Symbol(),
16
17
  _disable_lifecycle_events = Symbol(),
17
18
  _external_modifier_loaded = Symbol(),
19
+ _skip_cache = Symbol(),
18
20
  _serializers = Symbol();
19
21
 
20
22
  //const _type = Symbol("type");
@@ -48,6 +50,7 @@ export default class SpiceModel {
48
50
  this[_disable_lifecycle_events] =
49
51
  args.args?.disable_lifecycle_events || false;
50
52
  this[_ctx] = args?.args?.ctx;
53
+ this[_skip_cache] = args?.args?.skip_cache || false;
51
54
  this[_hooks] = {
52
55
  create: {
53
56
  before: [],
@@ -365,11 +368,21 @@ export default class SpiceModel {
365
368
  return return_string;
366
369
  }
367
370
 
368
- shouldCache(resource_type) {
369
- return (
370
- spice.cache[resource_type] != undefined ||
371
- spice.systemconfig?.cache?.status == "disable"
372
- );
371
+ shouldUseCache(resource_type) {
372
+ // If '_skip_cache' property of this object is true, then we shouldn't cache.
373
+ if (this[_skip_cache] == true) {
374
+ return false;
375
+ }
376
+
377
+ // If the system configuration for spice has a cache status set to "disable",
378
+ // then we shouldn't cache, so return false.
379
+ if (spice.config.cache?.status == "disabled") {
380
+ return false;
381
+ }
382
+
383
+ // If 'spice.cache[resource_type]' is not undefined,
384
+ // it implies that this resource type is already in the cache or is cacheable.
385
+ return spice.cache[resource_type] != undefined;
373
386
  }
374
387
 
375
388
  getCacheConfig(resource_type) {
@@ -405,8 +418,9 @@ export default class SpiceModel {
405
418
  setMonitor() {
406
419
  let current_time = new Date().getTime();
407
420
  let obj = this.getCacheProviderObject();
408
- obj.set(`monitor::${this.type}`, { time: current_time }, { ttl: 0 });
409
- //console.log("Monitor Set", spice.monitor);
421
+ let key = `monitor::${this.type}`;
422
+ let value = { time: current_time };
423
+ obj.set(key, value, { ttl: 0 });
410
424
  }
411
425
 
412
426
  async get(args) {
@@ -415,14 +429,17 @@ export default class SpiceModel {
415
429
  args = {};
416
430
  }
417
431
  if (_.isString(args.id)) {
418
- await this.run_hook(args, "get", "before");
432
+ if (args.skip_hooks != true) {
433
+ await this.run_hook(args, "get", "before");
434
+ }
419
435
  let key = `${this.type}::${args.id}`;
420
436
  let results = {};
421
- if (this.shouldCache(this.type)) {
437
+ if (this.shouldUseCache(this.type)) {
422
438
  let cached_results = await this.getCacheProviderObject(this.type).get(
423
439
  key
424
440
  );
425
441
  results = cached_results?.value;
442
+
426
443
  if (
427
444
  cached_results?.value == undefined ||
428
445
  (await this.shouldForceRefresh(cached_results))
@@ -449,14 +466,18 @@ export default class SpiceModel {
449
466
  }
450
467
 
451
468
  if (results.deleted == undefined || results.deleted == false) {
452
- await this.run_hook(results, "get", "after");
453
- results = await this.do_serialize(
454
- results,
455
- "read",
456
- {},
457
- args,
458
- await this.propsToBeRemoved(results)
459
- );
469
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
470
+ results = await this.do_serialize(
471
+ results,
472
+ "read",
473
+ {},
474
+ args,
475
+ await this.propsToBeRemoved(results)
476
+ );
477
+ }
478
+ if (args.skip_hooks != true) {
479
+ await this.run_hook(results, "get", "after");
480
+ }
460
481
  return results;
461
482
  } else {
462
483
  throw new Error(`${this.type} does not exist`);
@@ -481,13 +502,14 @@ export default class SpiceModel {
481
502
  if (!args) {
482
503
  args = {};
483
504
  }
484
-
485
- await this.run_hook(this, "list", "before");
505
+ if (args.skip_hooks != true) {
506
+ await this.run_hook(this, "list", "before");
507
+ }
486
508
  _.remove(args.ids, (o) => o == undefined);
487
509
  let key = `${this.type}::${_.join(args.ids, "|")}`;
488
510
  let results = [];
489
511
  if (args.ids.length > 0) {
490
- if (this.shouldCache(this.type)) {
512
+ if (this.shouldUseCache(this.type)) {
491
513
  let cached_results = await this.getCacheProviderObject(this.type).get(
492
514
  key
493
515
  );
@@ -508,15 +530,19 @@ export default class SpiceModel {
508
530
  }
509
531
  }
510
532
  _.remove(results, (o) => o.type != this.type);
533
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
534
+ results = await this.do_serialize(
535
+ results,
536
+ "read",
537
+ {},
538
+ args,
539
+ await this.propsToBeRemoved(results)
540
+ );
541
+ }
511
542
 
512
- await this.run_hook(results, "list", "after", args.context);
513
- results = await this.do_serialize(
514
- results,
515
- "read",
516
- {},
517
- args,
518
- await this.propsToBeRemoved(results)
519
- );
543
+ if (args.skip_hooks != true) {
544
+ await this.run_hook(results, "list", "after", args.context);
545
+ }
520
546
 
521
547
  return results;
522
548
  } catch (e) {
@@ -569,19 +595,35 @@ export default class SpiceModel {
569
595
  new: this,
570
596
  id: args.id,
571
597
  };
572
- if (args.skip_hooks != true) {
573
- await this.run_hook(cover_obj, "update", "before", results);
574
- }
575
598
 
576
599
  let form;
577
600
  if (args.skip_write_serialize != true && args.skip_serialize != true) {
578
- form = await this.do_serialize(this, "write", cover_obj.new, args);
601
+ cover_obj.new = await this.do_serialize(
602
+ this,
603
+ "write",
604
+ cover_obj.new,
605
+ args
606
+ );
607
+ }
608
+
609
+ if (args.skip_hooks != true) {
610
+ await this.run_hook(cover_obj, "update", "before", results);
579
611
  }
580
- let db_data = form || this;
612
+ let db_data = cover_obj.new || this;
581
613
 
582
614
  await this.database.update(args.id, db_data);
583
615
  this.setMonitor();
584
616
 
617
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
618
+ cover_obj.new = await this.do_serialize(
619
+ cover_obj.new,
620
+ "read",
621
+ {},
622
+ args,
623
+ await this.propsToBeRemoved(cover_obj.new)
624
+ );
625
+ }
626
+
585
627
  if (args.skip_hooks != true) {
586
628
  await this.run_hook(
587
629
  {
@@ -593,17 +635,8 @@ export default class SpiceModel {
593
635
  results
594
636
  );
595
637
  }
596
- if (args.skip_read_serialize != true && args.skip_serialize != true) {
597
- form = await this.do_serialize(
598
- form,
599
- "read",
600
- {},
601
- args,
602
- await this.propsToBeRemoved(form)
603
- );
604
- }
605
638
  this.id = args.id;
606
- return { ...form, id: args.id };
639
+ return { ...cover_obj.new, id: args.id };
607
640
  } catch (e) {
608
641
  console.log("Error on update", e, e.stack);
609
642
  throw e;
@@ -627,26 +660,37 @@ export default class SpiceModel {
627
660
  if (args && args.id) {
628
661
  id = args.id;
629
662
  }
630
- await this.run_hook(workingForm, "create", "before");
631
- workingForm = await this.do_serialize(workingForm, "write", {}, args);
663
+
664
+ if (args.skip_write_serialize != true && args.skip_serialize != true) {
665
+ workingForm = await this.do_serialize(workingForm, "write", {}, args);
666
+ }
667
+
668
+ if (args.skip_hooks != true) {
669
+ await this.run_hook(workingForm, "create", "before");
670
+ }
632
671
 
633
672
  let results = await this.database.insert(id, workingForm, args.expiry);
634
673
  this.setMonitor();
635
- await this.run_hook(
636
- {
637
- ...results,
638
- id,
639
- },
640
- "create",
641
- "after"
642
- );
643
- results = await this.do_serialize(
644
- results,
645
- "read",
646
- {},
647
- args,
648
- await this.propsToBeRemoved(results)
649
- );
674
+
675
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
676
+ results = await this.do_serialize(
677
+ results,
678
+ "read",
679
+ {},
680
+ args,
681
+ await this.propsToBeRemoved(results)
682
+ );
683
+ }
684
+ if (args.skip_hooks != true) {
685
+ await this.run_hook(
686
+ {
687
+ ...results,
688
+ id,
689
+ },
690
+ "create",
691
+ "after"
692
+ );
693
+ }
650
694
  return { ...results, id };
651
695
  } catch (e) {
652
696
  console.log(e.stack);
@@ -662,7 +706,9 @@ export default class SpiceModel {
662
706
  }
663
707
  let results = await this.database.get(args.id);
664
708
  try {
665
- await this.run_hook(args, "delete", "before");
709
+ if (args.skip_hooks != true) {
710
+ await this.run_hook(args, "delete", "before");
711
+ }
666
712
  let delete_response = {};
667
713
  if (args.hard) {
668
714
  delete_response = await this.database.delete(args.id);
@@ -672,7 +718,9 @@ export default class SpiceModel {
672
718
  results.deleted = true;
673
719
  delete_response = await this.database.update(args.id, "");
674
720
  }
675
- await this.run_hook(results, "delete", "after", results);
721
+ if (args.skip_hooks != true) {
722
+ await this.run_hook(results, "delete", "after", results);
723
+ }
676
724
  return {};
677
725
  } catch (e) {
678
726
  console.log(e.stack);
@@ -720,6 +768,9 @@ export default class SpiceModel {
720
768
  }
721
769
  }
722
770
 
771
+ if (hasSQLInjection(query)) {
772
+ return [];
773
+ }
723
774
  if (args.limit) {
724
775
  args.limit = Number(args.limit);
725
776
  }
@@ -730,8 +781,9 @@ export default class SpiceModel {
730
781
  if (!args.sort) {
731
782
  args.sort = "created_at DESC";
732
783
  }
733
-
734
- await this.run_hook(this, "list", "before");
784
+ if (args.skip_hooks != true) {
785
+ await this.run_hook(this, "list", "before");
786
+ }
735
787
  function removeSpaceAndSpecialCharacters(str) {
736
788
  return str.replace(/[^a-zA-Z0-9]/g, "");
737
789
  }
@@ -742,7 +794,7 @@ export default class SpiceModel {
742
794
  let results;
743
795
  if (args.is_custom_query && args.is_custom_query === "true") {
744
796
  if (args.ids.length > 0) {
745
- if (this.shouldCache(this.type)) {
797
+ if (this.shouldUseCache(this.type)) {
746
798
  let cached_results = await this.getCacheProviderObject(
747
799
  this.type
748
800
  ).get(key);
@@ -764,7 +816,7 @@ export default class SpiceModel {
764
816
  }
765
817
  } else {
766
818
  if (args.is_full_text && args.is_full_text === "true") {
767
- if (this.shouldCache(this.type)) {
819
+ if (this.shouldUseCache(this.type)) {
768
820
  let cached_results = await this.getCacheProviderObject(
769
821
  this.type
770
822
  ).get(key);
@@ -794,15 +846,23 @@ export default class SpiceModel {
794
846
  );
795
847
  }
796
848
  } else {
797
- if (this.shouldCache(this.type)) {
849
+ if (this.shouldUseCache(this.type)) {
798
850
  let cached_results = await this.getCacheProviderObject(
799
851
  this.type
800
852
  ).get(key);
801
853
  results = cached_results?.value;
802
- if (
803
- cached_results?.value == undefined ||
804
- (await this.shouldForceRefresh(cached_results))
805
- ) {
854
+ let shouleForceRefresh = await this.shouldForceRefresh(
855
+ cached_results
856
+ );
857
+ console.log(
858
+ "Cache Results",
859
+ this.type,
860
+ cached_results?.value == undefined,
861
+ shouleForceRefresh,
862
+ cached_results?.value == undefined || shouleForceRefresh
863
+ );
864
+ if (cached_results?.value == undefined || shouleForceRefresh) {
865
+ console.log("Getting From Database With Cache", this.type);
806
866
  results = await this.database.search(
807
867
  this.type,
808
868
  args.columns || "",
@@ -837,14 +897,18 @@ export default class SpiceModel {
837
897
  }
838
898
  }
839
899
  try {
840
- await this.run_hook(results.data, "list", "after");
841
- results.data = await this.do_serialize(
842
- results.data,
843
- "read",
844
- {},
845
- args,
846
- await this.propsToBeRemoved(results.data)
847
- );
900
+ if (args.skip_read_serialize != true && args.skip_serialize != true) {
901
+ results.data = await this.do_serialize(
902
+ results.data,
903
+ "read",
904
+ {},
905
+ args,
906
+ await this.propsToBeRemoved(results.data)
907
+ );
908
+ }
909
+ if (args.skip_hooks != true) {
910
+ await this.run_hook(results.data, "list", "after");
911
+ }
848
912
  } catch (e) {
849
913
  console.log(e);
850
914
  }
@@ -931,7 +995,10 @@ export default class SpiceModel {
931
995
 
932
996
  var returned_all = await Promise.allSettled(
933
997
  _.map(classes, (obj) => {
934
- return new obj(this[_args]).getMulti({
998
+ return new obj({
999
+ ...this[_args],
1000
+ skip_cache: this[_skip_cache],
1001
+ }).getMulti({
935
1002
  ids: ids,
936
1003
  });
937
1004
  })
@@ -986,7 +1053,10 @@ export default class SpiceModel {
986
1053
  let classes = _.isArray(Class) ? Class : [Class];
987
1054
  var returned_all = await Promise.allSettled(
988
1055
  _.map(classes, (obj) => {
989
- return new obj(this[_args]).getMulti({
1056
+ return new obj({
1057
+ ...this[_args],
1058
+ skip_cache: this[_skip_cache],
1059
+ }).getMulti({
990
1060
  ids: ids,
991
1061
  });
992
1062
  })
@@ -0,0 +1,49 @@
1
+ export function hasSQLInjection(input) {
2
+ // Convert input to lowercase for easier pattern matching
3
+ const lowerInput = input.toLowerCase();
4
+
5
+ // List of patterns that indicate potential SQL injection
6
+ const patterns = [
7
+ "--", // T-SQL comment
8
+ "/*", // Start of block comment
9
+ "*/", // End of block comment
10
+ "or 1=1", // OR statement that's always true
11
+ "or true", // OR statement that's always true (non-T-SQL databases)
12
+ "union all", // UNION statement (often used to retrieve data from another table)
13
+ "union select", // Another form of UNION statement
14
+ ";", // Commenting out the rest of a query
15
+ "drop table", // DDL statements are very suspicious
16
+ "update ", // Modification commands
17
+ "insert into", // Insertion commands
18
+ "delete from", // Deletion commands
19
+ "exec(", // Execution function in T-SQL
20
+ "execute(", // Another execution function in T-SQL
21
+ "xp_", // Extended stored procedures in T-SQL - often used in older SQL Server attacks
22
+ "0x", // Hex encoding
23
+ "benchmark(", // MySQL benchmark function - can be used for time-based blind attacks
24
+ "sleep(", // MySQL sleep function - can also be used for time-based blind attacks
25
+ "pg_sleep(", // PostgreSQL sleep function - time-based blind attack
26
+ "cast(", // Casting can be used for type-based attacks
27
+ "convert(", // Similar to the above
28
+ "waitfor delay", // SQL Server delay function - time-based blind attack
29
+ ];
30
+
31
+ for (let pattern of patterns) {
32
+ if (lowerInput.includes(pattern)) {
33
+ return true;
34
+ }
35
+ }
36
+
37
+ // Additional patterns based on regular expressions for more complex detections
38
+ const regexPatterns = [
39
+ /['"‘’“”][\s]*[+]+[\s]*['"‘’“”]/, // String concatenation, often used to obfuscate injections
40
+ ];
41
+
42
+ for (let regex of regexPatterns) {
43
+ if (regex.test(lowerInput)) {
44
+ return true;
45
+ }
46
+ }
47
+
48
+ return false;
49
+ }