@@ -26,50 +26,143 @@ const ScannerUI = () => {
2626 const files = Array . from ( event . target . files ) ;
2727 if ( files . length === 0 ) return ;
2828
29+ // Validate files first
30+ const validFiles = files . filter ( file => {
31+ // Check file size (max 10MB)
32+ if ( file . size > 10 * 1024 * 1024 ) {
33+ setError ( `File ${ file . name } is too large (max 10MB)` ) ;
34+ return false ;
35+ }
36+
37+ // Check file type - extensive list of file types that could contain vulnerabilities
38+ const validExtensions = [
39+ // Web/Frontend
40+ '.js' , '.jsx' , '.ts' , '.tsx' , '.html' , '.htm' , '.css' , '.scss' , '.sass' , '.less' , '.vue' , '.svelte' ,
41+ // Backend
42+ '.py' , '.rb' , '.php' , '.java' , '.jsp' , '.asp' , '.aspx' , '.cs' , '.go' , '.rs' , '.scala' , '.kt' , '.kts' ,
43+ // Configuration/Infrastructure
44+ '.xml' , '.yaml' , '.yml' , '.json' , '.toml' , '.ini' , '.conf' , '.config' , '.env' , '.properties' ,
45+ '.dockerfile' , 'dockerfile' , '.docker-compose.yml' , '.docker-compose.yaml' ,
46+ // Shell/Scripts
47+ '.sh' , '.bash' , '.zsh' , '.bat' , '.cmd' , '.ps1' , '.psm1' ,
48+ // Database
49+ '.sql' , '.graphql' , '.prisma' ,
50+ // Mobile
51+ '.swift' , '.m' , '.h' , '.mm' , '.kotlin' , '.gradle' ,
52+ // Other
53+ '.pl' , '.pm' , '.t' , '.perl' , '.cgi' , // Perl
54+ '.lua' , // Lua
55+ '.r' , '.rmd' , // R
56+ '.c' , '.cpp' , '.cc' , '.cxx' , '.h' , '.hpp' , // C/C++
57+ '.ex' , '.exs' , // Elixir
58+ '.erl' , '.hrl' , // Erlang
59+ '.hs' , '.lhs' , // Haskell
60+ '.ml' , '.mli' , // OCaml
61+ '.fs' , '.fsx' , '.fsi' , // F#
62+ // Template files
63+ '.ejs' , '.pug' , '.jade' , '.hbs' , '.mustache' , '.twig' , '.liquid' ,
64+ // Build/Package files
65+ 'package.json' , 'package-lock.json' , 'yarn.lock' , 'pom.xml' , 'build.gradle' ,
66+ 'requirements.txt' , 'pipfile' , 'gemfile' , 'cargo.toml' , 'mix.exs'
67+ ] ;
68+
69+ const ext = file . name . toLowerCase ( ) ;
70+ const isValidExtension = validExtensions . some ( validExt => {
71+ if ( validExt . startsWith ( '.' ) ) {
72+ return ext . endsWith ( validExt ) ;
73+ }
74+ // For exact filename matches (like 'dockerfile')
75+ return ext === validExt ;
76+ } ) ;
77+
78+ if ( ! isValidExtension ) {
79+ setError ( `File type ${ ext } is not supported` ) ;
80+ return false ;
81+ }
82+
83+ return true ;
84+ } ) ;
85+
86+ if ( validFiles . length === 0 ) {
87+ setError ( 'No valid files to scan' ) ;
88+ return ;
89+ }
90+
2991 setScanning ( true ) ;
3092 setError ( null ) ;
31- setProgress ( { current : 0 , total : files . length } ) ;
93+ setProgress ( { current : 0 , total : validFiles . length } ) ;
3294 setScanResults ( null ) ;
3395 setUsedCache ( false ) ;
3496
3597 try {
3698 const scanner = new VulnerabilityScanner ( {
3799 enableNewPatterns : true ,
38- enablePackageScanners : true
100+ enablePackageScanners : true ,
101+ onProgress : ( current , total ) => {
102+ setProgress ( { current, total } ) ;
103+ }
39104 } ) ;
40105
41106 let allFindings = [ ] ;
42107 let processedFiles = 0 ;
43108
44- for ( const file of files ) {
45- try {
46- const content = await file . text ( ) ;
47- const fileFindings = await scanner . scanFile ( content , file . name ) ;
48- allFindings . push ( ...fileFindings ) ;
109+ // Process files in batches to avoid memory issues
110+ const batchSize = 5 ;
111+ for ( let i = 0 ; i < validFiles . length ; i += batchSize ) {
112+ const batch = validFiles . slice ( i , i + batchSize ) ;
113+ const batchPromises = batch . map ( async ( file ) => {
114+ try {
115+ const content = await file . text ( ) ;
116+ const fileFindings = await scanner . scanFile ( content , file . name ) ;
117+ return { file : file . name , findings : fileFindings } ;
118+ } catch ( err ) {
119+ console . error ( `Error scanning file ${ file . name } :` , err ) ;
120+ return { file : file . name , error : err . message } ;
121+ }
122+ } ) ;
123+
124+ const batchResults = await Promise . all ( batchPromises ) ;
125+ batchResults . forEach ( result => {
126+ if ( result . findings ) {
127+ allFindings . push ( ...result . findings ) ;
128+ }
49129 processedFiles ++ ;
50- setProgress ( { current : processedFiles , total : files . length } ) ;
51- } catch ( err ) {
52- console . error ( `Error scanning file ${ file . name } :` , err ) ;
53- }
130+ setProgress ( { current : processedFiles , total : validFiles . length } ) ;
131+ } ) ;
54132 }
55133
56- // Process findings to ensure proper structure and maintain array format
57- const processedFindings = allFindings . map ( finding => ( {
58- ...finding ,
59- severity : finding . severity || 'LOW' ,
60- description : finding . description || 'No description provided' ,
61- allLineNumbers : { [ finding . file ] : finding . lineNumbers || [ ] }
62- } ) ) ;
134+ // Process findings to ensure proper structure
135+ const processedFindings = allFindings . reduce ( ( acc , finding ) => {
136+ const key = finding . type ;
137+ if ( ! acc [ key ] ) {
138+ acc [ key ] = {
139+ type : finding . type ,
140+ severity : finding . severity || 'LOW' ,
141+ description : finding . description || 'No description provided' ,
142+ allLineNumbers : { [ finding . file ] : finding . lineNumbers || [ ] }
143+ } ;
144+ } else {
145+ // Merge line numbers if same type
146+ const file = finding . file ;
147+ if ( ! acc [ key ] . allLineNumbers [ file ] ) {
148+ acc [ key ] . allLineNumbers [ file ] = finding . lineNumbers || [ ] ;
149+ } else {
150+ const merged = new Set ( [ ...acc [ key ] . allLineNumbers [ file ] , ...finding . lineNumbers ] ) ;
151+ acc [ key ] . allLineNumbers [ file ] = Array . from ( merged ) . sort ( ( a , b ) => a - b ) ;
152+ }
153+ }
154+ return acc ;
155+ } , { } ) ;
63156
64- const report = scanner . generateReport ( processedFindings ) ;
157+ const report = scanner . generateReport ( allFindings ) ;
65158 setScanResults ( {
66- ... report ,
67- findings : processedFindings // Keep findings as array for local scans
159+ findings : processedFindings ,
160+ summary : report . summary || { }
68161 } ) ;
69162
70163 const { criticalIssues = 0 , highIssues = 0 , mediumIssues = 0 , lowIssues = 0 } = report . summary || { } ;
71164 setSuccessMessage (
72- `Scan complete! Found ${ processedFindings . length } potential vulnerabilities ` +
165+ `Scan complete! Found ${ Object . keys ( processedFindings ) . length } potential vulnerabilities ` +
73166 `(${ criticalIssues } critical, ${ highIssues } high, ${ mediumIssues } medium, ${ lowIssues } low)`
74167 ) ;
75168 } catch ( err ) {
0 commit comments