Files
god-eye/internal/sources/base.go
Vyntral b1bf119c82 v0.1.1: Major AI improvements, new security modules, and documentation fixes
## AI & CVE Improvements
- Fix AI report to display actual subdomain names instead of generic placeholders
- Add 10-year CVE filter to reduce false positives from outdated vulnerabilities
- Integrate CISA KEV (Known Exploited Vulnerabilities) database support
- Improve AI analysis prompt for more accurate security findings

## New Security Modules
- Add wildcard DNS detection with multi-phase validation (DNS + HTTP)
- Add TLS certificate analyzer for certificate chain inspection
- Add comprehensive rate limiting module for API requests
- Add retry mechanism with exponential backoff
- Add stealth mode for reduced detection during scans
- Add progress tracking module for better UX

## Code Refactoring
- Extract scanner output logic to dedicated module
- Add base source interface for consistent passive source implementation
- Reduce admin panel paths to common generic patterns only
- Improve HTTP client with connection pooling
- Add JSON output formatter

## Documentation Updates
- Correct passive source count to 20 (was incorrectly stated as 34)
- Fix AI model names: deepseek-r1:1.5b (fast) + qwen2.5-coder:7b (deep)
- Update all markdown files for consistency
- Relocate demo GIFs to assets/ directory
- Add benchmark disclaimer for test variability

## Files Changed
- 4 documentation files updated (README, AI_SETUP, BENCHMARK, EXAMPLES)
- 11 new source files added
- 12 existing files modified
2025-11-21 12:00:58 +01:00

86 lines
2.2 KiB
Go

package sources
import (
"context"
"fmt"
"io"
"net/http"
"regexp"
"strings"
"time"
)
// sharedClient is reused across all source fetches
var sharedClient = &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 30 * time.Second,
},
}
// regexFetch performs a fetch and extracts subdomains using regex
// This reduces code duplication across many sources
func regexFetch(url string, domain string, timeout time.Duration) ([]string, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return []string{}, nil
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36")
resp, err := sharedClient.Do(req)
if err != nil {
return []string{}, nil
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return []string{}, nil
}
return extractSubdomains(string(body), domain), nil
}
// extractSubdomains extracts subdomains from text using regex
func extractSubdomains(text, domain string) []string {
// Compile regex once per call (could cache but domain changes)
pattern := fmt.Sprintf(`(?i)([a-z0-9][a-z0-9._-]*\.%s)`, regexp.QuoteMeta(domain))
re := regexp.MustCompile(pattern)
matches := re.FindAllStringSubmatch(text, -1)
seen := make(map[string]bool)
var subs []string
for _, match := range matches {
if len(match) > 1 {
name := strings.ToLower(match[1])
// Filter out invalid patterns
if !seen[name] && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, domain) {
seen[name] = true
subs = append(subs, name)
}
}
}
return subs
}
// dedupeAndFilter filters subdomains and ensures they belong to the target domain
func dedupeAndFilter(subs []string, domain string) []string {
seen := make(map[string]bool)
var result []string
for _, sub := range subs {
sub = strings.ToLower(strings.TrimSpace(sub))
sub = strings.TrimPrefix(sub, "*.")
if sub != "" && !seen[sub] && strings.HasSuffix(sub, domain) {
seen[sub] = true
result = append(result, sub)
}
}
return result
}