mirror of
https://github.com/Vyntral/god-eye.git
synced 2026-05-18 14:24:49 +02:00
3a4c230aa7
Complete architectural overhaul. Replaces the v0.1 monolithic scanner with an event-driven pipeline of auto-registered modules. Foundation (internal/): - eventbus: typed pub/sub, 20 event types, race-safe, drop counter - module: registry with phase-based selection - store: thread-safe host store with per-host locks + deep-copy reads - pipeline: coordinator with phase barriers + panic recovery - config: 5 scan profiles + 3 AI tiers + YAML loader + auto-discovery Modules (26 auto-registered across 6 phases): - Discovery: passive (26 sources), bruteforce, recursive, AXFR, GitHub dorks, CT streaming, permutation, reverse DNS, vhost, ASN, supply chain (npm + PyPI) - Enrichment: HTTP probe + tech fingerprint + TLS appliance ID, ports - Analysis: security checks, takeover (110+ sigs), cloud, JavaScript, GraphQL, JWT, headers (OWASP), HTTP smuggling, AI cascade, Nuclei - Reporting: TXT/JSON/CSV writer + AI scan brief AI layer (internal/ai/ + internal/modules/ai/): - Three profiles: lean (16 GB), balanced (32 GB MoE), heavy (64 GB) - Six event-driven handlers: CVE, JS file, HTTP response, secret filter, multi-agent vuln enrichment, anomaly + executive report - Content-hash cache dedups Ollama calls across hosts - Auto-pull of missing models via /api/pull with streaming progress - End-of-scan AI SCAN BRIEF in terminal with top chains + next actions Nuclei compat layer (internal/nucleitpl/): - Executes ~13k community templates (HTTP subset) - Auto-download of nuclei-templates ZIP to ~/.god-eye/nuclei-templates - Scope filter rejects off-host templates (eliminates OSINT FPs) Operations: - Interactive wizard (internal/wizard/) — zero-flag launch - LivePrinter (internal/tui/) — colorized event stream - Diff engine + scheduler (internal/diff, internal/scheduler) for continuous ASM monitoring with webhook alerts - Proxy support (internal/proxyconf/): http / https / socks5 / socks5h + basic auth Fixes #1 — native SOCKS5 / Tor compatibility via --proxy flag. 185 unit tests across 15 packages, all race-detector clean.
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
// Package recursive is a Fase 0.6 adapter for the v1 recursive discovery
|
|
// engine (pattern learning from found subdomains).
|
|
//
|
|
// Unlike event-driven modules, recursive runs as a deferred second-pass:
|
|
// after PhaseDiscovery completes it collects every host seen so far from
|
|
// the store, runs the v1 engine, and emits SubdomainDiscovered for any
|
|
// new hosts. It self-schedules in PhaseResolution to sit between discovery
|
|
// and HTTP probing.
|
|
package recursive
|
|
|
|
import (
|
|
"time"
|
|
|
|
"god-eye/internal/discovery"
|
|
"god-eye/internal/eventbus"
|
|
"god-eye/internal/module"
|
|
"god-eye/internal/store"
|
|
"strings"
|
|
)
|
|
|
|
const ModuleName = "discovery.recursive"
|
|
|
|
type recModule struct{}
|
|
|
|
func Register() { module.Register(&recModule{}) }
|
|
|
|
func (*recModule) Name() string { return ModuleName }
|
|
func (*recModule) Phase() module.Phase { return module.PhaseResolution } // runs after discovery
|
|
func (*recModule) Consumes() []eventbus.EventType { return []eventbus.EventType{eventbus.EventSubdomainDiscovered} }
|
|
func (*recModule) Produces() []eventbus.EventType {
|
|
return []eventbus.EventType{eventbus.EventSubdomainDiscovered}
|
|
}
|
|
|
|
// Recursive is opt-in by default — profiles enable it for bugbounty/pentest.
|
|
func (*recModule) DefaultEnabled() bool { return false }
|
|
|
|
func (*recModule) Run(mctx module.Context) error {
|
|
if !mctx.Config.Bool("recursive", false) {
|
|
return nil
|
|
}
|
|
|
|
target := mctx.Target
|
|
depth := mctx.Config.Int("recursive.depth", 3)
|
|
if depth < 1 {
|
|
depth = 1
|
|
} else if depth > 5 {
|
|
depth = 5
|
|
}
|
|
timeout := mctx.Config.Int("timeout", 5)
|
|
conc := mctx.Config.Int("concurrency", 500)
|
|
if conc <= 0 {
|
|
conc = 500
|
|
}
|
|
|
|
resolvers := parseResolvers(mctx.Config.String("resolvers", ""))
|
|
|
|
// Gather initial seeds from what's been discovered so far.
|
|
hosts := mctx.Store.All(mctx.Ctx)
|
|
seeds := make([]string, 0, len(hosts))
|
|
for _, h := range hosts {
|
|
seeds = append(seeds, h.Subdomain)
|
|
}
|
|
if len(seeds) == 0 {
|
|
return nil
|
|
}
|
|
|
|
rd := discovery.NewRecursiveDiscovery(discovery.RecursiveConfig{
|
|
Domain: target,
|
|
Resolvers: resolvers,
|
|
Timeout: timeout,
|
|
MaxDepth: depth,
|
|
Concurrency: conc,
|
|
})
|
|
found := rd.Discover(mctx.Ctx, seeds)
|
|
|
|
// Emit SubdomainDiscovered for any new hosts.
|
|
seen := make(map[string]struct{}, len(seeds))
|
|
for _, s := range seeds {
|
|
seen[s] = struct{}{}
|
|
}
|
|
for _, s := range found {
|
|
if _, dup := seen[s]; dup {
|
|
continue
|
|
}
|
|
seen[s] = struct{}{}
|
|
|
|
_ = mctx.Store.Upsert(mctx.Ctx, s, func(h *store.Host) {
|
|
store.AddDiscoveryMethod(h, "recursive")
|
|
})
|
|
|
|
mctx.Bus.Publish(mctx.Ctx, eventbus.SubdomainDiscovered{
|
|
EventMeta: eventbus.EventMeta{At: time.Now(), Source: ModuleName, Target: s},
|
|
Subdomain: s,
|
|
Method: "recursive",
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseResolvers(s string) []string {
|
|
s = strings.TrimSpace(s)
|
|
if s == "" {
|
|
return []string{"8.8.8.8:53", "1.1.1.1:53"}
|
|
}
|
|
var out []string
|
|
for _, r := range strings.Split(s, ",") {
|
|
r = strings.TrimSpace(r)
|
|
if r == "" {
|
|
continue
|
|
}
|
|
if !strings.Contains(r, ":") {
|
|
r = r + ":53"
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out
|
|
}
|