2025-05-15 15:35:02 -04:00
package cmd
import (
2025-05-17 10:00:59 -04:00
"crowsnest/internal/badger"
"crowsnest/internal/debug"
"crowsnest/internal/dehashed"
2026-04-07 09:09:12 -04:00
"crowsnest/internal/files"
"crowsnest/internal/pretty"
2025-05-17 10:00:59 -04:00
"crowsnest/internal/sqlite"
2025-05-15 15:35:02 -04:00
"fmt"
"github.com/spf13/cobra"
2025-05-16 20:21:36 -04:00
"go.uber.org/zap"
2025-05-15 15:35:02 -04:00
)
func init ( ) {
2025-05-16 23:46:55 -04:00
// Add api command to root command
2025-05-17 09:03:04 -04:00
rootCmd . AddCommand ( dehashedCmd )
2026-04-07 09:09:12 -04:00
dehashedCmd . AddCommand ( dehashedDataWellsCmd )
2025-05-15 15:35:02 -04:00
2025-05-16 15:33:29 -04:00
// Add flags specific to api command
2026-04-07 09:09:12 -04:00
dehashedCmd . Flags ( ) . IntVarP ( & maxRecords , "max-records" , "m" , 50000 , "Maximum total records to return (max 50000)" )
2025-05-17 09:03:04 -04:00
dehashedCmd . Flags ( ) . IntVarP ( & maxRequests , "max-requests" , "r" , - 1 , "Maximum number of requests to make" )
dehashedCmd . Flags ( ) . IntVarP ( & startingPage , "starting-page" , "s" , 1 , "Starting page for requests" )
dehashedCmd . Flags ( ) . BoolVarP ( & printBalance , "print-balance" , "b" , false , "Print remaining balance after requests" )
dehashedCmd . Flags ( ) . BoolVarP ( & regexMatch , "regex-match" , "R" , false , "Use regex matching on query fields" )
dehashedCmd . Flags ( ) . BoolVarP ( & wildcardMatch , "wildcard-match" , "W" , false , "Use wildcard matching on query fields (Use ? to replace a single character, and * for multiple characters)" )
dehashedCmd . Flags ( ) . BoolVarP ( & credsOnly , "creds-only" , "C" , false , "Return credentials only" )
2026-04-07 09:09:12 -04:00
dehashedCmd . Flags ( ) . StringVarP ( & outputFormat , "format" , "f" , "json" , "Output format (json, yaml, xml, txt, grep)" )
dehashedCmd . Flags ( ) . StringVarP ( & outputFile , "output" , "o" , "query" , "File to output results to without extension" )
2025-05-17 09:03:04 -04:00
dehashedCmd . Flags ( ) . StringVarP ( & usernameQuery , "username" , "U" , "" , "Username query" )
2026-04-07 09:09:12 -04:00
dehashedCmd . Flags ( ) . StringVarP ( & emailQuery , "email-query" , "E" , "" , "Email query" )
2025-05-17 09:03:04 -04:00
dehashedCmd . Flags ( ) . StringVarP ( & ipQuery , "ip" , "I" , "" , "IP address query" )
dehashedCmd . Flags ( ) . StringVarP ( & domainQuery , "domain" , "D" , "" , "Domain query" )
dehashedCmd . Flags ( ) . StringVarP ( & passwordQuery , "password" , "P" , "" , "Password query" )
dehashedCmd . Flags ( ) . StringVarP ( & vinQuery , "vin" , "V" , "" , "VIN query" )
dehashedCmd . Flags ( ) . StringVarP ( & licensePlateQuery , "license" , "L" , "" , "License plate query" )
dehashedCmd . Flags ( ) . StringVarP ( & addressQuery , "address" , "A" , "" , "Address query" )
dehashedCmd . Flags ( ) . StringVarP ( & phoneQuery , "phone" , "M" , "" , "Phone query" )
dehashedCmd . Flags ( ) . StringVarP ( & socialQuery , "social" , "S" , "" , "Social query" )
dehashedCmd . Flags ( ) . StringVarP ( & cryptoCurrencyAddressQuery , "crypto" , "B" , "" , "Crypto currency address query" )
dehashedCmd . Flags ( ) . StringVarP ( & hashQuery , "hash" , "Q" , "" , "Hashed password query" )
dehashedCmd . Flags ( ) . StringVarP ( & nameQuery , "name" , "N" , "" , "Name query" )
2025-05-15 15:35:02 -04:00
2025-05-16 15:33:29 -04:00
// Add mutually exclusive flags to wildcard match and regex match
2025-05-17 09:03:04 -04:00
dehashedCmd . MarkFlagsMutuallyExclusive ( "regex-match" , "wildcard-match" )
2026-04-07 09:09:12 -04:00
dehashedDataWellsCmd . Flags ( ) . IntVar ( & dataWellsCount , "count" , 20 , "Number of data wells to return (20 or 50)" )
dehashedDataWellsCmd . Flags ( ) . IntVarP ( & dataWellsPage , "page" , "p" , 1 , "Data wells page to request" )
dehashedDataWellsCmd . Flags ( ) . StringVar ( & dataWellsSort , "sort" , "" , "Sort data wells by added, name, date, or records; optionally suffix -ASC or -DESC" )
dehashedDataWellsCmd . Flags ( ) . StringVarP ( & dataWellsOutputFormat , "format" , "f" , "json" , "Output format (json, yaml, xml, txt, grep)" )
dehashedDataWellsCmd . Flags ( ) . StringVarP ( & dataWellsOutputFile , "output" , "o" , "data_wells" , "File to output data wells to without extension" )
2025-05-15 15:35:02 -04:00
}
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
2026-04-07 09:09:12 -04:00
dataWellsCount int
dataWellsPage int
dataWellsSort string
dataWellsOutputFormat string
dataWellsOutputFile string
2025-05-15 15:35:02 -04:00
// Query command
2025-05-17 09:03:04 -04:00
dehashedCmd = & cobra . Command {
Use : "dehashed" ,
2025-05-15 15:35:02 -04:00
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 ) {
2025-05-16 23:46:55 -04:00
key := getDehashedApiKey ( )
2025-05-15 15:35:02 -04:00
// Validate credentials
if key == "" {
2026-04-07 09:09:12 -04:00
fmt . Println ( "API key is required. Set the key with the \"set dehashed\" command. [crowsnest set dehashed <api_key>]" )
2025-05-15 15:35:02 -04:00
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 ,
2025-05-16 15:33:29 -04:00
debugGlobal ,
2025-05-15 15:35:02 -04:00
)
// Create new Dehasher
2025-05-16 15:33:29 -04:00
dehasher := dehashed . NewDehasher ( queryOptions )
2025-05-15 15:35:02 -04:00
dehasher . SetClientCredentials (
key ,
)
// Start querying
dehasher . Start ( )
fmt . Println ( "\n[*] Completing Process" )
2025-06-03 19:29:10 -04:00
// Store query options
2025-05-17 10:25:16 -04:00
err := sqlite . StoreDehashedQueryOptions ( queryOptions )
2025-05-16 20:21:36 -04:00
if err != nil {
if debugGlobal {
debug . PrintInfo ( "failed to store query options" )
debug . PrintError ( err )
}
zap . L ( ) . Error ( "store_query_options" ,
zap . String ( "message" , "failed to store query options" ) ,
zap . Error ( err ) ,
)
fmt . Printf ( "Error storing query options: %v\n" , err )
}
2025-05-15 15:35:02 -04:00
} ,
}
2026-04-07 09:09:12 -04:00
dehashedDataWellsCmd = & cobra . Command {
Use : "data-wells" ,
Short : "List DeHashed data wells" ,
Long : ` List DeHashed data wells. This endpoint is free and does not require a DeHashed API key or subscription. ` ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
client := dehashed . NewDehashedClientV2 ( "" , debugGlobal )
response , err := client . DataWells ( dehashed . DataWellsRequest {
Count : dataWellsCount ,
Page : dataWellsPage ,
Sort : dataWellsSort ,
} )
if err != nil {
fmt . Printf ( "[!] Error querying data wells: %v\n" , err )
return
}
fType := files . GetFileType ( dataWellsOutputFormat )
if dataWellsOutputFile != "" {
fmt . Printf ( "[*] Writing data wells to file: %s%s\n" , dataWellsOutputFile , fType . Extension ( ) )
if err := dehashed . WriteDataWellsToFile ( response , dataWellsOutputFile , fType ) ; err != nil {
fmt . Printf ( "[!] Error writing data wells to file: %v\n" , err )
return
}
}
fmt . Printf ( "[+] Retrieved %d data wells (total: %d, next page: %t)\n" , len ( response . DataWells ) , response . Total , response . NextPage )
printDataWellsTable ( response . DataWells )
} ,
}
2025-05-15 15:35:02 -04:00
)
// Helper functions to get stored API credentials
2025-05-16 23:46:55 -04:00
func getDehashedApiKey ( ) string {
return badger . GetDehashedKey ( )
2025-05-15 15:35:02 -04:00
}
2026-04-07 09:09:12 -04:00
func printDataWellsTable ( dataWells [ ] dehashed . DataWell ) {
headers := [ ] string { "Name" , "Date" , "Records" , "Sensitive" , "Data" }
rows := make ( [ ] [ ] string , 0 , len ( dataWells ) )
for _ , well := range dataWells {
rows = append ( rows , [ ] string {
well . Name ,
well . Date ,
fmt . Sprintf ( "%d" , well . Records ) ,
fmt . Sprintf ( "%t" , well . IsSensitive ) ,
well . Data ,
} )
}
pretty . Table ( headers , rows )
}