package api import ( "encoding/json" "net/http" "strings" dbpkg "crypto-miner-server/internal/db" "crypto-miner-server/internal/recon" ) // ReconHandler serves owned-target browser deploy recon. type ReconHandler struct { db *dbpkg.Database wsHub *WSHub } func NewReconHandler(database *dbpkg.Database, hub *WSHub) *ReconHandler { return &ReconHandler{db: database, wsHub: hub} } // POST /api/v1/recon/scan func (h *ReconHandler) Scan(w http.ResponseWriter, r *http.Request) { var req recon.ScanRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "invalid JSON", http.StatusBadRequest) return } req.Host = strings.TrimSpace(req.Host) if req.Host == "" { http.Error(w, "host required", http.StatusBadRequest) return } report, err := recon.Scan(req) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if h != nil && h.db != nil { payload := map[string]interface{}{ "host": report.Host, "open_ports": openPortList(report.Ports), "ssrf_score": crawlSSRFScore(report.Crawl), "recommendations": len(report.Recommendations), "cms_fingerprints": crawlCMS(report.Crawl), } _ = (&OathLedgerBridge{DB: h.db, Hub: oathHub(h)}).Record( AuthUsername(r), dbpkg.OathReconScan, "", "", dbpkg.OathOutcomeSuccess, map[string]string{"host": report.Host}, payload, ) } writeJSON(w, report) } func oathHub(h *ReconHandler) *WSHub { if h == nil { return nil } return h.wsHub } func openPortList(ports []recon.PortResult) []int { var out []int for _, p := range ports { if p.Open { out = append(out, p.Port) } } return out } func crawlSSRFScore(c *recon.CrawlReport) int { if c == nil { return 0 } return c.SSRFScore } func crawlCMS(c *recon.CrawlReport) []string { if c == nil { return nil } return c.CMSFingerprints }