package recon import ( "testing" "time" ) func TestProfileOptions(t *testing.T) { quick := ProfileOptions(ProfileQuick) if len(quick.Ports) != 10 || quick.MaxPages != 1 || quick.SkipPorts { t.Fatalf("quick=%+v", quick) } deep := ProfileOptions(ProfileDeep) if deep.MaxPages != 50 || deep.CrawlDepth != 2 { t.Fatalf("deep=%+v", deep) } ssrf := ProfileOptions(ProfileSSRFOnly) if !ssrf.SkipPorts || ssrf.MaxPages != 50 { t.Fatalf("ssrf=%+v", ssrf) } } func TestScanStreamEmitsPortsFirst(t *testing.T) { SetPortDialHook(func(host string, port int, _ time.Duration) bool { return port == 80 || port == 443 }) t.Cleanup(func() { SetPortDialHook(nil) }) SetFetchPageHook(func(rawURL string) (int, string, error) { return 200, `Home`, nil }) t.Cleanup(func() { SetFetchPageHook(nil) }) var events []string report, err := ScanStream(ScanRequest{Host: "stream.lab", Profile: ProfileQuick, Port: 80, Scheme: "http"}, "scan-1", func(eventType string, _ map[string]interface{}) { events = append(events, eventType) }) if err != nil { t.Fatal(err) } if report.ScanID != "scan-1" || report.Profile != ProfileQuick { t.Fatalf("report=%+v", report) } if len(events) == 0 { t.Fatal("expected streaming events") } firstPort := -1 for i, e := range events { if e == "recon_port" && firstPort < 0 { firstPort = i } } if firstPort < 0 { t.Fatalf("missing recon_port events: %v", events) } for i, e := range events { if e == "recon_page" && i < firstPort { t.Fatalf("pages before ports: %v", events) } } } func TestDiffReportsNewPortsAndForms(t *testing.T) { prev := &ScanReport{ Ports: []PortResult{{Port: 80, Open: true}}, Crawl: &CrawlReport{MultipartForms: []FormFinding{{PageURL: "http://a/", Action: "/upload"}}}, } cur := &ScanReport{ Ports: []PortResult{{Port: 80, Open: true}, {Port: 443, Open: true}}, Crawl: &CrawlReport{ MultipartForms: []FormFinding{ {PageURL: "http://a/", Action: "/upload"}, {PageURL: "http://a/admin", Action: "/post"}, }, }, } diff := DiffReports(prev, cur) if len(diff.NewPorts) != 1 || diff.NewPorts[0] != 443 { t.Fatalf("ports=%v", diff.NewPorts) } if len(diff.NewForms) != 1 || diff.NewForms[0].Action != "/post" { t.Fatalf("forms=%v", diff.NewForms) } } func TestBuildHistoryDiffChain(t *testing.T) { now := time.Now().UTC() rows := []*ScanReport{ {ScanID: "a", Host: "h", ScannedAt: now, Ports: []PortResult{{Port: 22, Open: true}}}, {ScanID: "b", Host: "h", ScannedAt: now.Add(time.Minute), Ports: []PortResult{{Port: 22, Open: true}, {Port: 80, Open: true}}}, } hist := BuildHistory(rows) if len(hist) != 2 || hist[0].Diff == nil || len(hist[0].Diff.NewPorts) != 1 { t.Fatalf("first diff=%+v", hist[0].Diff) } if hist[1].Diff == nil || len(hist[1].Diff.NewPorts) != 1 || hist[1].Diff.NewPorts[0] != 80 { t.Fatalf("second diff=%+v", hist[1].Diff) } }