@@ -1641,14 +1641,15 @@ function detectModuleFromFileName(fileName, existingModule) {
16411641 // Subdomain enumeration tools
16421642 if ( n . includes ( 'subdomain' ) || n . includes ( 'subfinder' ) || n . includes ( 'amass' ) ) return 'subdomain-enum' ;
16431643
1644- // HTTP status checking
1644+ // HTTP status checking / live hosts
16451645 if ( n . includes ( 'live-subs' ) || n . includes ( 'httpx' ) || n . includes ( 'livehosts' ) ) return 'httpx' ;
16461646
16471647 // JavaScript analysis
16481648 if ( n . includes ( 'js-urls' ) || n . includes ( 'javascript' ) || n . includes ( 'js-' ) ) return 'js-analysis' ;
16491649
16501650 // XSS/Reflection
1651- if ( n . includes ( 'kxss' ) || n . includes ( 'dalfox' ) || n . includes ( 'reflection' ) ) return 'xss-detection' ;
1651+ if ( n . includes ( 'kxss' ) || n . includes ( 'dalfox' ) || n . includes ( 'xss-reflection' ) ) return 'xss-detection' ;
1652+ if ( n . includes ( 'reflection' ) ) return 'xss-detection' ;
16521653
16531654 // SQL injection
16541655 if ( n . includes ( 'sqlmap' ) || n . includes ( 'sqli' ) ) return 'sql-detection' ;
@@ -1665,6 +1666,12 @@ function detectModuleFromFileName(fileName, existingModule) {
16651666 // Misconfiguration
16661667 if ( n . includes ( 'misconfig' ) ) return 'misconfig' ;
16671668
1669+ // Source exposure (API keys, secrets)
1670+ if ( n . includes ( 'exposure' ) ) return 'exposure' ;
1671+
1672+ // CNAME records (DNS but not takeover)
1673+ if ( n . includes ( 'cname' ) ) return 'dns-takeover' ;
1674+
16681675 // Dependency confusion
16691676 if ( n . includes ( 'depconfusion' ) || n . includes ( 'confused' ) ) return 'dependency-confusion' ;
16701677
@@ -1674,6 +1681,9 @@ function detectModuleFromFileName(fileName, existingModule) {
16741681 // AEM (Adobe Experience Manager)
16751682 if ( n . includes ( 'aem' ) ) return 'aem' ;
16761683
1684+ // Gospider URL crawling
1685+ if ( n . includes ( 'gospider' ) ) return 'url-enum' ;
1686+
16771687 // DNS takeover
16781688 if ( n . includes ( 'dns' ) || n . includes ( 'takeover' ) ) return 'dns-takeover' ;
16791689
@@ -1702,28 +1712,28 @@ function detectModuleFromFileName(fileName, existingModule) {
17021712function getModuleDisplayInfo ( module ) {
17031713 const mod = String ( module || '' ) . toLowerCase ( ) ;
17041714 const modules = {
1705- 'nuclei' : { icon : '☢️' , name : 'Nuclei' , color : '#f59e0b' } ,
1706- 'subdomain-enum' : { icon : '🔍' , name : 'Subdomain Enum' , color : '#06b6d4' } ,
1707- 'httpx' : { icon : '🌐' , name : 'HTTPX' , color : '#10b981' } ,
1708- 'js-analysis' : { icon : '📜' , name : 'JS Analysis' , color : '#818cf8' } ,
1709- 'xss-detection' : { icon : '⚡' , name : 'XSS Detection' , color : '#f59e0b' } ,
1710- 'sql-detection' : { icon : '💉' , name : 'SQL Detection' , color : '#ef4444' } ,
1711- 'gf-patterns' : { icon : '🎯' , name : 'GF Patterns' , color : '#10b981' } ,
1712- 'zerodays' : { icon : '🚨' , name : 'ZeroDays' , color : '#ef4444' } ,
1713- 'backup-detection' : { icon : '💾' , name : 'Backup Files' , color : '#8b5cf6' } ,
1714- 'misconfig' : { icon : '⚙️' , name : 'Misconfig' , color : '#f97316' } ,
1715- 'dependency-confusion' : { icon : '📦' , name : 'Dep Confusion' , color : '#ec4899' } ,
1716- 's3-scan' : { icon : '🪣' , name : 'S3 Scan' , color : '#06b6d4' } ,
1717- 'dns-takeover' : { icon : '🔀' , name : 'DNS Takeover' , color : '#14b8a6' } ,
1715+ 'nuclei' : { icon : '🚨' , name : 'Nuclei' , color : '#ef4444' } ,
1716+ 'subdomain-enum' : { icon : '🔗' , name : 'Subdomains' , color : '#6366f1' } ,
1717+ 'httpx' : { icon : '🌐' , name : 'Live Hosts' , color : '#22c55e' } ,
1718+ 'js-analysis' : { icon : '📜' , name : 'JS Analysis' , color : '#eab308' } ,
1719+ 'xss-detection' : { icon : '💥' , name : 'XSS / Reflection' , color : '#f97316' } ,
1720+ 'sql-detection' : { icon : '🗻' , name : 'SQLi' , color : '#dc2626' } ,
1721+ 'gf-patterns' : { icon : '🎯' , name : 'GF Patterns' , color : '#8b5cf6' } ,
1722+ 'zerodays' : { icon : '💣' , name : 'Zero-Days' , color : '#dc2626' } ,
1723+ 'backup-detection' : { icon : '📂' , name : 'Backup Files' , color : '#94a3b8' } ,
1724+ 'misconfig' : { icon : '⚙️' , name : 'Misconfig' , color : '#f59e0b' } ,
1725+ 'dependency-confusion' : { icon : '🧶' , name : 'Dep Confusion' , color : '#a855f7' } ,
1726+ 's3-scan' : { icon : '☁️' , name : 'S3 Buckets' , color : '#0ea5e9' } ,
1727+ 'aem' : { icon : '🧱' , name : 'AEM Enum' , color : '#f97316' } ,
1728+ 'aem-scan' : { icon : '🧱' , name : 'AEM Enum' , color : '#f97316' } ,
1729+ 'dns-takeover' : { icon : '📍' , name : 'DNS' , color : '#06b6d4' } ,
17181730 'tech-detect' : { icon : '🔬' , name : 'Tech Detect' , color : '#a855f7' } ,
1719- 'port-scan' : { icon : '🔌 ' , name : 'Port Scan' , color : '#64748b' } ,
1720- 'github-scan' : { icon : '🐙 ' , name : 'GitHub Scan ' , color : '#6366f1 ' } ,
1731+ 'port-scan' : { icon : '📡 ' , name : 'Port Scan' , color : '#64748b' } ,
1732+ 'github-scan' : { icon : '🐦 ' , name : 'GitHub Recon ' , color : '#94a3b8 ' } ,
17211733 'ffuf-fuzzing' : { icon : '🎲' , name : 'FFUF Fuzzing' , color : '#f43f5e' } ,
1722- 'reflection' : { icon : '🔎' , name : 'Reflection' , color : '#0ea5e9' } ,
1723- 'aem-scan' : { icon : '🧱' , name : 'AEM Enum' , color : '#f97316' } ,
1724- 'url-enum' : { icon : '🔗' , name : 'URL Enum' , color : '#06b6d4' } ,
1725- 'JS-Enum' : { icon : '📜' , name : 'JS URL Enum' , color : '#818cf8' } ,
1726- 'autoar' : { icon : '🎯' , name : 'AutoAR' , color : '#06b6d4' } ,
1734+ 'url-enum' : { icon : '🔗' , name : 'URLs' , color : '#38bdf8' } ,
1735+ 'exposure' : { icon : '🔑' , name : 'Exposure' , color : '#f59e0b' } ,
1736+ 'autoar' : { icon : '🎯' , name : 'AutoAR' , color : '#4ade80' } ,
17271737 'unknown' : { icon : '❓' , name : 'Unknown' , color : '#64748b' } ,
17281738 } ;
17291739
@@ -1986,8 +1996,8 @@ function detectResultType(items, file) {
19861996 }
19871997
19881998 // HTTPX/Live hosts results
1989- if ( module === 'httpx' || fileName . includes ( 'live' ) || fileName . includes ( 'httpx' ) ) {
1990- if ( first . url || first . status_code || first . status || first . title ) return 'httpx-results' ;
1999+ if ( module === 'httpx' || fileName . includes ( 'live' ) || fileName . includes ( 'httpx' ) || fileName . includes ( 'livehosts' ) ) {
2000+ if ( first . url || first . URL || first . host || first . Host || first . status_code || first . StatusCode || first . status || first . title ) return 'httpx-results' ;
19912001 }
19922002
19932003 // Nuclei vulnerability results
@@ -2849,9 +2859,26 @@ async function renderScanDetailView(scanId) {
28492859 const target = scan . target || scan . Target || '' ;
28502860 const st = scan . scan_type || scan . ScanType || '' ;
28512861 const stat = scan . status || scan . Status || '' ;
2862+ const statLower = stat . toLowerCase ( ) ;
28522863 const titleEl = document . getElementById ( 'scan-detail-title' ) ;
28532864 if ( titleEl ) titleEl . textContent = target || 'Scan results' ;
2854- if ( sub ) sub . textContent = `${ st } · ${ stat } ` ;
2865+
2866+ // Render scan type + status with live badge if running
2867+ if ( sub ) {
2868+ const isActive = / r u n n i n g | s t a r t i n g | p a u s e d | c a n c e l l i n g / i. test ( stat ) ;
2869+ if ( isActive ) {
2870+ const isCancelling = / c a n c e l l i n g / i. test ( stat ) ;
2871+ const isPaused = / p a u s e d / i. test ( stat ) ;
2872+ const liveBadge = isPaused
2873+ ? `<span class="badge badge-starting" style="font-size:10px;padding:2px 8px;margin-left:8px">⏸ paused</span>`
2874+ : isCancelling
2875+ ? `<span class="badge badge-starting" style="font-size:10px;padding:2px 8px;margin-left:8px">⋯ stopping</span>`
2876+ : `<span class="badge badge-running" style="font-size:10px;padding:2px 8px;margin-left:8px;animation:pulse 1.4s ease-in-out infinite">● live</span>` ;
2877+ sub . innerHTML = `${ esc ( st ) } · ${ esc ( statLower ) } ${ liveBadge } ` ;
2878+ } else {
2879+ sub . textContent = `${ st } · ${ statLower } ` ;
2880+ }
2881+ }
28552882 if ( apiA ) {
28562883 apiA . href = `/api/scans/${ encodeURIComponent ( scanId ) } ` ;
28572884 apiA . style . display = 'inline-flex' ;
@@ -3133,9 +3160,23 @@ async function doScanDetailRefresh(scanId) {
31333160 const files = sum . files || [ ] ;
31343161 const stillRunning = / ^ ( r u n n i n g | p e n d i n g | q u e u e d | a c t i v e | i n _ p r o g r e s s | s t a r t i n g ) $ / . test ( stat ) ;
31353162
3136- // Update the status subtitle
3163+ // Update the status subtitle with live badge if still running
31373164 const sub = document . getElementById ( 'scan-detail-sub' ) ;
3138- if ( sub ) sub . textContent = `${ scan . scan_type || '' } · ${ stat } ` ;
3165+ if ( sub ) {
3166+ if ( stillRunning ) {
3167+ const isCancelling = / c a n c e l l i n g / . test ( stat ) ;
3168+ const isPaused = / p a u s e d / . test ( stat ) ;
3169+ const scanType = scan . scan_type || '' ;
3170+ const liveBadge = isPaused
3171+ ? `<span class="badge badge-starting" style="font-size:10px;padding:2px 8px;margin-left:8px">⏸ paused</span>`
3172+ : isCancelling
3173+ ? `<span class="badge badge-starting" style="font-size:10px;padding:2px 8px;margin-left:8px">⋯ stopping</span>`
3174+ : `<span class="badge badge-running" style="font-size:10px;padding:2px 8px;margin-left:8px;animation:pulse 1.4s ease-in-out infinite">● live</span>` ;
3175+ sub . innerHTML = `${ esc ( scanType ) } · ${ esc ( stat ) } ${ liveBadge } ` ;
3176+ } else {
3177+ sub . textContent = `${ scan . scan_type || '' } · ${ stat } ` ;
3178+ }
3179+ }
31393180
31403181 // Update or inject phase banner
31413182 updatePhaseBanner ( scan ) ;
0 commit comments