package output import ( "fmt" "os" "github.com/charmbracelet/lipgloss" "github.com/salvacybersec/keyhunter/pkg/engine" ) var ( styleHigh = lipgloss.NewStyle().Foreground(lipgloss.Color("2")) // green styleMedium = lipgloss.NewStyle().Foreground(lipgloss.Color("3")) // yellow styleLow = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) // red styleHeader = lipgloss.NewStyle().Bold(true).Underline(true) ) // PrintFindings writes findings as a colored terminal table to stdout. // If unmask is true, KeyValue is shown; otherwise KeyMasked is shown. func PrintFindings(findings []engine.Finding, unmask bool) { if len(findings) == 0 { fmt.Println("No API keys found.") return } // Header fmt.Fprintf(os.Stdout, "%-20s %-40s %-10s %-30s %s\n", styleHeader.Render("PROVIDER"), styleHeader.Render("KEY"), styleHeader.Render("CONFIDENCE"), styleHeader.Render("SOURCE"), styleHeader.Render("LINE"), ) fmt.Println(lipgloss.NewStyle().Foreground(lipgloss.Color("8")).Render( "──────────────────────────────────────────────────────────────────────────────────────────────────────────", )) for _, f := range findings { keyDisplay := f.KeyMasked if unmask { keyDisplay = f.KeyValue } confStyle := styleLow switch f.Confidence { case "high": confStyle = styleHigh case "medium": confStyle = styleMedium } fmt.Fprintf(os.Stdout, "%-20s %-40s %-10s %-30s %d\n", f.ProviderName, keyDisplay, confStyle.Render(f.Confidence), truncate(f.Source, 28), f.LineNumber, ) } fmt.Printf("\n%d key(s) found.\n", len(findings)) } func truncate(s string, max int) string { if len(s) <= max { return s } return "..." + s[len(s)-max+3:] }