@arcis/node 1.1.0 → 1.3.0
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/README.md +156 -211
- package/dist/core/index.d.mts +4 -4
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +13 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +13 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/{headers-DBQedhrb.d.mts → encode-CrQCGlBq.d.mts} +202 -2
- package/dist/{headers-BJq2OA0i.d.ts → encode-jl9sOwmA.d.ts} +202 -2
- package/dist/{index-BvcFpoR3.d.ts → index-BAhgn9V2.d.ts} +96 -2
- package/dist/{index-iCOw8Fcg.d.ts → index-BGNKspqH.d.ts} +1 -1
- package/dist/{index-CslcoZUN.d.mts → index-Cd02z-0j.d.mts} +1 -1
- package/dist/{index-CCcPuTBo.d.mts → index-DgJtWMSj.d.mts} +96 -2
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +647 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +629 -9
- package/dist/index.mjs.map +1 -1
- package/dist/logging/index.d.mts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +12 -1
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs +12 -1
- package/dist/logging/index.mjs.map +1 -1
- package/dist/middleware/index.d.mts +2 -2
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +168 -6
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +165 -7
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/sanitizers/index.d.mts +2 -2
- package/dist/sanitizers/index.d.ts +2 -2
- package/dist/sanitizers/index.js +403 -3
- package/dist/sanitizers/index.js.map +1 -1
- package/dist/sanitizers/index.mjs +388 -4
- package/dist/sanitizers/index.mjs.map +1 -1
- package/dist/stores/index.d.mts +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/index.mjs.map +1 -1
- package/dist/{types-BOdL3ZWo.d.mts → types-BOkx5YJc.d.mts} +17 -2
- package/dist/{types-BOdL3ZWo.d.ts → types-BOkx5YJc.d.ts} +17 -2
- package/dist/validation/index.d.mts +2 -2
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +105 -3
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/index.mjs +105 -3
- package/dist/validation/index.mjs.map +1 -1
- package/package.json +114 -114
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { c as createSanitizer, d as detectCommandInjection, a as detectHeaderInjection, b as
|
|
1
|
+
export { c as createSanitizer, d as detectCommandInjection, a as detectHeaderInjection, b as detectJsonpInjection, e as detectNoSqlInjection, f as detectPathTraversal, g as detectPii, h as detectPrototypePollution, i as detectSql, j as detectSsti, k as detectXss, l as detectXxe, m as encodeForAttribute, n as encodeForCss, o as encodeForHtml, p as encodeForJs, q as encodeForUrl, r as getDangerousOperators, s as getDangerousProtoKeys, t as isDangerousNoSqlKey, u as isDangerousProtoKey, v as redactObjectPii, w as redactPii, x as sanitizeCommand, y as sanitizeHeaderValue, z as sanitizeHeaders, A as sanitizeJsonpCallback, B as sanitizeObject, C as sanitizePath, D as sanitizeSql, E as sanitizeSsti, F as sanitizeString, G as sanitizeXss, H as sanitizeXxe, I as scanObjectPii, J as scanPii } from '../encode-CrQCGlBq.mjs';
|
|
2
2
|
import 'express';
|
|
3
|
-
import '../types-
|
|
3
|
+
import '../types-BOkx5YJc.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @module @arcis/node/sanitizers/utils
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { c as createSanitizer, d as detectCommandInjection, a as detectHeaderInjection, b as
|
|
1
|
+
export { c as createSanitizer, d as detectCommandInjection, a as detectHeaderInjection, b as detectJsonpInjection, e as detectNoSqlInjection, f as detectPathTraversal, g as detectPii, h as detectPrototypePollution, i as detectSql, j as detectSsti, k as detectXss, l as detectXxe, m as encodeForAttribute, n as encodeForCss, o as encodeForHtml, p as encodeForJs, q as encodeForUrl, r as getDangerousOperators, s as getDangerousProtoKeys, t as isDangerousNoSqlKey, u as isDangerousProtoKey, v as redactObjectPii, w as redactPii, x as sanitizeCommand, y as sanitizeHeaderValue, z as sanitizeHeaders, A as sanitizeJsonpCallback, B as sanitizeObject, C as sanitizePath, D as sanitizeSql, E as sanitizeSsti, F as sanitizeString, G as sanitizeXss, H as sanitizeXxe, I as scanObjectPii, J as scanPii } from '../encode-jl9sOwmA.js';
|
|
2
2
|
import 'express';
|
|
3
|
-
import '../types-
|
|
3
|
+
import '../types-BOkx5YJc.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @module @arcis/node/sanitizers/utils
|
package/dist/sanitizers/index.js
CHANGED
|
@@ -76,7 +76,11 @@ var SQL_PATTERNS = [
|
|
|
76
76
|
/** Time-based blind: SLEEP() */
|
|
77
77
|
/\bSLEEP\s*\(\s*\d+\s*\)/gi,
|
|
78
78
|
/** Time-based blind: BENCHMARK() */
|
|
79
|
-
/\bBENCHMARK\s*\(/gi
|
|
79
|
+
/\bBENCHMARK\s*\(/gi,
|
|
80
|
+
/** Time-based blind: PostgreSQL pg_sleep() */
|
|
81
|
+
/\bpg_sleep\s*\(/gi,
|
|
82
|
+
/** Time-based blind: MSSQL WAITFOR DELAY */
|
|
83
|
+
/\bWAITFOR\s+DELAY\b/gi
|
|
80
84
|
];
|
|
81
85
|
var PATH_PATTERNS = [
|
|
82
86
|
/** Unix path traversal */
|
|
@@ -94,6 +98,10 @@ var PATH_PATTERNS = [
|
|
|
94
98
|
/\.%2e[\\/]/gi,
|
|
95
99
|
/** Fully URL-encoded: %2e%2e%2f */
|
|
96
100
|
/%2e%2e%2f/gi,
|
|
101
|
+
/** Double URL-encoded forward slash: %252f */
|
|
102
|
+
/%252f/gi,
|
|
103
|
+
/** Dotdotslash bypass: ....// or ....\\ */
|
|
104
|
+
/\.{2,}[/\\]{2,}/g,
|
|
97
105
|
/** Null byte injection in paths */
|
|
98
106
|
/\0/g
|
|
99
107
|
];
|
|
@@ -109,7 +117,9 @@ var COMMAND_PATTERNS = [
|
|
|
109
117
|
*/
|
|
110
118
|
/[;&|`]/g,
|
|
111
119
|
/** Command substitution: $( ... ) — matched as a pair to reduce false positives */
|
|
112
|
-
/\$\(/g
|
|
120
|
+
/\$\(/g,
|
|
121
|
+
/** URL-encoded newline/carriage-return injection (%0a, %0d) */
|
|
122
|
+
/%0[ad]/gi
|
|
113
123
|
];
|
|
114
124
|
var DANGEROUS_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
115
125
|
"__proto__",
|
|
@@ -143,6 +153,7 @@ var NOSQL_DANGEROUS_KEYS = /* @__PURE__ */ new Set([
|
|
|
143
153
|
"$expr",
|
|
144
154
|
"$mod",
|
|
145
155
|
"$text",
|
|
156
|
+
"$jsonSchema",
|
|
146
157
|
// Array
|
|
147
158
|
"$elemMatch",
|
|
148
159
|
"$all",
|
|
@@ -432,7 +443,8 @@ function sanitizeObject(obj, options = {}) {
|
|
|
432
443
|
if (typeof obj === "string") return sanitizeString(obj, options);
|
|
433
444
|
if (typeof obj !== "object") return obj;
|
|
434
445
|
if (Array.isArray(obj)) return obj.map((item) => sanitizeObject(item, options));
|
|
435
|
-
|
|
446
|
+
const result = sanitizeObjectDepth(obj, options, 0);
|
|
447
|
+
return options.freeze ? Object.freeze(result) : result;
|
|
436
448
|
}
|
|
437
449
|
function sanitizeObjectDepth(obj, options, depth) {
|
|
438
450
|
if (depth >= INPUT.MAX_RECURSION_DEPTH) return obj;
|
|
@@ -535,6 +547,179 @@ function getDangerousProtoKeys() {
|
|
|
535
547
|
return Array.from(DANGEROUS_PROTO_KEYS);
|
|
536
548
|
}
|
|
537
549
|
|
|
550
|
+
// src/sanitizers/ssti.ts
|
|
551
|
+
var SSTI_DETECT_PATTERNS = [
|
|
552
|
+
/** Jinja2 / Twig / Nunjucks: {{ ... }} */
|
|
553
|
+
/\{\{.*?\}\}/g,
|
|
554
|
+
/** Freemarker / Thymeleaf / Spring EL: ${ ... } */
|
|
555
|
+
/\$\{.*?\}/g,
|
|
556
|
+
/** ERB / EJS: <%= ... %> or <% ... %> */
|
|
557
|
+
/<%[=\-]?.*?%>/gs,
|
|
558
|
+
/** Pug / Jade / Slim: #{ ... } */
|
|
559
|
+
/#\{.*?\}/g,
|
|
560
|
+
/** Python dunder sandbox escape */
|
|
561
|
+
/__(?:class|mro|subclasses|globals|builtins|import)__/gi,
|
|
562
|
+
/** Jinja2 config leak: {{config.X}} or {{config['X']}} */
|
|
563
|
+
/\{\{\s*config[.\[]/gi,
|
|
564
|
+
/** Jinja2 built-in objects */
|
|
565
|
+
/\{\{\s*(?:self|request|lipsum|cycler|joiner|namespace|range)\b/gi
|
|
566
|
+
];
|
|
567
|
+
var SSTI_REMOVE_PATTERNS = [
|
|
568
|
+
/\{\{.*?\}\}/g,
|
|
569
|
+
/\$\{.*?\}/g,
|
|
570
|
+
/<%[=\-]?.*?%>/gs,
|
|
571
|
+
/#\{.*?\}/g,
|
|
572
|
+
/__(?:class|mro|subclasses|globals|builtins|import)__/gi
|
|
573
|
+
];
|
|
574
|
+
function sanitizeSsti(input, collectThreats = false) {
|
|
575
|
+
if (typeof input !== "string") {
|
|
576
|
+
return collectThreats ? { value: String(input), wasSanitized: false, threats: [] } : String(input);
|
|
577
|
+
}
|
|
578
|
+
const threats = [];
|
|
579
|
+
let value = input;
|
|
580
|
+
let wasSanitized = false;
|
|
581
|
+
for (const pattern of SSTI_REMOVE_PATTERNS) {
|
|
582
|
+
pattern.lastIndex = 0;
|
|
583
|
+
if (pattern.test(value)) {
|
|
584
|
+
pattern.lastIndex = 0;
|
|
585
|
+
if (collectThreats) {
|
|
586
|
+
const matches = value.match(pattern);
|
|
587
|
+
if (matches) {
|
|
588
|
+
for (const match of matches) {
|
|
589
|
+
threats.push({
|
|
590
|
+
type: "ssti",
|
|
591
|
+
pattern: pattern.source,
|
|
592
|
+
original: match
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
value = value.replace(pattern, "");
|
|
598
|
+
wasSanitized = true;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (collectThreats) {
|
|
602
|
+
return { value, wasSanitized, threats };
|
|
603
|
+
}
|
|
604
|
+
return value;
|
|
605
|
+
}
|
|
606
|
+
function detectSsti(input) {
|
|
607
|
+
if (typeof input !== "string") return false;
|
|
608
|
+
for (const pattern of SSTI_DETECT_PATTERNS) {
|
|
609
|
+
pattern.lastIndex = 0;
|
|
610
|
+
if (pattern.test(input)) {
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/sanitizers/xxe.ts
|
|
618
|
+
var XXE_DETECT_PATTERNS = [
|
|
619
|
+
/** DOCTYPE declaration */
|
|
620
|
+
/<!DOCTYPE\b/gi,
|
|
621
|
+
/** ENTITY declaration */
|
|
622
|
+
/<!ENTITY\b/gi,
|
|
623
|
+
/** SYSTEM keyword with URI */
|
|
624
|
+
/\bSYSTEM\s+["']/gi,
|
|
625
|
+
/** PUBLIC keyword with URI */
|
|
626
|
+
/\bPUBLIC\s+["']/gi,
|
|
627
|
+
/** Parameter entity reference (%entity;) */
|
|
628
|
+
/%\s*\w+\s*;/g,
|
|
629
|
+
/** CDATA section (often used to smuggle payloads) */
|
|
630
|
+
/<!\[CDATA\[/gi
|
|
631
|
+
];
|
|
632
|
+
var XXE_REMOVE_PATTERNS = [
|
|
633
|
+
/** Full DOCTYPE block with optional internal subset: <!DOCTYPE ... [...]> */
|
|
634
|
+
/<!DOCTYPE\s[^[>]*(?:\[[^\]]*\]\s*)?>|<!DOCTYPE\s[^>]*>/gi,
|
|
635
|
+
/** Full ENTITY declaration: <!ENTITY ... > */
|
|
636
|
+
/<!ENTITY[^>]*>/gi,
|
|
637
|
+
/** CDATA sections: <![CDATA[ ... ]]> */
|
|
638
|
+
/<!\[CDATA\[[\s\S]*?\]\]>/gi
|
|
639
|
+
];
|
|
640
|
+
function sanitizeXxe(input, collectThreats = false) {
|
|
641
|
+
if (typeof input !== "string") {
|
|
642
|
+
return collectThreats ? { value: String(input), wasSanitized: false, threats: [] } : String(input);
|
|
643
|
+
}
|
|
644
|
+
const threats = [];
|
|
645
|
+
let value = input;
|
|
646
|
+
let wasSanitized = false;
|
|
647
|
+
for (const pattern of XXE_REMOVE_PATTERNS) {
|
|
648
|
+
pattern.lastIndex = 0;
|
|
649
|
+
if (pattern.test(value)) {
|
|
650
|
+
pattern.lastIndex = 0;
|
|
651
|
+
if (collectThreats) {
|
|
652
|
+
const matches = value.match(pattern);
|
|
653
|
+
if (matches) {
|
|
654
|
+
for (const match of matches) {
|
|
655
|
+
threats.push({
|
|
656
|
+
type: "xxe",
|
|
657
|
+
pattern: pattern.source,
|
|
658
|
+
original: match
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
value = value.replace(pattern, "");
|
|
664
|
+
wasSanitized = true;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (collectThreats) {
|
|
668
|
+
return { value, wasSanitized, threats };
|
|
669
|
+
}
|
|
670
|
+
return value;
|
|
671
|
+
}
|
|
672
|
+
function detectXxe(input) {
|
|
673
|
+
if (typeof input !== "string") return false;
|
|
674
|
+
for (const pattern of XXE_DETECT_PATTERNS) {
|
|
675
|
+
pattern.lastIndex = 0;
|
|
676
|
+
if (pattern.test(input)) {
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// src/sanitizers/jsonp.ts
|
|
684
|
+
var SAFE_CALLBACK_PATTERN = /^[a-zA-Z_$][a-zA-Z0-9_$.[\]]*$/;
|
|
685
|
+
var DANGEROUS_CALLBACK_PATTERNS = [
|
|
686
|
+
/\.\./,
|
|
687
|
+
// prototype chain traversal
|
|
688
|
+
/\[\s*\]/
|
|
689
|
+
// empty bracket access
|
|
690
|
+
];
|
|
691
|
+
function sanitizeJsonpCallback(callback, maxLength = 128) {
|
|
692
|
+
if (typeof callback !== "string" || callback.length === 0) {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
if (callback.length > maxLength) {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
if (!SAFE_CALLBACK_PATTERN.test(callback)) {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
for (const pattern of DANGEROUS_CALLBACK_PATTERNS) {
|
|
702
|
+
if (pattern.test(callback)) {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return callback;
|
|
707
|
+
}
|
|
708
|
+
function detectJsonpInjection(callback) {
|
|
709
|
+
if (typeof callback !== "string" || callback.length === 0) {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
if (!SAFE_CALLBACK_PATTERN.test(callback)) {
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
715
|
+
for (const pattern of DANGEROUS_CALLBACK_PATTERNS) {
|
|
716
|
+
if (pattern.test(callback)) {
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
|
|
538
723
|
// src/sanitizers/headers.ts
|
|
539
724
|
var HEADER_INJECTION_PATTERN = /\r\n|\r|\n|\0/g;
|
|
540
725
|
function sanitizeHeaderValue(input, collectThreats = false) {
|
|
@@ -584,27 +769,242 @@ function detectHeaderInjection(input) {
|
|
|
584
769
|
return HEADER_INJECTION_PATTERN.test(input);
|
|
585
770
|
}
|
|
586
771
|
|
|
772
|
+
// src/sanitizers/pii.ts
|
|
773
|
+
var EMAIL_RE = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z]{2,})+/g;
|
|
774
|
+
var PHONE_RE = /(?:\+?1[-.\s]?)?\(?[2-9]\d{2}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
|
|
775
|
+
var CREDIT_CARD_RE = /\b(?:\d[ -]*?){13,19}\b/g;
|
|
776
|
+
var SSN_RE = /\b\d{3}[-\s]\d{2}[-\s]\d{4}\b/g;
|
|
777
|
+
var IPV4_RE = /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b/g;
|
|
778
|
+
var IPV6_RE = /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b(?:[0-9a-fA-F]{1,4}:){1,7}:|::(?:[0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4}\b/g;
|
|
779
|
+
var PATTERN_MAP = {
|
|
780
|
+
email: [EMAIL_RE],
|
|
781
|
+
phone: [PHONE_RE],
|
|
782
|
+
credit_card: [CREDIT_CARD_RE],
|
|
783
|
+
ssn: [SSN_RE],
|
|
784
|
+
ip_address: [IPV4_RE, IPV6_RE]
|
|
785
|
+
};
|
|
786
|
+
var ALL_TYPES = ["email", "phone", "credit_card", "ssn", "ip_address"];
|
|
787
|
+
var TYPE_LABELS = {
|
|
788
|
+
email: "[EMAIL]",
|
|
789
|
+
phone: "[PHONE]",
|
|
790
|
+
credit_card: "[CREDIT_CARD]",
|
|
791
|
+
ssn: "[SSN]",
|
|
792
|
+
ip_address: "[IP_ADDRESS]"
|
|
793
|
+
};
|
|
794
|
+
function luhnCheck(value) {
|
|
795
|
+
const digits = value.replace(/[\s-]/g, "");
|
|
796
|
+
if (!/^\d{13,19}$/.test(digits)) return false;
|
|
797
|
+
let sum = 0;
|
|
798
|
+
let alternate = false;
|
|
799
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
800
|
+
let n = parseInt(digits[i], 10);
|
|
801
|
+
if (alternate) {
|
|
802
|
+
n *= 2;
|
|
803
|
+
if (n > 9) n -= 9;
|
|
804
|
+
}
|
|
805
|
+
sum += n;
|
|
806
|
+
alternate = !alternate;
|
|
807
|
+
}
|
|
808
|
+
return sum % 10 === 0;
|
|
809
|
+
}
|
|
810
|
+
function scanPii(input, options = {}) {
|
|
811
|
+
if (!input || typeof input !== "string") return [];
|
|
812
|
+
const types = options.types ?? ALL_TYPES;
|
|
813
|
+
const matches = [];
|
|
814
|
+
for (const type of types) {
|
|
815
|
+
const patterns = PATTERN_MAP[type];
|
|
816
|
+
if (!patterns) continue;
|
|
817
|
+
for (const pattern of patterns) {
|
|
818
|
+
const re = new RegExp(pattern.source, pattern.flags);
|
|
819
|
+
let match;
|
|
820
|
+
while ((match = re.exec(input)) !== null) {
|
|
821
|
+
const value = match[0];
|
|
822
|
+
if (type === "credit_card" && !luhnCheck(value)) continue;
|
|
823
|
+
if (type === "ssn") {
|
|
824
|
+
const area = parseInt(value.substring(0, 3), 10);
|
|
825
|
+
if (area === 0 || area === 666 || area >= 900) continue;
|
|
826
|
+
}
|
|
827
|
+
matches.push({
|
|
828
|
+
type,
|
|
829
|
+
value,
|
|
830
|
+
start: match.index,
|
|
831
|
+
end: match.index + value.length
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
matches.sort((a, b) => a.start - b.start);
|
|
837
|
+
return matches;
|
|
838
|
+
}
|
|
839
|
+
function detectPii(input, options = {}) {
|
|
840
|
+
return scanPii(input, options).length > 0;
|
|
841
|
+
}
|
|
842
|
+
function redactPii(input, options = {}) {
|
|
843
|
+
if (!input || typeof input !== "string") return input;
|
|
844
|
+
const matches = scanPii(input, options);
|
|
845
|
+
if (matches.length === 0) return input;
|
|
846
|
+
const replacement = options.replacement ?? "[REDACTED]";
|
|
847
|
+
let result = input;
|
|
848
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
849
|
+
const m = matches[i];
|
|
850
|
+
const label = options.typeLabels ? TYPE_LABELS[m.type] : replacement;
|
|
851
|
+
result = result.substring(0, m.start) + label + result.substring(m.end);
|
|
852
|
+
}
|
|
853
|
+
return result;
|
|
854
|
+
}
|
|
855
|
+
function scanObjectPii(obj, options = {}, path = "") {
|
|
856
|
+
const results = [];
|
|
857
|
+
if (!obj || typeof obj !== "object") return results;
|
|
858
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
859
|
+
const fieldPath = path ? `${path}.${key}` : key;
|
|
860
|
+
if (typeof value === "string") {
|
|
861
|
+
const matches = scanPii(value, options);
|
|
862
|
+
for (const m of matches) {
|
|
863
|
+
results.push({ ...m, field: fieldPath });
|
|
864
|
+
}
|
|
865
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
866
|
+
results.push(...scanObjectPii(value, options, fieldPath));
|
|
867
|
+
} else if (Array.isArray(value)) {
|
|
868
|
+
for (let i = 0; i < value.length; i++) {
|
|
869
|
+
const item = value[i];
|
|
870
|
+
if (typeof item === "string") {
|
|
871
|
+
const matches = scanPii(item, options);
|
|
872
|
+
for (const m of matches) {
|
|
873
|
+
results.push({ ...m, field: `${fieldPath}[${i}]` });
|
|
874
|
+
}
|
|
875
|
+
} else if (item && typeof item === "object") {
|
|
876
|
+
results.push(...scanObjectPii(item, options, `${fieldPath}[${i}]`));
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return results;
|
|
882
|
+
}
|
|
883
|
+
function redactObjectPii(obj, options = {}) {
|
|
884
|
+
if (!obj || typeof obj !== "object") return obj;
|
|
885
|
+
const result = {};
|
|
886
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
887
|
+
if (typeof value === "string") {
|
|
888
|
+
result[key] = redactPii(value, options);
|
|
889
|
+
} else if (Array.isArray(value)) {
|
|
890
|
+
result[key] = value.map((item) => {
|
|
891
|
+
if (typeof item === "string") return redactPii(item, options);
|
|
892
|
+
if (item && typeof item === "object") return redactObjectPii(item, options);
|
|
893
|
+
return item;
|
|
894
|
+
});
|
|
895
|
+
} else if (value && typeof value === "object") {
|
|
896
|
+
result[key] = redactObjectPii(value, options);
|
|
897
|
+
} else {
|
|
898
|
+
result[key] = value;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return result;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// src/sanitizers/encode.ts
|
|
905
|
+
var HTML_ENTITIES = {
|
|
906
|
+
"&": "&",
|
|
907
|
+
"<": "<",
|
|
908
|
+
">": ">",
|
|
909
|
+
'"': """,
|
|
910
|
+
"'": "'"
|
|
911
|
+
};
|
|
912
|
+
var HTML_ENCODE_RE = /[&<>"']/g;
|
|
913
|
+
function encodeForHtml(value) {
|
|
914
|
+
if (!value) return "";
|
|
915
|
+
return value.replace(HTML_ENCODE_RE, (ch) => HTML_ENTITIES[ch]);
|
|
916
|
+
}
|
|
917
|
+
function encodeForAttribute(value) {
|
|
918
|
+
if (!value) return "";
|
|
919
|
+
let result = "";
|
|
920
|
+
for (let i = 0; i < value.length; i++) {
|
|
921
|
+
const ch = value.charCodeAt(i);
|
|
922
|
+
if (ch >= 48 && ch <= 57 || // 0-9
|
|
923
|
+
ch >= 65 && ch <= 90 || // A-Z
|
|
924
|
+
ch >= 97 && ch <= 122) {
|
|
925
|
+
result += value[i];
|
|
926
|
+
} else {
|
|
927
|
+
result += `&#x${ch.toString(16).toUpperCase()};`;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return result;
|
|
931
|
+
}
|
|
932
|
+
function encodeForJs(value) {
|
|
933
|
+
if (!value) return "";
|
|
934
|
+
let result = "";
|
|
935
|
+
for (let i = 0; i < value.length; i++) {
|
|
936
|
+
const ch = value.charCodeAt(i);
|
|
937
|
+
if (ch >= 48 && ch <= 57 || // 0-9
|
|
938
|
+
ch >= 65 && ch <= 90 || // A-Z
|
|
939
|
+
ch >= 97 && ch <= 122) {
|
|
940
|
+
result += value[i];
|
|
941
|
+
} else if (ch < 256) {
|
|
942
|
+
result += `\\x${ch.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
943
|
+
} else {
|
|
944
|
+
result += `\\u${ch.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
return result;
|
|
948
|
+
}
|
|
949
|
+
function encodeForUrl(value) {
|
|
950
|
+
if (!value) return "";
|
|
951
|
+
return encodeURIComponent(value).replace(/[!'()*]/g, (ch) => {
|
|
952
|
+
return `%${ch.charCodeAt(0).toString(16).toUpperCase()}`;
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
function encodeForCss(value) {
|
|
956
|
+
if (!value) return "";
|
|
957
|
+
let result = "";
|
|
958
|
+
for (let i = 0; i < value.length; i++) {
|
|
959
|
+
const ch = value.charCodeAt(i);
|
|
960
|
+
if (ch >= 48 && ch <= 57 || // 0-9
|
|
961
|
+
ch >= 65 && ch <= 90 || // A-Z
|
|
962
|
+
ch >= 97 && ch <= 122) {
|
|
963
|
+
result += value[i];
|
|
964
|
+
} else {
|
|
965
|
+
result += `\\${ch.toString(16).toUpperCase()} `;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return result;
|
|
969
|
+
}
|
|
970
|
+
|
|
587
971
|
exports.createSanitizer = createSanitizer;
|
|
588
972
|
exports.detectCommandInjection = detectCommandInjection;
|
|
589
973
|
exports.detectHeaderInjection = detectHeaderInjection;
|
|
974
|
+
exports.detectJsonpInjection = detectJsonpInjection;
|
|
590
975
|
exports.detectNoSqlInjection = detectNoSqlInjection;
|
|
591
976
|
exports.detectPathTraversal = detectPathTraversal;
|
|
977
|
+
exports.detectPii = detectPii;
|
|
592
978
|
exports.detectPrototypePollution = detectPrototypePollution;
|
|
593
979
|
exports.detectSql = detectSql;
|
|
980
|
+
exports.detectSsti = detectSsti;
|
|
594
981
|
exports.detectXss = detectXss;
|
|
982
|
+
exports.detectXxe = detectXxe;
|
|
983
|
+
exports.encodeForAttribute = encodeForAttribute;
|
|
984
|
+
exports.encodeForCss = encodeForCss;
|
|
985
|
+
exports.encodeForHtml = encodeForHtml;
|
|
986
|
+
exports.encodeForJs = encodeForJs;
|
|
987
|
+
exports.encodeForUrl = encodeForUrl;
|
|
595
988
|
exports.encodeHtmlEntities = encodeHtmlEntities;
|
|
596
989
|
exports.getDangerousOperators = getDangerousOperators;
|
|
597
990
|
exports.getDangerousProtoKeys = getDangerousProtoKeys;
|
|
598
991
|
exports.isDangerousNoSqlKey = isDangerousNoSqlKey;
|
|
599
992
|
exports.isDangerousProtoKey = isDangerousProtoKey;
|
|
600
993
|
exports.isPlainObject = isPlainObject;
|
|
994
|
+
exports.redactObjectPii = redactObjectPii;
|
|
995
|
+
exports.redactPii = redactPii;
|
|
601
996
|
exports.sanitizeCommand = sanitizeCommand;
|
|
602
997
|
exports.sanitizeHeaderValue = sanitizeHeaderValue;
|
|
603
998
|
exports.sanitizeHeaders = sanitizeHeaders;
|
|
999
|
+
exports.sanitizeJsonpCallback = sanitizeJsonpCallback;
|
|
604
1000
|
exports.sanitizeObject = sanitizeObject;
|
|
605
1001
|
exports.sanitizePath = sanitizePath;
|
|
606
1002
|
exports.sanitizeSql = sanitizeSql;
|
|
1003
|
+
exports.sanitizeSsti = sanitizeSsti;
|
|
607
1004
|
exports.sanitizeString = sanitizeString;
|
|
608
1005
|
exports.sanitizeXss = sanitizeXss;
|
|
1006
|
+
exports.sanitizeXxe = sanitizeXxe;
|
|
1007
|
+
exports.scanObjectPii = scanObjectPii;
|
|
1008
|
+
exports.scanPii = scanPii;
|
|
609
1009
|
//# sourceMappingURL=index.js.map
|
|
610
1010
|
//# sourceMappingURL=index.js.map
|