430 lines
14 KiB
Go
430 lines
14 KiB
Go
package cmd
|
|
|
|
import (
|
|
"dehasher/internal/badger"
|
|
"dehasher/internal/debug"
|
|
"dehasher/internal/export"
|
|
"dehasher/internal/files"
|
|
hunter "dehasher/internal/hunter.io"
|
|
"dehasher/internal/pretty"
|
|
"fmt"
|
|
"github.com/spf13/cobra"
|
|
"go.uber.org/zap"
|
|
"time"
|
|
)
|
|
|
|
func init() {
|
|
// Add hunter command to root command
|
|
rootCmd.AddCommand(hunterCmd)
|
|
|
|
// Add flags specific to hunter command
|
|
hunterCmd.Flags().StringVarP(&hunterDomain, "domain", "d", "", "Domain to query")
|
|
hunterCmd.Flags().StringVarP(&hunterEmail, "email", "e", "", "Email to query")
|
|
hunterCmd.Flags().StringVarP(&hunterFirstName, "first-name", "F", "", "First name to query")
|
|
hunterCmd.Flags().StringVarP(&hunterLastName, "last-name", "L", "", "Last name to query")
|
|
hunterCmd.Flags().BoolVarP(&hunterDomainSearch, "domain-search", "D", false, "Search for domain")
|
|
hunterCmd.Flags().BoolVarP(&hunterEmailFind, "email-find", "E", false, "Find emails for user using domain, first name, and last name")
|
|
hunterCmd.Flags().BoolVarP(&hunterEmailVerify, "email-verify", "V", false, "Verify email")
|
|
hunterCmd.Flags().BoolVarP(&hunterCompanyEnrichmentDomain, "company-enrichment", "C", false, "Company enrichment for domain")
|
|
hunterCmd.Flags().BoolVarP(&hunterPersonEnrichmentEmail, "person-enrichment", "P", false, "Person enrichment for email")
|
|
hunterCmd.Flags().BoolVarP(&hunterCombinedEnrichmentEmail, "combined-enrichment", "B", false, "Combined Company and Person enrichment for email")
|
|
hunterCmd.Flags().StringVarP(&hunterOutputFormat, "format", "f", "json", "Output format (json, yaml, xml, txt)")
|
|
hunterCmd.Flags().StringVarP(&hunterOutputFile, "output", "o", "hunter", "File to output results to including extension")
|
|
|
|
// Add mutually exclusive flags to hunter command
|
|
hunterCmd.MarkFlagsMutuallyExclusive("email-find")
|
|
|
|
}
|
|
|
|
var (
|
|
// Hunter Commands Flags
|
|
hunterDomain string
|
|
hunterEmail string
|
|
hunterFirstName string
|
|
hunterLastName string
|
|
hunterDomainSearch bool
|
|
hunterEmailFind bool
|
|
hunterEmailVerify bool
|
|
hunterCompanyEnrichmentDomain bool
|
|
hunterPersonEnrichmentEmail bool
|
|
hunterCombinedEnrichmentEmail bool
|
|
hunterOutputFormat string
|
|
hunterOutputFile string
|
|
|
|
hunterCmd = &cobra.Command{
|
|
Use: "hunter",
|
|
Short: "Hunter.io API interaction",
|
|
Long: `Interact with the Hunter.io API for email and domain information.`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
if debugGlobal {
|
|
debug.PrintInfo("debug mode enabled")
|
|
zap.L().Info("hunter_debug",
|
|
zap.String("message", "debug mode enabled"),
|
|
)
|
|
}
|
|
|
|
// Flag Checks
|
|
if !hunterFlagCheck() {
|
|
return
|
|
}
|
|
|
|
if hunterOutputFile == "" {
|
|
if debugGlobal {
|
|
debug.PrintInfo("output file not specified, using default")
|
|
}
|
|
hunterOutputFile = "hunter_" + time.Now().Format("05_04_05")
|
|
}
|
|
|
|
if hunterOutputFormat == "" {
|
|
if debugGlobal {
|
|
debug.PrintInfo("output format not specified, using default")
|
|
}
|
|
hunterOutputFormat = "json"
|
|
}
|
|
|
|
fType := files.GetFileType(hunterOutputFormat)
|
|
if fType == files.UNKNOWN {
|
|
fmt.Println("[!] Error: Invalid output format. Must be 'json', 'xml', 'yaml', or 'txt'.")
|
|
return
|
|
}
|
|
if debugGlobal {
|
|
debug.PrintInfo("using output format: " + hunterOutputFormat)
|
|
}
|
|
|
|
fmt.Println("[*] Hunter.io API interaction [Beta]")
|
|
|
|
h := hunter.NewHunterIO(getHunterApiKey(), debugGlobal)
|
|
|
|
if hunterDomainSearch {
|
|
fmt.Println("[*] Performing domain search search...")
|
|
result, err := h.DomainSearch(hunterDomain)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to perform domain search")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("hunter_domain_search",
|
|
zap.String("message", "failed to perform domain search"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error performing domain search: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Write Hunter.io Domain Search Result to file
|
|
fmt.Printf("[*] Writing Hunter.io Domain Search Result to file: %s%s\n", hunterOutputFile, fType.Extension())
|
|
err = export.WriteHunterDomainToFile(result, hunterOutputFile, fType)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to write hunter domain search to file")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("write_hunter_domain_search",
|
|
zap.String("message", "failed to write hunter domain search to file"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error writing Hunter.io Domain Search Result to file: %v\n", err)
|
|
}
|
|
|
|
// Pretty Print Hunter.io Domain Search Result
|
|
fmt.Println("Domain Search Result:")
|
|
pretty.HunterDomainTree(hunterDomain, result)
|
|
return
|
|
}
|
|
|
|
if hunterEmailFind {
|
|
fmt.Println("[*] Performing email find search...")
|
|
result, err := h.EmailFinder(hunterDomain, hunterFirstName, hunterLastName)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to perform email find")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("hunter_email_find",
|
|
zap.String("message", "failed to perform email find"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error performing email find: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Write Hunter.io Email Finder Result to file
|
|
fmt.Printf("[*] Writing Hunter.io Email Finder Result to file: %s%s\n", hunterOutputFile, fType.Extension())
|
|
err = export.WriteHunterEmailToFile(result, hunterOutputFile, fType)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to write hunter email find to file")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("write_hunter_email_find",
|
|
zap.String("message", "failed to write hunter email find to file"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error writing Hunter.io Email Finder Result to file: %v\n", err)
|
|
}
|
|
|
|
fmt.Println("Email Find Result:")
|
|
|
|
var (
|
|
headers = []string{"Email", "Score", "Domain", "Accept All", "Position", "Twitter", "Linkedin", "Phone Number", "Company", "Sources", "Verification"}
|
|
rows [][]string
|
|
)
|
|
|
|
rows = append(rows, []string{
|
|
result.Email,
|
|
fmt.Sprintf("%d", result.Score),
|
|
result.Domain,
|
|
fmt.Sprintf("%t", result.AcceptAll),
|
|
result.Position,
|
|
result.Twitter,
|
|
result.LinkedinURL,
|
|
result.PhoneNumber,
|
|
result.Company,
|
|
fmt.Sprintf("%v", result.Sources),
|
|
fmt.Sprintf("%v", result.Verification),
|
|
})
|
|
|
|
pretty.Table(headers, rows)
|
|
|
|
return
|
|
}
|
|
|
|
if hunterEmailVerify {
|
|
fmt.Println("[*] Performing email verification search...")
|
|
result, err := h.EmailVerification(hunterEmail)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to perform email verification")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("hunter_email_verification",
|
|
zap.String("message", "failed to perform email verification"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error performing email verification: %v\n", err)
|
|
return
|
|
}
|
|
// Write Hunter.io Email Verification Result to file
|
|
fmt.Printf("[*] Writing Hunter.io Email Verification Result to file: %s%s\n", hunterOutputFile, fType.Extension())
|
|
err = export.WriteHunterEmailVerifyToFile(result, hunterOutputFile, fType)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to write hunter email verification to file")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("write_hunter_email_verification",
|
|
zap.String("message", "failed to write hunter email verification to file"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error writing Hunter.io Email Verification Result to file: %v\n", err)
|
|
}
|
|
|
|
// Pretty Print Hunter.io Email Verification Result
|
|
var (
|
|
headers = []string{"Email", "Status", "Result", "Score", "Regexp", "Gibberish", "Disposable", "Webmail", "MX Records", "SMTP Server", "SMTP Check", "Accept All", "Block", "Sources"}
|
|
rows [][]string
|
|
)
|
|
rows = append(rows, []string{
|
|
result.Email,
|
|
result.Status,
|
|
result.Result,
|
|
fmt.Sprintf("%d", result.Score),
|
|
fmt.Sprintf("%t", result.Regexp),
|
|
fmt.Sprintf("%t", result.Gibberish),
|
|
fmt.Sprintf("%t", result.Disposable),
|
|
fmt.Sprintf("%t", result.Webmail),
|
|
fmt.Sprintf("%t", result.MXRecords),
|
|
fmt.Sprintf("%t", result.SMTPServer),
|
|
fmt.Sprintf("%t", result.SMTPCheck),
|
|
fmt.Sprintf("%t", result.AcceptAll),
|
|
fmt.Sprintf("%t", result.Block),
|
|
fmt.Sprintf("%v", result.Sources),
|
|
})
|
|
|
|
fmt.Println("Email Verification Result:")
|
|
pretty.Table(headers, rows)
|
|
return
|
|
}
|
|
|
|
if hunterCompanyEnrichmentDomain {
|
|
fmt.Println("[*] Performing company enrichment search...")
|
|
result, err := h.CompanyEnrichment(hunterDomain)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to perform company enrichment")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("hunter_company_enrichment",
|
|
zap.String("message", "failed to perform company enrichment"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error performing company enrichment: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Write to file
|
|
fmt.Printf("[*] Writing Hunter.io Company Enrichment Result to file: %s%s\n", hunterOutputFile, fType.Extension())
|
|
err = export.WriteHunterCompanyEnrichmentToFile(result, hunterOutputFile, fType)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to write hunter company enrichment to file")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("write_hunter_company_enrichment",
|
|
zap.String("message", "failed to write hunter company enrichment to file"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error writing Hunter.io Company Enrichment Result to file: %v\n", err)
|
|
}
|
|
|
|
// Pretty Print Hunter.io Company Enrichment Result
|
|
fmt.Println("Company Enrichment Result:")
|
|
pretty.HunterCompanyEnrichmentTree(hunterDomain, result)
|
|
|
|
return
|
|
}
|
|
|
|
if hunterPersonEnrichmentEmail {
|
|
fmt.Println("[*] Performing person enrichment search...")
|
|
result, err := h.PersonEnrichment(hunterEmail)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to perform person enrichment")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("hunter_person_enrichment",
|
|
zap.String("message", "failed to perform person enrichment"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error performing person enrichment: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Write to file
|
|
fmt.Printf("[*] Writing Hunter.io Person Enrichment Result to file: %s%s\n", hunterOutputFile, fType.Extension())
|
|
err = export.WriteHunterPersonEnrichmentToFile(result, hunterOutputFile, fType)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to write hunter person enrichment to file")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("write_hunter_person_enrichment",
|
|
zap.String("message", "failed to write hunter person enrichment to file"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error writing Hunter.io Person Enrichment Result to file: %v\n", err)
|
|
}
|
|
|
|
// Pretty Print Hunter.io Person Enrichment Result
|
|
fmt.Println("Person Enrichment Result:")
|
|
pretty.HunterPersonEnrichmentTree(hunterEmail, result)
|
|
return
|
|
}
|
|
|
|
if hunterCombinedEnrichmentEmail {
|
|
fmt.Println("[*] Performing combined enrichment search...")
|
|
result, err := h.CombinedEnrichment(hunterEmail)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to perform combined enrichment")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("hunter_combined_enrichment",
|
|
zap.String("message", "failed to perform combined enrichment"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error performing combined enrichment: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Write to file
|
|
fmt.Printf("[*] Writing Hunter.io Combined Enrichment Result to file: %s%s\n", hunterOutputFile, fType.Extension())
|
|
err = export.WriteHunterCombinedEnrichmentToFile(result, hunterOutputFile, fType)
|
|
if err != nil {
|
|
if debugGlobal {
|
|
debug.PrintInfo("failed to write hunter combined enrichment to file")
|
|
debug.PrintError(err)
|
|
}
|
|
zap.L().Error("write_hunter_combined_enrichment",
|
|
zap.String("message", "failed to write hunter combined enrichment to file"),
|
|
zap.Error(err),
|
|
)
|
|
fmt.Printf("Error writing Hunter.io Combined Enrichment Result to file: %v\n", err)
|
|
}
|
|
|
|
fmt.Println("Combined Enrichment Result:")
|
|
pretty.HunterCombinedEnrichmentTree(hunterEmail, result)
|
|
return
|
|
}
|
|
|
|
},
|
|
}
|
|
)
|
|
|
|
func hunterFlagCheck() bool {
|
|
if debugGlobal {
|
|
debug.PrintInfo("checking flags")
|
|
}
|
|
|
|
var optionSet bool
|
|
|
|
if hunterDomainSearch {
|
|
if hunterDomain == "" {
|
|
fmt.Println("Domain is required for domain search")
|
|
return false
|
|
}
|
|
optionSet = true
|
|
}
|
|
if hunterEmailVerify {
|
|
if hunterEmail == "" {
|
|
fmt.Println("Email is required for email verification")
|
|
return false
|
|
}
|
|
optionSet = true
|
|
}
|
|
if hunterCompanyEnrichmentDomain {
|
|
if hunterDomain == "" {
|
|
fmt.Println("Domain is required for company enrichment")
|
|
return false
|
|
}
|
|
optionSet = true
|
|
}
|
|
if hunterPersonEnrichmentEmail {
|
|
if hunterEmail == "" {
|
|
fmt.Println("Email is required for person enrichment")
|
|
return false
|
|
}
|
|
optionSet = true
|
|
}
|
|
if hunterCombinedEnrichmentEmail {
|
|
if hunterEmail == "" {
|
|
fmt.Println("Email is required for combined enrichment")
|
|
return false
|
|
}
|
|
optionSet = true
|
|
}
|
|
if hunterEmailFind {
|
|
if hunterFirstName == "" || hunterLastName == "" {
|
|
fmt.Println("First name and last name are required for email find")
|
|
return false
|
|
}
|
|
if hunterDomain == "" {
|
|
fmt.Println("Domain is required for email find")
|
|
return false
|
|
}
|
|
optionSet = true
|
|
}
|
|
|
|
if !optionSet {
|
|
fmt.Println("[!] No options selected")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Helper functions to get stored API credentials
|
|
func getHunterApiKey() string {
|
|
return badger.GetHunterKey()
|
|
}
|