first commit
This commit is contained in:
@@ -0,0 +1,656 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/export"
|
||||
"dehasher/internal/files"
|
||||
"dehasher/internal/pretty"
|
||||
"dehasher/internal/sqlite"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// DB command flags
|
||||
dbPath string
|
||||
|
||||
// DB query command flags
|
||||
usernameDBQuery string
|
||||
emailDBQuery string
|
||||
ipDBQuery string
|
||||
passwordDBQuery string
|
||||
hashDBQuery string
|
||||
nameDBQuery string
|
||||
vinDBQuery string
|
||||
licensePlateDBQuery string
|
||||
addressDBQuery string
|
||||
phoneDBQuery string
|
||||
socialDBQuery string
|
||||
cryptoCurrencyAddressDBQuery string
|
||||
domainDBQuery string
|
||||
limitResultsDB int
|
||||
exactMatchDBQuery bool
|
||||
outputFormatDB string
|
||||
nonEmptyFieldsDBQuery string
|
||||
displayFieldsDBQuery string
|
||||
tableTypeDBQuery string
|
||||
|
||||
// DB runs command flags
|
||||
startDateDBRuns string
|
||||
endDateDBRuns string
|
||||
containsQueryDBRuns string
|
||||
lastXRunsDBRuns int
|
||||
|
||||
// DB command
|
||||
dbCmd = &cobra.Command{
|
||||
Use: "db",
|
||||
Short: "Database operations for Dehasher",
|
||||
Long: `Perform database operations like export, import, and query on the local Dehasher database.`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add subcommands to db command
|
||||
dbCmd.AddCommand(dbExportCmd)
|
||||
dbCmd.AddCommand(dbQueryCmd)
|
||||
dbCmd.AddCommand(dbRunsCmd)
|
||||
dbCmd.AddCommand(dbCredsCmd)
|
||||
|
||||
// Add flags specific to db command
|
||||
dbCmd.PersistentFlags().StringVarP(&dbPath, "db-path", "D", "", "Path to database (default: ~/.local/share/Dehasher/dehashed.db)")
|
||||
|
||||
// Add flags specific to db query command
|
||||
dbQueryCmd.Flags().StringVarP(&usernameDBQuery, "username", "u", "", "Filter by username")
|
||||
dbQueryCmd.Flags().StringVarP(&emailDBQuery, "email", "e", "", "Filter by email")
|
||||
dbQueryCmd.Flags().StringVarP(&ipDBQuery, "ip", "i", "", "Filter by IP address")
|
||||
dbQueryCmd.Flags().StringVarP(&passwordDBQuery, "password", "p", "", "Filter by password")
|
||||
dbQueryCmd.Flags().StringVarP(&hashDBQuery, "hash", "H", "", "Filter by hashed password")
|
||||
dbQueryCmd.Flags().StringVarP(&nameDBQuery, "name", "n", "", "Filter by name")
|
||||
dbQueryCmd.Flags().StringVarP(&vinDBQuery, "vin", "v", "", "Filter by VIN")
|
||||
dbQueryCmd.Flags().StringVarP(&licensePlateDBQuery, "license", "L", "", "Filter by license plate")
|
||||
dbQueryCmd.Flags().StringVarP(&addressDBQuery, "address", "a", "", "Filter by address")
|
||||
dbQueryCmd.Flags().StringVarP(&phoneDBQuery, "phone", "P", "", "Filter by phone number")
|
||||
dbQueryCmd.Flags().StringVarP(&socialDBQuery, "social", "s", "", "Filter by social media handle")
|
||||
dbQueryCmd.Flags().StringVarP(&cryptoCurrencyAddressDBQuery, "crypto", "c", "", "Filter by cryptocurrency address")
|
||||
dbQueryCmd.Flags().StringVarP(&domainDBQuery, "domain", "d", "", "Filter by domain/URL")
|
||||
dbQueryCmd.Flags().IntVarP(&limitResultsDB, "limit", "l", 100, "Limit number of results")
|
||||
dbQueryCmd.Flags().BoolVarP(&exactMatchDBQuery, "exact", "x", false, "Use exact matching instead of partial matching")
|
||||
dbQueryCmd.Flags().StringVarP(&outputFormatDB, "format", "f", "table", "Output format (json, table, simple)")
|
||||
dbQueryCmd.Flags().StringVar(&nonEmptyFieldsDBQuery, "non-empty", "", "Filter for non-empty fields (comma-separated list, e.g., 'password,email')")
|
||||
dbQueryCmd.Flags().StringVar(&displayFieldsDBQuery, "display", "", "Fields to display in output (comma-separated list, e.g., 'username,email,password')")
|
||||
dbQueryCmd.Flags().StringVarP(&tableTypeDBQuery, "table", "t", "results", "Table to query (results, runs, creds)")
|
||||
|
||||
// Add flags specific to db runs command
|
||||
dbRunsCmd.Flags().StringVarP(&startDateDBRuns, "start-date", "s", "", "Start date for filtering runs (format: YYYY-MM-DD)")
|
||||
dbRunsCmd.Flags().StringVarP(&endDateDBRuns, "end-date", "e", "", "End date for filtering runs (format: YYYY-MM-DD)")
|
||||
dbRunsCmd.Flags().StringVarP(&containsQueryDBRuns, "contains", "c", "", "Filter runs containing this query string")
|
||||
dbRunsCmd.Flags().IntVarP(&lastXRunsDBRuns, "last", "x", 0, "Show the last X runs")
|
||||
dbRunsCmd.Flags().IntVarP(&limitResultsDB, "limit", "l", 100, "Limit number of results")
|
||||
dbRunsCmd.Flags().StringVarP(&outputFormatDB, "format", "f", "table", "Output format (json, table, simple)")
|
||||
|
||||
// Add flags specific to db creds command
|
||||
dbCredsCmd.Flags().StringVarP(&usernameDBQuery, "username", "u", "", "Filter by username")
|
||||
dbCredsCmd.Flags().StringVarP(&emailDBQuery, "email", "e", "", "Filter by email")
|
||||
dbCredsCmd.Flags().StringVarP(&passwordDBQuery, "password", "p", "", "Filter by password")
|
||||
dbCredsCmd.Flags().IntVarP(&limitResultsDB, "limit", "l", 100, "Limit number of results")
|
||||
dbCredsCmd.Flags().BoolVarP(&exactMatchDBQuery, "exact", "x", false, "Use exact matching instead of partial matching")
|
||||
dbCredsCmd.Flags().StringVarP(&outputFormatDB, "format", "f", "table", "Output format (json, table, simple)")
|
||||
dbCredsCmd.Flags().StringVar(&nonEmptyFieldsDBQuery, "non-empty", "", "Filter for non-empty fields (comma-separated list, e.g., 'password,email')")
|
||||
dbCredsCmd.Flags().StringVar(&displayFieldsDBQuery, "display", "", "Fields to display in output (comma-separated list, e.g., 'username,email,password')")
|
||||
}
|
||||
|
||||
// DB export command
|
||||
var dbExportCmd = &cobra.Command{
|
||||
Use: "export",
|
||||
Short: "Export database to file",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("Exporting database...")
|
||||
// Create DBOptions with the provided parameters
|
||||
options := &sqlite.DBOptions{
|
||||
Username: usernameDBQuery,
|
||||
Email: emailDBQuery,
|
||||
IPAddress: ipDBQuery,
|
||||
Password: passwordDBQuery,
|
||||
HashedPassword: hashDBQuery,
|
||||
Name: nameDBQuery,
|
||||
Limit: limitResultsDB,
|
||||
ExactMatch: exactMatchDBQuery,
|
||||
}
|
||||
|
||||
// Parse non-empty fields if provided
|
||||
if nonEmptyFieldsDBQuery != "" {
|
||||
options.NonEmptyFields = strings.Split(nonEmptyFieldsDBQuery, ",")
|
||||
}
|
||||
|
||||
// Parse display fields if provided
|
||||
if displayFieldsDBQuery != "" {
|
||||
options.DisplayFields = strings.Split(displayFieldsDBQuery, ",")
|
||||
}
|
||||
|
||||
// Check if at least one search parameter is provided
|
||||
if options.Username == "" && options.Email == "" && options.IPAddress == "" &&
|
||||
options.Password == "" && options.HashedPassword == "" && options.Name == "" &&
|
||||
len(options.NonEmptyFields) == 0 {
|
||||
fmt.Println("Error: At least one search parameter is required.")
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
|
||||
// Get the count of matching results
|
||||
count, err := sqlite.GetResultsCount(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error counting results: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Query the database
|
||||
results, err := sqlite.QueryResults(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error querying database: %v\n", err)
|
||||
return
|
||||
}
|
||||
dhResults := sqlite.DehashedResults{Results: results}
|
||||
|
||||
fmt.Printf("Found %d results (showing %d):\n", count, len(results))
|
||||
|
||||
// Output results based on format
|
||||
ft := files.GetFileType(outputFormatDB)
|
||||
err = export.WriteToFile(dhResults, "dehasher_export", ft)
|
||||
if err != nil {
|
||||
zap.L().Error("write_to_file",
|
||||
zap.String("message", "failed to write to file"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error writing to file: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Exported successfully to file: dehasher_export%s\n", ft.Extension())
|
||||
},
|
||||
}
|
||||
|
||||
// DB query command
|
||||
var dbQueryCmd = &cobra.Command{
|
||||
Use: "query",
|
||||
Short: "Query local database",
|
||||
Long: `Query the local database for previously run dehasher queries based on various parameters.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Determine which table to query based on the tableTypeDBQuery parameter
|
||||
switch tableTypeDBQuery {
|
||||
case "results":
|
||||
queryResultsTable(cmd)
|
||||
case "runs":
|
||||
queryRunsTable()
|
||||
case "creds":
|
||||
queryCredsTable(cmd)
|
||||
default:
|
||||
fmt.Printf("Error: Unknown table type '%s'. Valid options are: results, runs, creds\n", tableTypeDBQuery)
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func queryRunsTable() {
|
||||
// Parse date strings to time.Time
|
||||
var startDate, endDate time.Time
|
||||
var err error
|
||||
|
||||
if startDateDBRuns != "" {
|
||||
startDate, err = time.Parse("2006-01-02", startDateDBRuns)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing start date: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if endDateDBRuns != "" {
|
||||
endDate, err = time.Parse("2006-01-02", endDateDBRuns)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing end date: %v\n", err)
|
||||
return
|
||||
}
|
||||
// Set end date to end of day
|
||||
endDate = endDate.Add(24*time.Hour - time.Second)
|
||||
}
|
||||
|
||||
// Get the count of matching runs
|
||||
count, err := sqlite.GetRunsCount(lastXRunsDBRuns, startDate, endDate, containsQueryDBRuns)
|
||||
if err != nil {
|
||||
fmt.Printf("Error counting runs: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Query the database
|
||||
runs, err := sqlite.QueryRuns(limitResultsDB, lastXRunsDBRuns, startDate, endDate, containsQueryDBRuns)
|
||||
if err != nil {
|
||||
fmt.Printf("Error querying runs: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
displayRunsResults(count, runs)
|
||||
}
|
||||
|
||||
func displayRunsResults(count int64, runs []sqlite.QueryOptions) {
|
||||
// Display the results
|
||||
fmt.Printf("Found %d runs (showing %d):\n", count, len(runs))
|
||||
|
||||
if len(runs) == 0 {
|
||||
fmt.Println("No runs found.")
|
||||
return
|
||||
}
|
||||
|
||||
// Output results based on format
|
||||
switch outputFormatDB {
|
||||
case "json":
|
||||
data, err := json.MarshalIndent(runs, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("Error formatting results: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
case "table":
|
||||
// Define headers and rows for the table
|
||||
headers := []string{"ID", "Created At", "Max Records", "Username Query", "Email Query", "IP Query", "Password Query", "Hash Query", "Name Query", "Domain Query"}
|
||||
rows := make([][]string, len(runs))
|
||||
|
||||
for i, run := range runs {
|
||||
rows[i] = []string{
|
||||
fmt.Sprintf("%d", run.ID),
|
||||
run.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
fmt.Sprintf("%d", run.MaxRecords),
|
||||
truncate(run.UsernameQuery, 20),
|
||||
truncate(run.EmailQuery, 20),
|
||||
truncate(run.IpQuery, 20),
|
||||
truncate(run.PassQuery, 20),
|
||||
truncate(run.HashQuery, 20),
|
||||
truncate(run.NameQuery, 20),
|
||||
truncate(run.DomainQuery, 20),
|
||||
}
|
||||
}
|
||||
|
||||
pretty.Table(headers, rows)
|
||||
default:
|
||||
// Simple output
|
||||
for _, run := range runs {
|
||||
fmt.Printf("Run ID: %d\n", run.ID)
|
||||
fmt.Printf(" Created At: %s\n", run.CreatedAt.Format("2006-01-02 15:04:05"))
|
||||
fmt.Printf(" Max Records: %d\n", run.MaxRecords)
|
||||
fmt.Printf(" Max Requests: %d\n", run.MaxRequests)
|
||||
fmt.Printf(" Starting Page: %d\n", run.StartingPage)
|
||||
fmt.Printf(" Output Format: %s\n", run.OutputFormat.String())
|
||||
fmt.Printf(" Output File: %s\n", run.OutputFile)
|
||||
fmt.Printf(" Regex Match: %t\n", run.RegexMatch)
|
||||
fmt.Printf(" Wildcard Match: %t\n", run.WildcardMatch)
|
||||
fmt.Printf(" Username Query: %s\n", run.UsernameQuery)
|
||||
fmt.Printf(" Email Query: %s\n", run.EmailQuery)
|
||||
fmt.Printf(" IP Query: %s\n", run.IpQuery)
|
||||
fmt.Printf(" Password Query: %s\n", run.PassQuery)
|
||||
fmt.Printf(" Hash Query: %s\n", run.HashQuery)
|
||||
fmt.Printf(" Name Query: %s\n", run.NameQuery)
|
||||
fmt.Printf(" Domain Query: %s\n", run.DomainQuery)
|
||||
fmt.Printf(" VIN Query: %s\n", run.VinQuery)
|
||||
fmt.Printf(" License Plate Query: %s\n", run.LicensePlateQuery)
|
||||
fmt.Printf(" Address Query: %s\n", run.AddressQuery)
|
||||
fmt.Printf(" Phone Query: %s\n", run.PhoneQuery)
|
||||
fmt.Printf(" Social Query: %s\n", run.SocialQuery)
|
||||
fmt.Printf(" Crypto Address Query: %s\n", run.CryptoAddressQuery)
|
||||
fmt.Printf(" Print Balance: %t\n", run.PrintBalance)
|
||||
fmt.Printf(" Creds Only: %t\n", run.CredsOnly)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// queryResultsTable queries the results table
|
||||
func queryResultsTable(cmd *cobra.Command) {
|
||||
// Create DBOptions with the provided parameters
|
||||
options := &sqlite.DBOptions{
|
||||
Username: usernameDBQuery,
|
||||
Email: emailDBQuery,
|
||||
IPAddress: ipDBQuery,
|
||||
Password: passwordDBQuery,
|
||||
HashedPassword: hashDBQuery,
|
||||
Name: nameDBQuery,
|
||||
Vin: vinDBQuery,
|
||||
LicensePlate: licensePlateDBQuery,
|
||||
Address: addressDBQuery,
|
||||
Phone: phoneDBQuery,
|
||||
Social: socialDBQuery,
|
||||
CryptoCurrencyAddress: cryptoCurrencyAddressDBQuery,
|
||||
Domain: domainDBQuery,
|
||||
Limit: limitResultsDB,
|
||||
ExactMatch: exactMatchDBQuery,
|
||||
}
|
||||
|
||||
// Parse non-empty fields if provided
|
||||
if nonEmptyFieldsDBQuery != "" {
|
||||
options.NonEmptyFields = strings.Split(nonEmptyFieldsDBQuery, ",")
|
||||
}
|
||||
|
||||
// Parse display fields if provided
|
||||
if displayFieldsDBQuery != "" {
|
||||
options.DisplayFields = strings.Split(displayFieldsDBQuery, ",")
|
||||
}
|
||||
|
||||
// Check if at least one search parameter is provided
|
||||
if options.Empty() {
|
||||
fmt.Println("Error: At least one search parameter is required.")
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
|
||||
// Get the count of matching results
|
||||
count, err := sqlite.GetResultsCount(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error counting results: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Query the database
|
||||
results, err := sqlite.QueryResults(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error querying database: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Display the results
|
||||
displayResultsTable(count, results, options)
|
||||
}
|
||||
|
||||
// displayResultsTable displays the results from the results table
|
||||
func displayResultsTable(count int64, results []sqlite.Result, options *sqlite.DBOptions) {
|
||||
// Display the results
|
||||
fmt.Printf("Found %d results (showing %d):\n", count, len(results))
|
||||
|
||||
if len(results) == 0 {
|
||||
fmt.Println("No results found.")
|
||||
return
|
||||
}
|
||||
|
||||
// Output results based on format
|
||||
switch outputFormatDB {
|
||||
case "json":
|
||||
data, err := json.MarshalIndent(results, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("Error formatting results: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
case "table":
|
||||
// Determine which fields to display
|
||||
type FieldInfo struct {
|
||||
Name string
|
||||
Width int
|
||||
Getter func(result sqlite.Result) string
|
||||
}
|
||||
|
||||
// Define all available fields
|
||||
allFields := []FieldInfo{
|
||||
{"Username", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.Username), 20) }},
|
||||
{"Email", 30, func(r sqlite.Result) string { return truncate(arrayToString(r.Email), 30) }},
|
||||
{"IP Address", 15, func(r sqlite.Result) string { return truncate(arrayToString(r.IpAddress), 15) }},
|
||||
{"Password", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.Password), 20) }},
|
||||
{"Hashed Password", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.HashedPassword), 20) }},
|
||||
{"Name", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.Name), 20) }},
|
||||
{"VIN", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.Vin), 20) }},
|
||||
{"License Plate", 15, func(r sqlite.Result) string { return truncate(arrayToString(r.LicensePlate), 15) }},
|
||||
{"Address", 30, func(r sqlite.Result) string { return truncate(arrayToString(r.Address), 30) }},
|
||||
{"Phone", 15, func(r sqlite.Result) string { return truncate(arrayToString(r.Phone), 15) }},
|
||||
{"Social", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.Social), 20) }},
|
||||
{"Crypto Address", 20, func(r sqlite.Result) string { return truncate(arrayToString(r.CryptoCurrencyAddress), 20) }},
|
||||
{"Domain/URL", 30, func(r sqlite.Result) string { return truncate(arrayToString(r.Url), 30) }},
|
||||
}
|
||||
|
||||
// Select fields to display
|
||||
var fieldsToDisplay []FieldInfo
|
||||
var headers []string
|
||||
if len(options.DisplayFields) > 0 {
|
||||
// Use specified fields
|
||||
for _, fieldName := range options.DisplayFields {
|
||||
fieldName = strings.ToLower(strings.TrimSpace(fieldName))
|
||||
for _, field := range allFields {
|
||||
if strings.ToLower(field.Name) == fieldName ||
|
||||
(fieldName == "ip" && strings.ToLower(field.Name) == "ip address") ||
|
||||
(fieldName == "hash" && strings.ToLower(field.Name) == "hashed password") ||
|
||||
(fieldName == "license" && strings.ToLower(field.Name) == "license plate") ||
|
||||
(fieldName == "crypto" && strings.ToLower(field.Name) == "crypto address") ||
|
||||
(fieldName == "url" && strings.ToLower(field.Name) == "domain/url") {
|
||||
fieldsToDisplay = append(fieldsToDisplay, field)
|
||||
headers = append(headers, field.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default fields (first 6)
|
||||
fieldsToDisplay = allFields[:6]
|
||||
}
|
||||
|
||||
var rows [][]string
|
||||
for _, result := range results {
|
||||
rowValues := []string{}
|
||||
for _, field := range fieldsToDisplay {
|
||||
rowValues = append(rowValues, field.Getter(result))
|
||||
}
|
||||
rows = append(rows, rowValues)
|
||||
}
|
||||
|
||||
pretty.Table(headers, rows)
|
||||
default:
|
||||
// Simple output
|
||||
for i, result := range results {
|
||||
fmt.Printf("Result %d:\n", i+1)
|
||||
|
||||
// Determine which fields to display
|
||||
if len(options.DisplayFields) > 0 {
|
||||
// Display only specified fields
|
||||
for _, field := range options.DisplayFields {
|
||||
field = strings.ToLower(strings.TrimSpace(field))
|
||||
switch field {
|
||||
case "username":
|
||||
fmt.Printf(" Username: %s\n", result.Username)
|
||||
case "email":
|
||||
fmt.Printf(" Email: %s\n", result.Email)
|
||||
case "ip", "ipaddress", "ip_address":
|
||||
fmt.Printf(" IP Address: %s\n", result.IpAddress)
|
||||
case "password":
|
||||
fmt.Printf(" Password: %s\n", result.Password)
|
||||
case "hash", "hashed_password":
|
||||
fmt.Printf(" Hashed Password: %s\n", result.HashedPassword)
|
||||
case "name":
|
||||
fmt.Printf(" Name: %s\n", result.Name)
|
||||
case "vin":
|
||||
fmt.Printf(" VIN: %s\n", result.Vin)
|
||||
case "license", "license_plate":
|
||||
fmt.Printf(" License Plate: %s\n", result.LicensePlate)
|
||||
case "address":
|
||||
fmt.Printf(" Address: %s\n", result.Address)
|
||||
case "phone":
|
||||
fmt.Printf(" Phone: %s\n", result.Phone)
|
||||
case "social":
|
||||
fmt.Printf(" Social: %s\n", result.Social)
|
||||
case "crypto", "cryptocurrency_address":
|
||||
fmt.Printf(" Crypto Address: %s\n", result.CryptoCurrencyAddress)
|
||||
case "domain", "url":
|
||||
fmt.Printf(" Domain/URL: %s\n", result.Url)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Display default fields
|
||||
fmt.Printf(" Username: %s\n", result.Username)
|
||||
fmt.Printf(" Email: %s\n", result.Email)
|
||||
fmt.Printf(" IP Address: %s\n", result.IpAddress)
|
||||
fmt.Printf(" Password: %s\n", result.Password)
|
||||
fmt.Printf(" Hashed Password: %s\n", result.HashedPassword)
|
||||
fmt.Printf(" Name: %s\n", result.Name)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// truncate truncates a string to the specified length and adds ellipsis if needed
|
||||
func truncate(s string, length int) string {
|
||||
if len(s) <= length {
|
||||
return s
|
||||
}
|
||||
return s[:length-3] + "..."
|
||||
}
|
||||
|
||||
func arrayToString(a []string) string {
|
||||
return strings.Join(a, ", ")
|
||||
}
|
||||
|
||||
// DB runs command
|
||||
var dbRunsCmd = &cobra.Command{
|
||||
Use: "runs",
|
||||
Short: "Query previous query runs",
|
||||
Long: `Query the database for previous query runs (QueryOptions) based on date range and query content.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Call queryRunsTable directly
|
||||
queryRunsTable()
|
||||
},
|
||||
}
|
||||
|
||||
// DB creds command
|
||||
var dbCredsCmd = &cobra.Command{
|
||||
Use: "creds",
|
||||
Short: "Query credentials",
|
||||
Long: `Query the database for credentials based on username, email, and password.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Call queryCredsTable directly
|
||||
queryCredsTable(cmd)
|
||||
},
|
||||
}
|
||||
|
||||
// queryCredsTable queries the credentials table
|
||||
func queryCredsTable(cmd *cobra.Command) {
|
||||
// Create DBOptions with the provided parameters
|
||||
options := &sqlite.DBOptions{
|
||||
Username: usernameDBQuery,
|
||||
Email: emailDBQuery,
|
||||
Password: passwordDBQuery,
|
||||
Limit: limitResultsDB,
|
||||
ExactMatch: exactMatchDBQuery,
|
||||
}
|
||||
|
||||
// Parse non-empty fields if provided
|
||||
if nonEmptyFieldsDBQuery != "" {
|
||||
options.NonEmptyFields = strings.Split(nonEmptyFieldsDBQuery, ",")
|
||||
}
|
||||
|
||||
// Parse display fields if provided
|
||||
if displayFieldsDBQuery != "" {
|
||||
options.DisplayFields = strings.Split(displayFieldsDBQuery, ",")
|
||||
}
|
||||
|
||||
// Check if at least one search parameter is provided
|
||||
if options.Username == "" && options.Email == "" && options.Password == "" && len(options.NonEmptyFields) == 0 {
|
||||
fmt.Println("Error: At least one search parameter is required.")
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
|
||||
// Get the count of matching credentials
|
||||
count, err := sqlite.GetCredsCount(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error counting credentials: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Query the database
|
||||
creds, err := sqlite.QueryCreds(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error querying credentials: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Display the results
|
||||
displayCredsResults(count, creds)
|
||||
}
|
||||
|
||||
// displayCredsResults displays the results from the creds table
|
||||
func displayCredsResults(count int64, creds []sqlite.Creds) {
|
||||
// Display the results
|
||||
fmt.Printf("Found %d credentials (showing %d):\n", count, len(creds))
|
||||
|
||||
if len(creds) == 0 {
|
||||
fmt.Println("No credentials found.")
|
||||
return
|
||||
}
|
||||
|
||||
// Output results based on format
|
||||
switch outputFormatDB {
|
||||
case "json":
|
||||
data, err := json.MarshalIndent(creds, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("Error formatting results: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
case "table":
|
||||
// Define all available fields
|
||||
type FieldInfo struct {
|
||||
Name string
|
||||
Getter func(cred sqlite.Creds) string
|
||||
}
|
||||
|
||||
allFields := []FieldInfo{
|
||||
{"ID", func(c sqlite.Creds) string { return fmt.Sprintf("%d", c.ID) }},
|
||||
{"Created At", func(c sqlite.Creds) string { return c.CreatedAt.Format("2006-01-02 15:04:05") }},
|
||||
{"Email", func(c sqlite.Creds) string { return c.Email }},
|
||||
{"Username", func(c sqlite.Creds) string { return c.Username }},
|
||||
{"Password", func(c sqlite.Creds) string { return c.Password }},
|
||||
}
|
||||
|
||||
// Select fields to display
|
||||
var fieldsToDisplay []FieldInfo
|
||||
var headers []string
|
||||
|
||||
if len(displayFieldsDBQuery) > 0 {
|
||||
// Use specified display fields
|
||||
displayFields := strings.Split(displayFieldsDBQuery, ",")
|
||||
for _, fieldName := range displayFields {
|
||||
fieldName = strings.ToLower(strings.TrimSpace(fieldName))
|
||||
for _, field := range allFields {
|
||||
if strings.ToLower(field.Name) == fieldName {
|
||||
fieldsToDisplay = append(fieldsToDisplay, field)
|
||||
headers = append(headers, field.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default fields
|
||||
fieldsToDisplay = allFields
|
||||
for _, field := range fieldsToDisplay {
|
||||
headers = append(headers, field.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Create rows
|
||||
rows := make([][]string, len(creds))
|
||||
for i, cred := range creds {
|
||||
rowValues := []string{}
|
||||
for _, field := range fieldsToDisplay {
|
||||
rowValues = append(rowValues, field.Getter(cred))
|
||||
}
|
||||
rows[i] = rowValues
|
||||
}
|
||||
|
||||
pretty.Table(headers, rows)
|
||||
default:
|
||||
// Simple output
|
||||
for _, cred := range creds {
|
||||
fmt.Printf("Credential ID: %d\n", cred.ID)
|
||||
fmt.Printf(" Created At: %s\n", cred.CreatedAt.Format("2006-01-02 15:04:05"))
|
||||
fmt.Printf(" Email: %s\n", cred.Email)
|
||||
fmt.Printf(" Username: %s\n", cred.Username)
|
||||
fmt.Printf(" Password: %s\n", cred.Password)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/badger"
|
||||
"dehasher/internal/query"
|
||||
"dehasher/internal/sqlite"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Query command flags
|
||||
maxRecords int
|
||||
maxRequests int
|
||||
startingPage int
|
||||
credsOnly bool
|
||||
printBalance bool
|
||||
regexMatch bool
|
||||
wildcardMatch bool
|
||||
outputFormat string
|
||||
outputFile string
|
||||
usernameQuery string
|
||||
emailQuery string
|
||||
ipQuery string
|
||||
passwordQuery string
|
||||
hashQuery string
|
||||
nameQuery string
|
||||
domainQuery string
|
||||
vinQuery string
|
||||
licensePlateQuery string
|
||||
addressQuery string
|
||||
phoneQuery string
|
||||
socialQuery string
|
||||
cryptoCurrencyAddressQuery string
|
||||
|
||||
// Query command
|
||||
queryCmd = &cobra.Command{
|
||||
Use: "query",
|
||||
Short: "Query the Dehashed API",
|
||||
Long: `Query the Dehashed API for emails, usernames, passwords, hashes, IP addresses, and names.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Check if API key and email are provided
|
||||
key := apiKey
|
||||
email := apiEmail
|
||||
|
||||
// If not provided as flags, try to get from stored values
|
||||
if key == "" {
|
||||
key = getStoredApiKey()
|
||||
}
|
||||
if email == "" {
|
||||
email = getStoredApiEmail()
|
||||
}
|
||||
|
||||
// Validate credentials
|
||||
if key == "" || email == "" {
|
||||
fmt.Println("API key and email are required. Use --key and --email flags or set them with set-key and set-email commands.")
|
||||
return
|
||||
}
|
||||
|
||||
// Create new QueryOptions
|
||||
queryOptions := sqlite.NewQueryOptions(
|
||||
maxRecords,
|
||||
maxRequests,
|
||||
startingPage,
|
||||
outputFormat,
|
||||
outputFile,
|
||||
usernameQuery,
|
||||
emailQuery,
|
||||
ipQuery,
|
||||
passwordQuery,
|
||||
hashQuery,
|
||||
nameQuery,
|
||||
domainQuery,
|
||||
vinQuery,
|
||||
licensePlateQuery,
|
||||
addressQuery,
|
||||
phoneQuery,
|
||||
socialQuery,
|
||||
cryptoCurrencyAddressQuery,
|
||||
regexMatch,
|
||||
wildcardMatch,
|
||||
printBalance,
|
||||
credsOnly,
|
||||
)
|
||||
|
||||
// Create new Dehasher
|
||||
dehasher := query.NewDehasher(queryOptions)
|
||||
dehasher.SetClientCredentials(
|
||||
key,
|
||||
)
|
||||
|
||||
// Start querying
|
||||
dehasher.Start()
|
||||
fmt.Println("\n[*] Completing Process")
|
||||
|
||||
sqlite.StoreQueryOptions(queryOptions)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add flags specific to query command
|
||||
queryCmd.Flags().IntVarP(&maxRecords, "max-records", "m", 30000, "Maximum amount of records to return")
|
||||
queryCmd.Flags().IntVarP(&maxRequests, "max-requests", "r", -1, "Maximum number of requests to make")
|
||||
queryCmd.Flags().IntVarP(&startingPage, "starting-page", "s", 1, "Starting page for requests")
|
||||
queryCmd.Flags().BoolVarP(&printBalance, "print-balance", "b", false, "Print remaining balance after requests")
|
||||
queryCmd.Flags().BoolVarP(®exMatch, "regex-match", "R", false, "Use regex matching on query fields")
|
||||
queryCmd.Flags().BoolVarP(&wildcardMatch, "wildcard-match", "W", false, "Use wildcard matching on query fields (Use ? to replace a single character, and * for multiple characters)")
|
||||
queryCmd.Flags().BoolVarP(&credsOnly, "creds-only", "C", false, "Return credentials only")
|
||||
queryCmd.Flags().StringVarP(&outputFormat, "format", "f", "json", "Output format (json, yaml, xml, txt)")
|
||||
queryCmd.Flags().StringVarP(&outputFile, "output", "o", "query", "File to output results to including extension")
|
||||
queryCmd.Flags().StringVarP(&usernameQuery, "username", "U", "", "Username query")
|
||||
queryCmd.Flags().StringVarP(&emailQuery, "email-query", "E", "", "Email query")
|
||||
queryCmd.Flags().StringVarP(&ipQuery, "ip", "I", "", "IP address query")
|
||||
queryCmd.Flags().StringVarP(&domainQuery, "domain", "D", "", "Domain query")
|
||||
queryCmd.Flags().StringVarP(&passwordQuery, "password", "P", "", "Password query")
|
||||
queryCmd.Flags().StringVarP(&vinQuery, "vin", "V", "", "VIN query")
|
||||
queryCmd.Flags().StringVarP(&licensePlateQuery, "license", "L", "", "License plate query")
|
||||
queryCmd.Flags().StringVarP(&addressQuery, "address", "A", "", "Address query")
|
||||
queryCmd.Flags().StringVarP(&phoneQuery, "phone", "M", "", "Phone query")
|
||||
queryCmd.Flags().StringVarP(&socialQuery, "social", "S", "", "Social query")
|
||||
queryCmd.Flags().StringVarP(&cryptoCurrencyAddressQuery, "crypto", "B", "", "Crypto currency address query")
|
||||
queryCmd.Flags().StringVarP(&hashQuery, "hash", "Q", "", "Hashed password query")
|
||||
queryCmd.Flags().StringVarP(&nameQuery, "name", "N", "", "Name query")
|
||||
|
||||
// Add mutually exclusive flags to exact match and regex match
|
||||
queryCmd.MarkFlagsMutuallyExclusive("regex-match", "wildcard-match")
|
||||
}
|
||||
|
||||
// Helper functions to get stored API credentials
|
||||
func getStoredApiKey() string {
|
||||
return badger.GetKey()
|
||||
}
|
||||
|
||||
func getStoredApiEmail() string {
|
||||
return badger.GetEmail()
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/badger"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
// Global Flags
|
||||
apiKey string
|
||||
apiEmail string
|
||||
|
||||
// rootCmd is the base command for the CLI.
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "dehasher",
|
||||
Short: `Dehasher is a cli tool for querying query.`,
|
||||
Long: fmt.Sprintf(
|
||||
"%s\n%s",
|
||||
`
|
||||
______ _______ _______ _______ _______ _______
|
||||
( __ \ ( ____ \|\ /|( ___ )( ____ \|\ /|( ____ \( ____ )
|
||||
| ( \ )| ( \/| ) ( || ( ) || ( \/| ) ( || ( \/| ( )|
|
||||
| | ) || (__ | (___) || (___) || (_____ | (___) || (__ | (____)|
|
||||
| | | || __) | ___ || ___ |(_____ )| ___ || __) | __)
|
||||
| | ) || ( | ( ) || ( ) | ) || ( ) || ( | (\ (
|
||||
| (__/ )| (____/\| ) ( || ) ( |/\____) || ) ( || (____/\| ) \ \__
|
||||
(______/ (_______/|/ \||/ \|\_______)|/ \|(_______/|/ \__/
|
||||
An Ar1ste1a Project
|
||||
`,
|
||||
`––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•––
|
||||
Dehasher can query the query API for:
|
||||
- Emails - Usernames - Password
|
||||
- Hashes - IP Addresses - Names
|
||||
- VINs - License Plates - Addresses
|
||||
- Phones - Social Media - Crypto Currency Addresses
|
||||
Dehasher supports:
|
||||
- Regex Matching
|
||||
- Exact Matching
|
||||
––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•––
|
||||
`,
|
||||
),
|
||||
Version: "v1.0",
|
||||
}
|
||||
)
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
zap.L().Fatal("execute_root_command",
|
||||
zap.String("message", "failed to execute root command"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Hide the default help command
|
||||
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
||||
|
||||
// Add global flags for API key and email
|
||||
rootCmd.PersistentFlags().StringVarP(&apiKey, "key", "k", "", "API Key for authentication")
|
||||
|
||||
// Add subcommands
|
||||
rootCmd.AddCommand(dbCmd)
|
||||
rootCmd.AddCommand(queryCmd)
|
||||
rootCmd.AddCommand(setKeyCmd)
|
||||
rootCmd.AddCommand(setEmailCmd)
|
||||
}
|
||||
|
||||
// Command to set API key
|
||||
var setKeyCmd = &cobra.Command{
|
||||
Use: "set-key [key]",
|
||||
Short: "Set and store API key",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
key := args[0]
|
||||
// Store key in badger DB
|
||||
err := storeApiKey(key)
|
||||
if err != nil {
|
||||
fmt.Printf("Error storing API key: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("API key stored successfully")
|
||||
},
|
||||
}
|
||||
|
||||
// Command to set API email
|
||||
var setEmailCmd = &cobra.Command{
|
||||
Use: "set-email [email]",
|
||||
Short: "Set and store API email",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
email := args[0]
|
||||
// Store email in badger DB
|
||||
err := storeApiEmail(email)
|
||||
if err != nil {
|
||||
fmt.Printf("Error storing API email: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("API email stored successfully")
|
||||
},
|
||||
}
|
||||
|
||||
// Helper functions to store API credentials
|
||||
func storeApiKey(key string) error {
|
||||
err := badger.StoreKey(key)
|
||||
if err != nil {
|
||||
fmt.Printf("Error storing API key: %v\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func storeApiEmail(email string) error {
|
||||
err := badger.StoreEmail(email)
|
||||
if err != nil {
|
||||
fmt.Printf("Error storing API email: %v\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/sqlite"
|
||||
"dehasher/internal/whois"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// WHOIS command flags
|
||||
whoisDomain string
|
||||
whoisIPAddress string
|
||||
whoisMXAddress string
|
||||
whoisNSAddress string
|
||||
whoisInclude string
|
||||
whoisExclude string
|
||||
whoisReverseType string
|
||||
whoisOutputFormat string
|
||||
whoisShowCredits bool
|
||||
whoisHistory bool
|
||||
whoisSubdomainScan bool
|
||||
|
||||
// WHOIS command
|
||||
whoisCmd = &cobra.Command{
|
||||
Use: "whois",
|
||||
Short: "Dehashed WHOIS lookups and reverse WHOIS searches",
|
||||
Long: `Perform WHOIS lookups, history searches, reverse WHOIS searches, IP lookups, MX lookups, NS lookups, and subdomain scans.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Check if API key is provided
|
||||
key := apiKey
|
||||
|
||||
// If not provided as flag, try to get from stored value
|
||||
if key == "" {
|
||||
key = getStoredApiKey()
|
||||
}
|
||||
|
||||
// Validate credentials
|
||||
if key == "" {
|
||||
fmt.Println("API key is required. Use --key flag or set it with set-key command.")
|
||||
return
|
||||
}
|
||||
|
||||
// Show credits if requested
|
||||
if whoisShowCredits {
|
||||
fmt.Println("[*] Getting WHOIS credits...")
|
||||
credits, err := whois.GetWHOISCredits(key)
|
||||
if err != nil {
|
||||
zap.L().Error("get_whois_credits",
|
||||
zap.String("message", "failed to get whois credits"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error getting WHOIS credits: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("WHOIS Credits: %d\n", credits.WhoisCredits)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if domain is provided for history and subdomain scan
|
||||
if whoisHistory || whoisSubdomainScan {
|
||||
if whoisDomain == "" {
|
||||
fmt.Println("Domain is required for history and subdomain scan.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which operation to perform based on flags
|
||||
if whoisDomain != "" {
|
||||
fmt.Println("[*] Performing WHOIS lookup...")
|
||||
// Domain lookup
|
||||
result, err := whois.WhoisSearch(whoisDomain, key)
|
||||
if err != nil {
|
||||
zap.L().Error("whois_search",
|
||||
zap.String("message", "failed to perform whois search"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing WHOIS lookup: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Fix the output format to use proper formatting
|
||||
fmt.Printf("WHOIS Lookup Result:\n%+v\n", result.Data.WhoisRecord)
|
||||
|
||||
// Store the record
|
||||
err = sqlite.StoreWhoisRecord(result.Data.WhoisRecord)
|
||||
if err != nil {
|
||||
zap.L().Error("store_whois_record",
|
||||
zap.String("message", "failed to store whois record"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error storing WHOIS record: %v\n", err)
|
||||
// Continue execution even if storage fails
|
||||
}
|
||||
|
||||
if whoisHistory {
|
||||
fmt.Println("[*] Performing WHOIS history search...")
|
||||
// Perform history search
|
||||
history, err := whois.WhoisHistory(whoisDomain, key)
|
||||
if err != nil {
|
||||
zap.L().Error("whois_history",
|
||||
zap.String("message", "failed to perform whois history lookup"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing WHOIS history lookup: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("\nWHOIS History:")
|
||||
fmt.Println(history)
|
||||
}
|
||||
|
||||
err = sqlite.StoreHistoryRecord(history.Data.Records)
|
||||
if err != nil {
|
||||
zap.L().Error("store_history_record",
|
||||
zap.String("message", "failed to store history record"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error storing WHOIS history record: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Perform subdomain scan
|
||||
if whoisSubdomainScan {
|
||||
fmt.Println("[*] Performing WHOIS subdomain scan...")
|
||||
subdomains, err := whois.WhoisSubdomainScan(whoisDomain, key)
|
||||
if err != nil {
|
||||
zap.L().Error("whois_subdomain_scan",
|
||||
zap.String("message", "failed to perform subdomain scan"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing subdomain scan: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("\nSubdomain Scan:")
|
||||
fmt.Println(subdomains)
|
||||
}
|
||||
|
||||
err = sqlite.StoreSubdomainRecord(subdomains.Data.Result.Records)
|
||||
if err != nil {
|
||||
zap.L().Error("store_subdomain_record",
|
||||
zap.String("message", "failed to store subdomain record"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error storing WHOIS subdomain record: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get credits
|
||||
credits, err := whois.GetWHOISCredits(key)
|
||||
if err != nil {
|
||||
zap.L().Error("get_whois_credits",
|
||||
zap.String("message", "failed to get whois credits"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error getting WHOIS credits: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nWHOIS Credits Remaining: %d\n", credits.WhoisCredits)
|
||||
return
|
||||
}
|
||||
|
||||
if whoisIPAddress != "" {
|
||||
fmt.Println("[*] Performing reverse IP lookup...")
|
||||
// IP lookup
|
||||
result, err := whois.WhoisIP(whoisIPAddress, key)
|
||||
if err != nil {
|
||||
zap.L().Error("whois_ip",
|
||||
zap.String("message", "failed to perform ip lookup"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing IP lookup: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("IP Lookup Result:")
|
||||
fmt.Println(string(result))
|
||||
|
||||
// Get credits
|
||||
credits, err := whois.GetWHOISCredits(key)
|
||||
if err != nil {
|
||||
zap.L().Error("get_whois_credits",
|
||||
zap.String("message", "failed to get whois credits"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error getting WHOIS credits: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nWHOIS Credits Remaining: %d\n", credits.WhoisCredits)
|
||||
return
|
||||
}
|
||||
|
||||
if whoisMXAddress != "" {
|
||||
fmt.Println("[*] Performing reverse MX lookup...")
|
||||
// MX lookup
|
||||
result, err := whois.WhoisMX(whoisMXAddress, key)
|
||||
if err != nil {
|
||||
zap.L().Error("whois_mx",
|
||||
zap.String("message", "failed to perform mx lookup"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing MX lookup: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// todo unmarshal mx lookup
|
||||
fmt.Println("MX Lookup Result:")
|
||||
fmt.Println(result)
|
||||
|
||||
// Get credits
|
||||
credits, err := whois.GetWHOISCredits(key)
|
||||
if err != nil {
|
||||
zap.L().Error("get_whois_credits",
|
||||
zap.String("message", "failed to get whois credits"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error getting WHOIS credits: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nWHOIS Credits Remaining: %d\n", credits.WhoisCredits)
|
||||
return
|
||||
}
|
||||
|
||||
if whoisNSAddress != "" {
|
||||
fmt.Println("[*] Performing reverse NS lookup...")
|
||||
// NS lookup
|
||||
result, err := whois.WhoisNS(whoisNSAddress, key)
|
||||
if err != nil {
|
||||
zap.L().Error("whois_ns",
|
||||
zap.String("message", "failed to perform ns lookup"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error performing NS lookup: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("NS Lookup Result:")
|
||||
fmt.Println(result)
|
||||
|
||||
// Get credits
|
||||
credits, err := whois.GetWHOISCredits(key)
|
||||
if err != nil {
|
||||
zap.L().Error("get_whois_credits",
|
||||
zap.String("message", "failed to get whois credits"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("Error getting WHOIS credits: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("\nWHOIS Credits Remaining: %d\n", credits.WhoisCredits)
|
||||
return
|
||||
}
|
||||
|
||||
if whoisInclude != "" || whoisExclude != "" {
|
||||
// Reverse WHOIS
|
||||
includeTerms := []string{}
|
||||
if whoisInclude != "" {
|
||||
includeTerms = strings.Split(whoisInclude, ",")
|
||||
}
|
||||
|
||||
excludeTerms := []string{}
|
||||
if whoisExclude != "" {
|
||||
excludeTerms = strings.Split(whoisExclude, ",")
|
||||
}
|
||||
|
||||
if whoisReverseType == "" {
|
||||
whoisReverseType = "registrant"
|
||||
}
|
||||
|
||||
fmt.Println("[*] Performing reverse WHOIS lookup...")
|
||||
result, err := whois.ReverseWHOIS(includeTerms, excludeTerms, whoisReverseType, key)
|
||||
if err != nil {
|
||||
fmt.Printf("Error performing reverse WHOIS: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Reverse WHOIS Result:")
|
||||
fmt.Println(result)
|
||||
return
|
||||
}
|
||||
|
||||
// If no specific operation was requested
|
||||
cmd.Help()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add whois command to root command
|
||||
rootCmd.AddCommand(whoisCmd)
|
||||
|
||||
// Add flags specific to whois command
|
||||
whoisCmd.Flags().StringVarP(&whoisDomain, "domain", "d", "", "Domain for WHOIS lookup, history search, and subdomain scan")
|
||||
whoisCmd.Flags().StringVarP(&whoisIPAddress, "ip", "i", "", "IP address for reverse IP lookup")
|
||||
whoisCmd.Flags().StringVarP(&whoisMXAddress, "mx", "m", "", "MX address for reverse MX lookup")
|
||||
whoisCmd.Flags().StringVarP(&whoisNSAddress, "ns", "n", "", "NS address for reverse NS lookup")
|
||||
whoisCmd.Flags().StringVarP(&whoisInclude, "include", "I", "", "Terms to include in reverse WHOIS search (comma-separated)")
|
||||
whoisCmd.Flags().StringVarP(&whoisExclude, "exclude", "E", "", "Terms to exclude in reverse WHOIS search (comma-separated)")
|
||||
whoisCmd.Flags().StringVarP(&whoisReverseType, "type", "t", "registrant", "Type of reverse WHOIS search (registrant, email, organization, address, phone)")
|
||||
whoisCmd.Flags().StringVarP(&whoisOutputFormat, "format", "f", "text", "Output format (text, json)")
|
||||
whoisCmd.Flags().BoolVarP(&whoisShowCredits, "credits", "c", false, "Show remaining WHOIS credits")
|
||||
whoisCmd.Flags().BoolVarP(&whoisHistory, "history", "H", false, "Perform WHOIS history search [25 Credits]")
|
||||
whoisCmd.Flags().BoolVarP(&whoisSubdomainScan, "subdomains", "s", false, "Perform WHOIS subdomain scan")
|
||||
|
||||
// Add API key flag
|
||||
whoisCmd.Flags().StringVarP(&apiKey, "key", "k", "", "Dehashed API key")
|
||||
}
|
||||
Reference in New Issue
Block a user