11import sanitizeHtml from "sanitize-html" ;
22
33const MAX_INPUT_LENGTH = 10000 ;
4+ const MAX_LINE_COUNT = 500 ;
5+
6+ type ValidationResult = {
7+ isValid : boolean ;
8+ reason ?: string ;
9+ } ;
410
511function normalizeInput ( input : string ) : string {
612 return input
@@ -21,32 +27,120 @@ function enforceLengthLimit(input: string): string {
2127 : input ;
2228}
2329
30+ function removeControlCharacters (
31+ input : string
32+ ) : string {
33+ return input . replace (
34+ / [ \u0001 - \u001F \u007F ] / g,
35+ ""
36+ ) ;
37+ }
38+
39+ function removeSuspiciousUnicode (
40+ input : string
41+ ) : string {
42+ return input . replace (
43+ / [ \u202A - \u202E \u2066 - \u2069 ] / g,
44+ ""
45+ ) ;
46+ }
47+
48+ function limitLineCount (
49+ input : string
50+ ) : string {
51+ const lines =
52+ input . split ( "\n" ) ;
53+
54+ return lines
55+ . slice ( 0 , MAX_LINE_COUNT )
56+ . join ( "\n" ) ;
57+ }
58+
59+ export function validateInput (
60+ input : string
61+ ) : ValidationResult {
62+ if (
63+ input . length >
64+ MAX_INPUT_LENGTH * 2
65+ ) {
66+ return {
67+ isValid : false ,
68+ reason :
69+ "Input exceeds validation threshold" ,
70+ } ;
71+ }
72+
73+ return {
74+ isValid : true ,
75+ } ;
76+ }
77+
78+ export function securityAuditInput (
79+ input : string
80+ ) {
81+ return {
82+ containsScript :
83+ / < s c r i p t / i. test ( input ) ,
84+ containsEventHandlers :
85+ / o n \w + = / i. test ( input ) ,
86+ containsJavascriptUrl :
87+ / j a v a s c r i p t : / i. test ( input ) ,
88+ inputLength :
89+ input . length ,
90+ } ;
91+ }
92+
2493export function sanitizeInput (
2594 input : string | null | undefined
2695) : string {
2796 if ( ! input ) {
2897 return "" ;
2998 }
3099
100+ const validation =
101+ validateInput ( input ) ;
102+
103+ if ( ! validation . isValid ) {
104+ return "" ;
105+ }
106+
31107 const normalizedInput =
32108 normalizeInput ( input ) ;
33109
34- const sanitized = sanitizeHtml (
35- normalizedInput ,
36- {
37- allowedTags : [ ] ,
38- allowedAttributes : { } ,
39- allowedSchemes : [ ] ,
40- parser : {
41- lowerCaseTags : true ,
42- } ,
43- }
44- ) ;
110+ const controlSafe =
111+ removeControlCharacters (
112+ normalizedInput
113+ ) ;
114+
115+ const unicodeSafe =
116+ removeSuspiciousUnicode (
117+ controlSafe
118+ ) ;
119+
120+ const sanitized =
121+ sanitizeHtml (
122+ unicodeSafe ,
123+ {
124+ allowedTags : [ ] ,
125+ allowedAttributes : { } ,
126+ allowedSchemes : [ ] ,
127+ parser : {
128+ lowerCaseTags : true ,
129+ } ,
130+ }
131+ ) ;
132+
133+ const normalizedWhitespace =
134+ normalizeWhitespace (
135+ sanitized
136+ ) ;
45137
46- const cleanedInput =
47- normalizeWhitespace ( sanitized ) ;
138+ const lineLimited =
139+ limitLineCount (
140+ normalizedWhitespace
141+ ) ;
48142
49143 return enforceLengthLimit (
50- cleanedInput
144+ lineLimited
51145 ) ;
52146}
0 commit comments