spice-js 2.6.7 → 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.
- package/build/bootstrap/cache.js +5 -1
- package/build/models/SpiceModel.js +85 -33
- package/build/utility/Security.js +51 -0
- package/package.json +1 -2
- package/src/bootstrap/cache.js +8 -1
- package/src/models/SpiceModel.js +121 -69
- package/src/utility/Security.js +49 -0
package/build/bootstrap/cache.js
CHANGED
|
@@ -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); }
|
|
@@ -495,11 +497,13 @@ class SpiceModel {
|
|
|
495
497
|
setMonitor() {
|
|
496
498
|
var current_time = new Date().getTime();
|
|
497
499
|
var obj = this.getCacheProviderObject();
|
|
498
|
-
|
|
500
|
+
var key = "monitor::" + this.type;
|
|
501
|
+
var value = {
|
|
499
502
|
time: current_time
|
|
500
|
-
}
|
|
503
|
+
};
|
|
504
|
+
obj.set(key, value, {
|
|
501
505
|
ttl: 0
|
|
502
|
-
});
|
|
506
|
+
});
|
|
503
507
|
}
|
|
504
508
|
|
|
505
509
|
get(args) {
|
|
@@ -512,7 +516,10 @@ class SpiceModel {
|
|
|
512
516
|
}
|
|
513
517
|
|
|
514
518
|
if (_.isString(args.id)) {
|
|
515
|
-
|
|
519
|
+
if (args.skip_hooks != true) {
|
|
520
|
+
yield _this4.run_hook(args, "get", "before");
|
|
521
|
+
}
|
|
522
|
+
|
|
516
523
|
var key = _this4.type + "::" + args.id;
|
|
517
524
|
var results = {};
|
|
518
525
|
|
|
@@ -540,8 +547,14 @@ class SpiceModel {
|
|
|
540
547
|
}
|
|
541
548
|
|
|
542
549
|
if (results.deleted == undefined || results.deleted == false) {
|
|
543
|
-
|
|
544
|
-
|
|
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
|
+
|
|
545
558
|
return results;
|
|
546
559
|
} else {
|
|
547
560
|
throw new Error(_this4.type + " does not exist");
|
|
@@ -575,7 +588,9 @@ class SpiceModel {
|
|
|
575
588
|
args = {};
|
|
576
589
|
}
|
|
577
590
|
|
|
578
|
-
|
|
591
|
+
if (args.skip_hooks != true) {
|
|
592
|
+
yield _this6.run_hook(_this6, "list", "before");
|
|
593
|
+
}
|
|
579
594
|
|
|
580
595
|
_.remove(args.ids, o => o == undefined);
|
|
581
596
|
|
|
@@ -603,8 +618,14 @@ class SpiceModel {
|
|
|
603
618
|
|
|
604
619
|
_.remove(results, o => o.type != _this6.type);
|
|
605
620
|
|
|
606
|
-
|
|
607
|
-
|
|
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
|
+
|
|
608
629
|
return results;
|
|
609
630
|
} catch (e) {
|
|
610
631
|
console.log(e.stack);
|
|
@@ -664,34 +685,33 @@ class SpiceModel {
|
|
|
664
685
|
new: _this8,
|
|
665
686
|
id: args.id
|
|
666
687
|
};
|
|
667
|
-
|
|
668
|
-
if (args.skip_hooks != true) {
|
|
669
|
-
yield _this8.run_hook(cover_obj, "update", "before", results);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
688
|
var form;
|
|
673
689
|
|
|
674
690
|
if (args.skip_write_serialize != true && args.skip_serialize != true) {
|
|
675
|
-
|
|
691
|
+
cover_obj.new = yield _this8.do_serialize(_this8, "write", cover_obj.new, args);
|
|
676
692
|
}
|
|
677
693
|
|
|
678
|
-
|
|
694
|
+
if (args.skip_hooks != true) {
|
|
695
|
+
yield _this8.run_hook(cover_obj, "update", "before", results);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
var db_data = cover_obj.new || _this8;
|
|
679
699
|
yield _this8.database.update(args.id, db_data);
|
|
680
700
|
|
|
681
701
|
_this8.setMonitor();
|
|
682
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
|
+
|
|
683
707
|
if (args.skip_hooks != true) {
|
|
684
708
|
yield _this8.run_hook(_extends({}, _this8, {
|
|
685
709
|
id: args.id
|
|
686
710
|
}), "update", "after", results);
|
|
687
711
|
}
|
|
688
712
|
|
|
689
|
-
if (args.skip_read_serialize != true && args.skip_serialize != true) {
|
|
690
|
-
form = yield _this8.do_serialize(form, "read", {}, args, (yield _this8.propsToBeRemoved(form)));
|
|
691
|
-
}
|
|
692
|
-
|
|
693
713
|
_this8.id = args.id;
|
|
694
|
-
return _extends({},
|
|
714
|
+
return _extends({}, cover_obj.new, {
|
|
695
715
|
id: args.id
|
|
696
716
|
});
|
|
697
717
|
} catch (e) {
|
|
@@ -724,16 +744,28 @@ class SpiceModel {
|
|
|
724
744
|
id = args.id;
|
|
725
745
|
}
|
|
726
746
|
|
|
727
|
-
|
|
728
|
-
|
|
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
|
+
|
|
729
755
|
var results = yield _this9.database.insert(id, workingForm, args.expiry);
|
|
730
756
|
|
|
731
757
|
_this9.setMonitor();
|
|
732
758
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
}
|
|
736
|
-
|
|
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
|
+
|
|
737
769
|
return _extends({}, results, {
|
|
738
770
|
id
|
|
739
771
|
});
|
|
@@ -757,7 +789,10 @@ class SpiceModel {
|
|
|
757
789
|
var results = yield _this10.database.get(args.id);
|
|
758
790
|
|
|
759
791
|
try {
|
|
760
|
-
|
|
792
|
+
if (args.skip_hooks != true) {
|
|
793
|
+
yield _this10.run_hook(args, "delete", "before");
|
|
794
|
+
}
|
|
795
|
+
|
|
761
796
|
var delete_response = {};
|
|
762
797
|
|
|
763
798
|
if (args.hard) {
|
|
@@ -770,7 +805,10 @@ class SpiceModel {
|
|
|
770
805
|
delete_response = yield _this10.database.update(args.id, "");
|
|
771
806
|
}
|
|
772
807
|
|
|
773
|
-
|
|
808
|
+
if (args.skip_hooks != true) {
|
|
809
|
+
yield _this10.run_hook(results, "delete", "after", results);
|
|
810
|
+
}
|
|
811
|
+
|
|
774
812
|
return {};
|
|
775
813
|
} catch (e) {
|
|
776
814
|
console.log(e.stack);
|
|
@@ -822,6 +860,10 @@ class SpiceModel {
|
|
|
822
860
|
}
|
|
823
861
|
}
|
|
824
862
|
|
|
863
|
+
if ((0, _Security.hasSQLInjection)(query)) {
|
|
864
|
+
return [];
|
|
865
|
+
}
|
|
866
|
+
|
|
825
867
|
if (args.limit) {
|
|
826
868
|
args.limit = Number(args.limit);
|
|
827
869
|
}
|
|
@@ -834,7 +876,9 @@ class SpiceModel {
|
|
|
834
876
|
args.sort = "created_at DESC";
|
|
835
877
|
}
|
|
836
878
|
|
|
837
|
-
|
|
879
|
+
if (args.skip_hooks != true) {
|
|
880
|
+
yield _this11.run_hook(_this11, "list", "before");
|
|
881
|
+
}
|
|
838
882
|
|
|
839
883
|
function removeSpaceAndSpecialCharacters(str) {
|
|
840
884
|
return str.replace(/[^a-zA-Z0-9]/g, "");
|
|
@@ -884,8 +928,11 @@ class SpiceModel {
|
|
|
884
928
|
var _cached_results2 = yield _this11.getCacheProviderObject(_this11.type).get(key);
|
|
885
929
|
|
|
886
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);
|
|
887
933
|
|
|
888
|
-
if ((_cached_results2 == null ? void 0 : _cached_results2.value) == undefined ||
|
|
934
|
+
if ((_cached_results2 == null ? void 0 : _cached_results2.value) == undefined || shouleForceRefresh) {
|
|
935
|
+
console.log("Getting From Database With Cache", _this11.type);
|
|
889
936
|
results = yield _this11.database.search(_this11.type, args.columns || "", query || "", args.limit, args.offset, args.sort, args.do_count, args.statement_consistent);
|
|
890
937
|
|
|
891
938
|
_this11.getCacheProviderObject(_this11.type).set(key, {
|
|
@@ -904,8 +951,13 @@ class SpiceModel {
|
|
|
904
951
|
}
|
|
905
952
|
|
|
906
953
|
try {
|
|
907
|
-
|
|
908
|
-
|
|
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
|
+
}
|
|
909
961
|
} catch (e) {
|
|
910
962
|
console.log(e);
|
|
911
963
|
}
|
|
@@ -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.
|
|
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",
|
package/src/bootstrap/cache.js
CHANGED
|
@@ -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]
|
|
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);
|
package/src/models/SpiceModel.js
CHANGED
|
@@ -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"),
|
|
@@ -417,8 +418,9 @@ export default class SpiceModel {
|
|
|
417
418
|
setMonitor() {
|
|
418
419
|
let current_time = new Date().getTime();
|
|
419
420
|
let obj = this.getCacheProviderObject();
|
|
420
|
-
|
|
421
|
-
|
|
421
|
+
let key = `monitor::${this.type}`;
|
|
422
|
+
let value = { time: current_time };
|
|
423
|
+
obj.set(key, value, { ttl: 0 });
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
async get(args) {
|
|
@@ -427,7 +429,9 @@ export default class SpiceModel {
|
|
|
427
429
|
args = {};
|
|
428
430
|
}
|
|
429
431
|
if (_.isString(args.id)) {
|
|
430
|
-
|
|
432
|
+
if (args.skip_hooks != true) {
|
|
433
|
+
await this.run_hook(args, "get", "before");
|
|
434
|
+
}
|
|
431
435
|
let key = `${this.type}::${args.id}`;
|
|
432
436
|
let results = {};
|
|
433
437
|
if (this.shouldUseCache(this.type)) {
|
|
@@ -435,6 +439,7 @@ export default class SpiceModel {
|
|
|
435
439
|
key
|
|
436
440
|
);
|
|
437
441
|
results = cached_results?.value;
|
|
442
|
+
|
|
438
443
|
if (
|
|
439
444
|
cached_results?.value == undefined ||
|
|
440
445
|
(await this.shouldForceRefresh(cached_results))
|
|
@@ -461,14 +466,18 @@ export default class SpiceModel {
|
|
|
461
466
|
}
|
|
462
467
|
|
|
463
468
|
if (results.deleted == undefined || results.deleted == false) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
+
}
|
|
472
481
|
return results;
|
|
473
482
|
} else {
|
|
474
483
|
throw new Error(`${this.type} does not exist`);
|
|
@@ -493,8 +502,9 @@ export default class SpiceModel {
|
|
|
493
502
|
if (!args) {
|
|
494
503
|
args = {};
|
|
495
504
|
}
|
|
496
|
-
|
|
497
|
-
|
|
505
|
+
if (args.skip_hooks != true) {
|
|
506
|
+
await this.run_hook(this, "list", "before");
|
|
507
|
+
}
|
|
498
508
|
_.remove(args.ids, (o) => o == undefined);
|
|
499
509
|
let key = `${this.type}::${_.join(args.ids, "|")}`;
|
|
500
510
|
let results = [];
|
|
@@ -520,15 +530,19 @@ export default class SpiceModel {
|
|
|
520
530
|
}
|
|
521
531
|
}
|
|
522
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
|
+
}
|
|
523
542
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
"read",
|
|
528
|
-
{},
|
|
529
|
-
args,
|
|
530
|
-
await this.propsToBeRemoved(results)
|
|
531
|
-
);
|
|
543
|
+
if (args.skip_hooks != true) {
|
|
544
|
+
await this.run_hook(results, "list", "after", args.context);
|
|
545
|
+
}
|
|
532
546
|
|
|
533
547
|
return results;
|
|
534
548
|
} catch (e) {
|
|
@@ -581,19 +595,35 @@ export default class SpiceModel {
|
|
|
581
595
|
new: this,
|
|
582
596
|
id: args.id,
|
|
583
597
|
};
|
|
584
|
-
if (args.skip_hooks != true) {
|
|
585
|
-
await this.run_hook(cover_obj, "update", "before", results);
|
|
586
|
-
}
|
|
587
598
|
|
|
588
599
|
let form;
|
|
589
600
|
if (args.skip_write_serialize != true && args.skip_serialize != true) {
|
|
590
|
-
|
|
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);
|
|
591
611
|
}
|
|
592
|
-
let db_data =
|
|
612
|
+
let db_data = cover_obj.new || this;
|
|
593
613
|
|
|
594
614
|
await this.database.update(args.id, db_data);
|
|
595
615
|
this.setMonitor();
|
|
596
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
|
+
|
|
597
627
|
if (args.skip_hooks != true) {
|
|
598
628
|
await this.run_hook(
|
|
599
629
|
{
|
|
@@ -605,17 +635,8 @@ export default class SpiceModel {
|
|
|
605
635
|
results
|
|
606
636
|
);
|
|
607
637
|
}
|
|
608
|
-
if (args.skip_read_serialize != true && args.skip_serialize != true) {
|
|
609
|
-
form = await this.do_serialize(
|
|
610
|
-
form,
|
|
611
|
-
"read",
|
|
612
|
-
{},
|
|
613
|
-
args,
|
|
614
|
-
await this.propsToBeRemoved(form)
|
|
615
|
-
);
|
|
616
|
-
}
|
|
617
638
|
this.id = args.id;
|
|
618
|
-
return { ...
|
|
639
|
+
return { ...cover_obj.new, id: args.id };
|
|
619
640
|
} catch (e) {
|
|
620
641
|
console.log("Error on update", e, e.stack);
|
|
621
642
|
throw e;
|
|
@@ -639,26 +660,37 @@ export default class SpiceModel {
|
|
|
639
660
|
if (args && args.id) {
|
|
640
661
|
id = args.id;
|
|
641
662
|
}
|
|
642
|
-
|
|
643
|
-
|
|
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
|
+
}
|
|
644
671
|
|
|
645
672
|
let results = await this.database.insert(id, workingForm, args.expiry);
|
|
646
673
|
this.setMonitor();
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|
+
}
|
|
662
694
|
return { ...results, id };
|
|
663
695
|
} catch (e) {
|
|
664
696
|
console.log(e.stack);
|
|
@@ -674,7 +706,9 @@ export default class SpiceModel {
|
|
|
674
706
|
}
|
|
675
707
|
let results = await this.database.get(args.id);
|
|
676
708
|
try {
|
|
677
|
-
|
|
709
|
+
if (args.skip_hooks != true) {
|
|
710
|
+
await this.run_hook(args, "delete", "before");
|
|
711
|
+
}
|
|
678
712
|
let delete_response = {};
|
|
679
713
|
if (args.hard) {
|
|
680
714
|
delete_response = await this.database.delete(args.id);
|
|
@@ -684,7 +718,9 @@ export default class SpiceModel {
|
|
|
684
718
|
results.deleted = true;
|
|
685
719
|
delete_response = await this.database.update(args.id, "");
|
|
686
720
|
}
|
|
687
|
-
|
|
721
|
+
if (args.skip_hooks != true) {
|
|
722
|
+
await this.run_hook(results, "delete", "after", results);
|
|
723
|
+
}
|
|
688
724
|
return {};
|
|
689
725
|
} catch (e) {
|
|
690
726
|
console.log(e.stack);
|
|
@@ -732,6 +768,9 @@ export default class SpiceModel {
|
|
|
732
768
|
}
|
|
733
769
|
}
|
|
734
770
|
|
|
771
|
+
if (hasSQLInjection(query)) {
|
|
772
|
+
return [];
|
|
773
|
+
}
|
|
735
774
|
if (args.limit) {
|
|
736
775
|
args.limit = Number(args.limit);
|
|
737
776
|
}
|
|
@@ -742,8 +781,9 @@ export default class SpiceModel {
|
|
|
742
781
|
if (!args.sort) {
|
|
743
782
|
args.sort = "created_at DESC";
|
|
744
783
|
}
|
|
745
|
-
|
|
746
|
-
|
|
784
|
+
if (args.skip_hooks != true) {
|
|
785
|
+
await this.run_hook(this, "list", "before");
|
|
786
|
+
}
|
|
747
787
|
function removeSpaceAndSpecialCharacters(str) {
|
|
748
788
|
return str.replace(/[^a-zA-Z0-9]/g, "");
|
|
749
789
|
}
|
|
@@ -811,10 +851,18 @@ export default class SpiceModel {
|
|
|
811
851
|
this.type
|
|
812
852
|
).get(key);
|
|
813
853
|
results = cached_results?.value;
|
|
814
|
-
|
|
815
|
-
cached_results
|
|
816
|
-
|
|
817
|
-
|
|
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);
|
|
818
866
|
results = await this.database.search(
|
|
819
867
|
this.type,
|
|
820
868
|
args.columns || "",
|
|
@@ -849,14 +897,18 @@ export default class SpiceModel {
|
|
|
849
897
|
}
|
|
850
898
|
}
|
|
851
899
|
try {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
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
|
+
}
|
|
860
912
|
} catch (e) {
|
|
861
913
|
console.log(e);
|
|
862
914
|
}
|
|
@@ -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
|
+
}
|