updates to db queries and exports
Updates to how queries to the db are made.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.idea/*
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/badger"
|
||||
"dehasher/internal/query"
|
||||
"dehasher/internal/sqlite"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add query command to root command
|
||||
rootCmd.AddCommand(apiCmd)
|
||||
|
||||
// Add flags specific to query command
|
||||
apiCmd.Flags().IntVarP(&maxRecords, "max-records", "m", 30000, "Maximum amount of records to return")
|
||||
apiCmd.Flags().IntVarP(&maxRequests, "max-requests", "r", -1, "Maximum number of requests to make")
|
||||
apiCmd.Flags().IntVarP(&startingPage, "starting-page", "s", 1, "Starting page for requests")
|
||||
apiCmd.Flags().BoolVarP(&printBalance, "print-balance", "b", false, "Print remaining balance after requests")
|
||||
apiCmd.Flags().BoolVarP(®exMatch, "regex-match", "R", false, "Use regex matching on query fields")
|
||||
apiCmd.Flags().BoolVarP(&wildcardMatch, "wildcard-match", "W", false, "Use wildcard matching on query fields (Use ? to replace a single character, and * for multiple characters)")
|
||||
apiCmd.Flags().BoolVarP(&credsOnly, "creds-only", "C", false, "Return credentials only")
|
||||
apiCmd.Flags().StringVarP(&outputFormat, "format", "f", "json", "Output format (json, yaml, xml, txt)")
|
||||
apiCmd.Flags().StringVarP(&outputFile, "output", "o", "query", "File to output results to including extension")
|
||||
apiCmd.Flags().StringVarP(&usernameQuery, "username", "U", "", "Username query")
|
||||
apiCmd.Flags().StringVarP(&emailQuery, "email-query", "E", "", "Email query")
|
||||
apiCmd.Flags().StringVarP(&ipQuery, "ip", "I", "", "IP address query")
|
||||
apiCmd.Flags().StringVarP(&domainQuery, "domain", "D", "", "Domain query")
|
||||
apiCmd.Flags().StringVarP(&passwordQuery, "password", "P", "", "Password query")
|
||||
apiCmd.Flags().StringVarP(&vinQuery, "vin", "V", "", "VIN query")
|
||||
apiCmd.Flags().StringVarP(&licensePlateQuery, "license", "L", "", "License plate query")
|
||||
apiCmd.Flags().StringVarP(&addressQuery, "address", "A", "", "Address query")
|
||||
apiCmd.Flags().StringVarP(&phoneQuery, "phone", "M", "", "Phone query")
|
||||
apiCmd.Flags().StringVarP(&socialQuery, "social", "S", "", "Social query")
|
||||
apiCmd.Flags().StringVarP(&cryptoCurrencyAddressQuery, "crypto", "B", "", "Crypto currency address query")
|
||||
apiCmd.Flags().StringVarP(&hashQuery, "hash", "Q", "", "Hashed password query")
|
||||
apiCmd.Flags().StringVarP(&nameQuery, "name", "N", "", "Name query")
|
||||
|
||||
// Add mutually exclusive flags to exact match and regex match
|
||||
apiCmd.MarkFlagsMutuallyExclusive("regex-match", "wildcard-match")
|
||||
}
|
||||
|
||||
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
|
||||
apiCmd = &cobra.Command{
|
||||
Use: "api",
|
||||
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) {
|
||||
key := getStoredApiKey()
|
||||
|
||||
// Validate credentials
|
||||
if key == "" {
|
||||
fmt.Println("API key is required. Set the key with the \"set-key\" command. [dehasher set-key <api_key>]")
|
||||
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)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Helper functions to get stored API credentials
|
||||
func getStoredApiKey() string {
|
||||
return badger.GetKey()
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/pretty"
|
||||
"dehasher/internal/sqlite"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add whois command to root command
|
||||
rootCmd.AddCommand(databaseQueryCmd)
|
||||
|
||||
// Add flags specific to whois command
|
||||
databaseQueryCmd.Flags().StringVarP(&dbQueryTableName, "table", "t", "", "Table to query (results, creds, whois, subdomains, history, query_options)")
|
||||
databaseQueryCmd.Flags().IntVarP(&dbQueryLimitRows, "limit", "l", 100, "Limit number of results")
|
||||
databaseQueryCmd.Flags().StringVarP(&dbQueryNotNull, "not-null", "n", "", "Filter for non-null values (comma-separated list, e.g., 'password,email')")
|
||||
databaseQueryCmd.Flags().StringVarP(&dbQueryColumns, "columns", "c", "", "Columns to display in output (comma-separated list, e.g., 'username,email,password')")
|
||||
databaseQueryCmd.Flags().StringVarP(&dbQueryUserQuery, "query", "q", "", "User query to execute")
|
||||
databaseQueryCmd.Flags().StringVarP(&dbQueryRawQuery, "raw-query", "r", "", "Raw SQL query to execute")
|
||||
databaseQueryCmd.Flags().BoolVarP(&dbQueryListAll, "list-all", "a", false, "List all columns")
|
||||
|
||||
// Add mutually exclusive flags to query and raw-query
|
||||
// Cannot use query and raw-query at the same time
|
||||
databaseQueryCmd.MarkFlagsMutuallyExclusive("query", "raw-query")
|
||||
// Raw query does not require a table
|
||||
databaseQueryCmd.MarkFlagsMutuallyExclusive("query", "table")
|
||||
// List all columns does not require a query or raw-query
|
||||
databaseQueryCmd.MarkFlagsMutuallyExclusive("raw-query", "list-all")
|
||||
}
|
||||
|
||||
var (
|
||||
dbQueryTableName string
|
||||
dbQueryLimitRows int
|
||||
dbQueryNotNull string
|
||||
dbQueryColumns string
|
||||
dbQueryUserQuery string
|
||||
dbQueryRawQuery string
|
||||
dbQueryListAll bool
|
||||
|
||||
databaseQueryCmd = &cobra.Command{
|
||||
Use: "db",
|
||||
Short: "Query the database",
|
||||
Long: `Query the database for various information.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// If Raw Query is set, execute it and return
|
||||
if dbQueryRawQuery != "" {
|
||||
fmt.Println("[*] Executing Raw Query...")
|
||||
rawDBQuery()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Determine which table to query based on the tableTypeDBQuery parameter
|
||||
table := GetTable(dbQueryTableName)
|
||||
if table == UnknownTable {
|
||||
fmt.Printf("Error: Unknown table type '%s'.\n", dbQueryTableName)
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
fmt.Println("[*] Querying Database...")
|
||||
tableQuery(table)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func tableQuery(table Table) {
|
||||
|
||||
// Get the columns to query
|
||||
columns := []string{"*"}
|
||||
if dbQueryColumns != "" {
|
||||
columns = strings.Split(dbQueryColumns, ",")
|
||||
}
|
||||
|
||||
// Get the not null fields
|
||||
notNullFields := []string{}
|
||||
if dbQueryNotNull != "" {
|
||||
notNullFields = strings.Split(dbQueryNotNull, ",")
|
||||
}
|
||||
|
||||
// Get the user query
|
||||
userQuery := ""
|
||||
if dbQueryUserQuery != "" {
|
||||
userQuery = dbQueryUserQuery
|
||||
}
|
||||
|
||||
// Get the limit
|
||||
limit := dbQueryLimitRows
|
||||
|
||||
// Get the object for the table
|
||||
object := table.Object()
|
||||
|
||||
// Query the database
|
||||
db := sqlite.GetDB()
|
||||
query := db.Model(object).Select(columns)
|
||||
if len(notNullFields) > 0 {
|
||||
for _, field := range notNullFields {
|
||||
query = query.Where(fmt.Sprintf("%s IS NOT NULL", field))
|
||||
}
|
||||
}
|
||||
if userQuery != "" {
|
||||
query = query.Where(userQuery)
|
||||
}
|
||||
if limit > 0 {
|
||||
query = query.Limit(limit)
|
||||
}
|
||||
rows, err := query.Rows()
|
||||
if err != nil {
|
||||
zap.L().Error("db_query",
|
||||
zap.String("message", "failed to execute query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error executing query: %v\n", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Get the columns
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
zap.L().Error("db_query",
|
||||
zap.String("message", "failed to get columns from query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error getting columns from query: %v\n", err)
|
||||
}
|
||||
|
||||
// Prepare data for pretty.Table
|
||||
headers := cols
|
||||
var tableRows [][]string
|
||||
|
||||
// Process the rows
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, len(cols))
|
||||
pointers := make([]interface{}, len(cols))
|
||||
for i := range values {
|
||||
pointers[i] = &values[i]
|
||||
}
|
||||
if err := rows.Scan(pointers...); err != nil {
|
||||
zap.L().Error("db_query",
|
||||
zap.String("message", "failed to scan row from query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error scanning row from query: %v\n", err)
|
||||
}
|
||||
|
||||
// Convert row values to strings
|
||||
rowStrings := make([]string, len(values))
|
||||
for i, value := range values {
|
||||
if value == nil {
|
||||
rowStrings[i] = " "
|
||||
} else {
|
||||
// Check if the value is a slice or array
|
||||
switch v := value.(type) {
|
||||
case []string:
|
||||
// Join string slices with commas, no brackets
|
||||
rowStrings[i] = strings.Join(v, ", ")
|
||||
case []interface{}:
|
||||
// Convert interface slice to strings and join
|
||||
strSlice := make([]string, len(v))
|
||||
for j, item := range v {
|
||||
if item == nil {
|
||||
strSlice[j] = ""
|
||||
} else {
|
||||
strSlice[j] = fmt.Sprintf("%v", item)
|
||||
}
|
||||
}
|
||||
rowStrings[i] = strings.Join(strSlice, ", ")
|
||||
case string:
|
||||
// Handle JSON strings that might be arrays
|
||||
if strings.HasPrefix(v, "[") && strings.HasSuffix(v, "]") {
|
||||
// Try to unmarshal JSON array
|
||||
var strArray []string
|
||||
if err := json.Unmarshal([]byte(v), &strArray); err == nil {
|
||||
rowStrings[i] = strings.Join(strArray, ", ")
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
default:
|
||||
rowStrings[i] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
tableRows = append(tableRows, rowStrings)
|
||||
}
|
||||
|
||||
// Display the table
|
||||
pretty.Table(headers, tableRows)
|
||||
}
|
||||
|
||||
func rawDBQuery() {
|
||||
db := sqlite.GetDB()
|
||||
rows, err := db.Raw(dbQueryRawQuery).Rows()
|
||||
if err != nil {
|
||||
zap.L().Error("raw_query",
|
||||
zap.String("message", "failed to execute raw query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error executing raw query: %v\n", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
zap.L().Error("raw_query",
|
||||
zap.String("message", "failed to get columns from raw query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error getting columns from raw query: %v\n", err)
|
||||
}
|
||||
|
||||
// Prepare data for pretty.Table
|
||||
headers := columns
|
||||
var tableRows [][]string
|
||||
|
||||
// Process the rows
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, len(columns))
|
||||
pointers := make([]interface{}, len(columns))
|
||||
for i := range values {
|
||||
pointers[i] = &values[i]
|
||||
}
|
||||
if err := rows.Scan(pointers...); err != nil {
|
||||
zap.L().Error("raw_query",
|
||||
zap.String("message", "failed to scan row from raw query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error scanning row from raw query: %v\n", err)
|
||||
}
|
||||
|
||||
// Convert row values to strings
|
||||
rowStrings := make([]string, len(values))
|
||||
for i, value := range values {
|
||||
if value == nil {
|
||||
rowStrings[i] = " "
|
||||
} else {
|
||||
// Check if the value is a slice or array
|
||||
switch v := value.(type) {
|
||||
case []string:
|
||||
// Join string slices with commas, no brackets
|
||||
rowStrings[i] = strings.Join(v, ", ")
|
||||
case []interface{}:
|
||||
// Convert interface slice to strings and join
|
||||
strSlice := make([]string, len(v))
|
||||
for j, item := range v {
|
||||
if item == nil {
|
||||
strSlice[j] = ""
|
||||
} else {
|
||||
strSlice[j] = fmt.Sprintf("%v", item)
|
||||
}
|
||||
}
|
||||
rowStrings[i] = strings.Join(strSlice, ", ")
|
||||
case string:
|
||||
// Handle JSON strings that might be arrays
|
||||
if strings.HasPrefix(v, "[") && strings.HasSuffix(v, "]") {
|
||||
// Try to unmarshal JSON array
|
||||
var strArray []string
|
||||
if err := json.Unmarshal([]byte(v), &strArray); err == nil {
|
||||
rowStrings[i] = strings.Join(strArray, ", ")
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
default:
|
||||
rowStrings[i] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
tableRows = append(tableRows, rowStrings)
|
||||
}
|
||||
|
||||
// Display the table
|
||||
pretty.Table(headers, tableRows)
|
||||
}
|
||||
+7
-7
@@ -20,18 +20,18 @@ func init() {
|
||||
exportCmd.Flags().StringVarP(&exportTableName, "table", "t", "", "Table to export")
|
||||
exportCmd.Flags().StringVarP(&exportNotNull, "not-null", "n", "", "Filter for non-null values (comma-separated list, e.g., 'password,email')")
|
||||
exportCmd.Flags().StringVarP(&exportColumns, "columns", "c", "", "Columns to display in output (comma-separated list, e.g., 'username,email,password')")
|
||||
exportCmd.Flags().StringVarP(&exportUserQuery, "query", "q", "", "User query to execute")
|
||||
exportCmd.Flags().StringVarP(&exportUserQuery, "user-query", "q", "", "User query to execute")
|
||||
exportCmd.Flags().StringVarP(&exportRawQuery, "raw-query", "r", "", "Raw SQL query to execute")
|
||||
exportCmd.Flags().StringVarP(&exportFormat, "format", "f", "json", "Output format (json, yaml, xml, txt)")
|
||||
exportCmd.Flags().StringVarP(&exportFile, "file", "o", "export", "File to output results to including extension")
|
||||
|
||||
// Add mutually exclusive flags to query and raw-query
|
||||
// Cannot use query and raw-query at the same time
|
||||
databaseQueryCmd.MarkFlagsMutuallyExclusive("query", "raw-query")
|
||||
exportCmd.MarkFlagsMutuallyExclusive("user-query", "raw-query")
|
||||
// Raw query does not require a table
|
||||
databaseQueryCmd.MarkFlagsMutuallyExclusive("query", "table")
|
||||
exportCmd.MarkFlagsMutuallyExclusive("user-query", "table")
|
||||
// List all columns does not require a query or raw-query
|
||||
databaseQueryCmd.MarkFlagsMutuallyExclusive("raw-query", "list-all")
|
||||
exportCmd.MarkFlagsMutuallyExclusive("raw-query", "list-all")
|
||||
}
|
||||
|
||||
// DB export command
|
||||
@@ -60,8 +60,8 @@ var (
|
||||
}
|
||||
|
||||
// Determine which table to query based on the tableTypeDBQuery parameter
|
||||
table := GetTable(exportTableName)
|
||||
if table == UnknownTable {
|
||||
table := sqlite.GetTable(exportTableName)
|
||||
if table == sqlite.UnknownTable {
|
||||
fmt.Printf("Error: Unknown table type '%s'.\n", exportTableName)
|
||||
cmd.Help()
|
||||
return
|
||||
@@ -74,7 +74,7 @@ var (
|
||||
)
|
||||
|
||||
// exportTableQuery queries a table and exports the results
|
||||
func exportTableQuery(table Table) {
|
||||
func exportTableQuery(table sqlite.Table) {
|
||||
// Get the columns to query
|
||||
columns := []string{"*"}
|
||||
if exportColumns != "" {
|
||||
|
||||
+258
-103
@@ -1,126 +1,281 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"dehasher/internal/badger"
|
||||
"dehasher/internal/query"
|
||||
"dehasher/internal/pretty"
|
||||
"dehasher/internal/sqlite"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
func init() {
|
||||
// Add whois command to root command
|
||||
rootCmd.AddCommand(queryCmd)
|
||||
|
||||
// Add flags specific to whois command
|
||||
queryCmd.Flags().StringVarP(&dbQueryTableName, "table", "t", "", "Table to query (results, creds, whois, subdomains, history, query_options)")
|
||||
queryCmd.Flags().IntVarP(&dbQueryLimitRows, "limit", "l", 100, "Limit number of results")
|
||||
queryCmd.Flags().StringVarP(&dbQueryNotNull, "not-null", "n", "", "Filter for non-null values (comma-separated list, e.g., 'password,email')")
|
||||
queryCmd.Flags().StringVarP(&dbQueryColumns, "columns", "c", "", "Columns to display in output (comma-separated list, e.g., 'username,email,password')")
|
||||
queryCmd.Flags().StringVarP(&dbQueryUserQuery, "user-query", "q", "", "User query to execute")
|
||||
queryCmd.Flags().StringVarP(&dbQueryRawQuery, "raw-query", "r", "", "Raw SQL query to execute")
|
||||
queryCmd.Flags().BoolVarP(&dbQueryListAll, "list-all", "a", false, "List all columns")
|
||||
|
||||
// Add mutually exclusive flags to query and raw-query
|
||||
// Cannot use query and raw-query at the same time
|
||||
queryCmd.MarkFlagsMutuallyExclusive("user-query", "raw-query")
|
||||
// Raw query does not require a table
|
||||
queryCmd.MarkFlagsMutuallyExclusive("user-query", "table")
|
||||
// List all columns does not require a query or raw-query
|
||||
queryCmd.MarkFlagsMutuallyExclusive("raw-query", "list-all")
|
||||
}
|
||||
|
||||
var (
|
||||
dbQueryTableName string
|
||||
dbQueryLimitRows int
|
||||
dbQueryNotNull string
|
||||
dbQueryColumns string
|
||||
dbQueryUserQuery string
|
||||
dbQueryRawQuery string
|
||||
dbQueryListAll bool
|
||||
|
||||
// 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.`,
|
||||
Short: "Query the database",
|
||||
Long: `Query the database for various information.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
key := getStoredApiKey()
|
||||
|
||||
// Validate credentials
|
||||
if key == "" {
|
||||
fmt.Println("API key is required. Set the key with the \"set-key\" command. [dehasher set-key <api_key>]")
|
||||
return
|
||||
// If Raw Query is set, execute it and return
|
||||
if dbQueryRawQuery != "" {
|
||||
fmt.Println("[*] Executing Raw Query...")
|
||||
rawDBQuery()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 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)
|
||||
// Determine which table to query based on the tableTypeDBQuery parameter
|
||||
table := sqlite.GetTable(dbQueryTableName)
|
||||
if table == sqlite.UnknownTable {
|
||||
fmt.Printf("Error: Unknown table type '%s'.\n", dbQueryTableName)
|
||||
cmd.Help()
|
||||
return
|
||||
}
|
||||
fmt.Println("[*] Querying Database...")
|
||||
tableQuery(table)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add query command to root command
|
||||
rootCmd.AddCommand(queryCmd)
|
||||
func tableQuery(table sqlite.Table) {
|
||||
|
||||
// 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")
|
||||
// Get the columns to query
|
||||
columns := []string{"*"}
|
||||
if dbQueryColumns != "" {
|
||||
columns = strings.Split(dbQueryColumns, ",")
|
||||
}
|
||||
|
||||
// Add mutually exclusive flags to exact match and regex match
|
||||
queryCmd.MarkFlagsMutuallyExclusive("regex-match", "wildcard-match")
|
||||
// Get the not null fields
|
||||
notNullFields := []string{}
|
||||
if dbQueryNotNull != "" {
|
||||
notNullFields = strings.Split(dbQueryNotNull, ",")
|
||||
}
|
||||
|
||||
// Get the user query
|
||||
userQuery := ""
|
||||
if dbQueryUserQuery != "" {
|
||||
userQuery = dbQueryUserQuery
|
||||
}
|
||||
|
||||
// Get the limit
|
||||
limit := dbQueryLimitRows
|
||||
|
||||
// Get the object for the table
|
||||
object := table.Object()
|
||||
|
||||
// Query the database
|
||||
db := sqlite.GetDB()
|
||||
query := db.Model(object).Select(columns)
|
||||
if len(notNullFields) > 0 {
|
||||
for _, field := range notNullFields {
|
||||
query = query.Where(fmt.Sprintf("%s IS NOT NULL", field))
|
||||
}
|
||||
}
|
||||
if userQuery != "" {
|
||||
query = query.Where(userQuery)
|
||||
}
|
||||
if limit > 0 {
|
||||
query = query.Limit(limit)
|
||||
}
|
||||
rows, err := query.Rows()
|
||||
if err != nil {
|
||||
zap.L().Error("db_query",
|
||||
zap.String("message", "failed to execute query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error executing query: %v\n", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Get the columns
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
zap.L().Error("db_query",
|
||||
zap.String("message", "failed to get columns from query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error getting columns from query: %v\n", err)
|
||||
}
|
||||
|
||||
// Prepare data for pretty.Table
|
||||
headers := cols
|
||||
var tableRows [][]string
|
||||
|
||||
// Process the rows
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, len(cols))
|
||||
pointers := make([]interface{}, len(cols))
|
||||
for i := range values {
|
||||
pointers[i] = &values[i]
|
||||
}
|
||||
if err := rows.Scan(pointers...); err != nil {
|
||||
zap.L().Error("db_query",
|
||||
zap.String("message", "failed to scan row from query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error scanning row from query: %v\n", err)
|
||||
}
|
||||
|
||||
// Convert row values to strings
|
||||
rowStrings := make([]string, len(values))
|
||||
for i, value := range values {
|
||||
if value == nil {
|
||||
rowStrings[i] = " "
|
||||
} else {
|
||||
// Check if the value is a slice or array
|
||||
switch v := value.(type) {
|
||||
case []string:
|
||||
// Join string slices with commas, no brackets
|
||||
rowStrings[i] = strings.Join(v, ", ")
|
||||
case []interface{}:
|
||||
// Convert interface slice to strings and join
|
||||
strSlice := make([]string, len(v))
|
||||
for j, item := range v {
|
||||
if item == nil {
|
||||
strSlice[j] = ""
|
||||
} else {
|
||||
strSlice[j] = fmt.Sprintf("%v", item)
|
||||
}
|
||||
}
|
||||
rowStrings[i] = strings.Join(strSlice, ", ")
|
||||
case string:
|
||||
// Handle JSON strings that might be arrays
|
||||
if strings.HasPrefix(v, "[") && strings.HasSuffix(v, "]") {
|
||||
// Try to unmarshal JSON array
|
||||
var strArray []string
|
||||
if err := json.Unmarshal([]byte(v), &strArray); err == nil {
|
||||
rowStrings[i] = strings.Join(strArray, ", ")
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
default:
|
||||
rowStrings[i] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
tableRows = append(tableRows, rowStrings)
|
||||
}
|
||||
|
||||
// Display the table
|
||||
pretty.Table(headers, tableRows)
|
||||
}
|
||||
|
||||
// Helper functions to get stored API credentials
|
||||
func getStoredApiKey() string {
|
||||
return badger.GetKey()
|
||||
func rawDBQuery() {
|
||||
db := sqlite.GetDB()
|
||||
rows, err := db.Raw(dbQueryRawQuery).Rows()
|
||||
if err != nil {
|
||||
zap.L().Error("raw_query",
|
||||
zap.String("message", "failed to execute raw query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error executing raw query: %v\n", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
zap.L().Error("raw_query",
|
||||
zap.String("message", "failed to get columns from raw query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error getting columns from raw query: %v\n", err)
|
||||
}
|
||||
|
||||
// Prepare data for pretty.Table
|
||||
headers := columns
|
||||
var tableRows [][]string
|
||||
|
||||
// Process the rows
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, len(columns))
|
||||
pointers := make([]interface{}, len(columns))
|
||||
for i := range values {
|
||||
pointers[i] = &values[i]
|
||||
}
|
||||
if err := rows.Scan(pointers...); err != nil {
|
||||
zap.L().Error("raw_query",
|
||||
zap.String("message", "failed to scan row from raw query"),
|
||||
zap.Error(err),
|
||||
)
|
||||
fmt.Printf("[!] Error scanning row from raw query: %v\n", err)
|
||||
}
|
||||
|
||||
// Convert row values to strings
|
||||
rowStrings := make([]string, len(values))
|
||||
for i, value := range values {
|
||||
if value == nil {
|
||||
rowStrings[i] = " "
|
||||
} else {
|
||||
// Check if the value is a slice or array
|
||||
switch v := value.(type) {
|
||||
case []string:
|
||||
// Join string slices with commas, no brackets
|
||||
rowStrings[i] = strings.Join(v, ", ")
|
||||
case []interface{}:
|
||||
// Convert interface slice to strings and join
|
||||
strSlice := make([]string, len(v))
|
||||
for j, item := range v {
|
||||
if item == nil {
|
||||
strSlice[j] = ""
|
||||
} else {
|
||||
strSlice[j] = fmt.Sprintf("%v", item)
|
||||
}
|
||||
}
|
||||
rowStrings[i] = strings.Join(strSlice, ", ")
|
||||
case string:
|
||||
// Handle JSON strings that might be arrays
|
||||
if strings.HasPrefix(v, "[") && strings.HasSuffix(v, "]") {
|
||||
// Try to unmarshal JSON array
|
||||
var strArray []string
|
||||
if err := json.Unmarshal([]byte(v), &strArray); err == nil {
|
||||
rowStrings[i] = strings.Join(strArray, ", ")
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
} else {
|
||||
rowStrings[i] = v
|
||||
}
|
||||
default:
|
||||
rowStrings[i] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
tableRows = append(tableRows, rowStrings)
|
||||
}
|
||||
|
||||
// Display the table
|
||||
pretty.Table(headers, tableRows)
|
||||
}
|
||||
|
||||
+12
-8
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
var (
|
||||
// Global Flags
|
||||
useLocalDatabase bool
|
||||
|
||||
// rootCmd is the base command for the CLI.
|
||||
rootCmd = &cobra.Command{
|
||||
@@ -20,15 +19,15 @@ var (
|
||||
Long: fmt.Sprintf(
|
||||
"%s\n%s",
|
||||
`
|
||||
______ _______ _______ _______ _______ _______
|
||||
______ _______ _______ _______ _______ _______
|
||||
( __ \ ( ____ \|\ /|( ___ )( ____ \|\ /|( ____ \( ____ )
|
||||
| ( \ )| ( \/| ) ( || ( ) || ( \/| ) ( || ( \/| ( )|
|
||||
| | ) || (__ | (___) || (___) || (_____ | (___) || (__ | (____)|
|
||||
| | | || __) | ___ || ___ |(_____ )| ___ || __) | __)
|
||||
| | ) || ( | ( ) || ( ) | ) || ( ) || ( | (\ (
|
||||
| | ) || ( | ( ) || ( ) | ) || ( ) || ( | (\ (
|
||||
| (__/ )| (____/\| ) ( || ) ( |/\____) || ) ( || (____/\| ) \ \__
|
||||
(______/ (_______/|/ \||/ \|\_______)|/ \|(_______/|/ \__/
|
||||
An Ar1ste1a Project
|
||||
An Ar1ste1a Project
|
||||
`,
|
||||
`––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•––
|
||||
Dehasher can query the query API for:
|
||||
@@ -59,12 +58,15 @@ func Execute() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Attempt to retreive the useLocalDB
|
||||
useLocalDatabase = badger.GetUseLocalDB()
|
||||
//// Attempt to retrieve the useLocalDB
|
||||
//useLocalDatabase := badger.GetUseLocalDB()
|
||||
|
||||
// Hide the default help command
|
||||
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
||||
|
||||
//// Add global flags
|
||||
//rootCmd.PersistentFlags().BoolVar(&useLocalDatabase, "local-db", useLocalDatabase, "Use local database in current directory instead of default path")
|
||||
|
||||
// Add subcommands
|
||||
rootCmd.AddCommand(setKeyCmd)
|
||||
rootCmd.AddCommand(setLocalDb)
|
||||
@@ -88,10 +90,12 @@ var setKeyCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
var setLocalDb = &cobra.Command{
|
||||
Use: "set-local-db [true|false]",
|
||||
Short: "Set dehasher to use a local database path instead of the default (must be unset to use default)",
|
||||
Use: "local-db [true|false]",
|
||||
Short: "Set dehasher to use a local database path instead of the default path",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var useLocalDatabase bool
|
||||
|
||||
useLocal := strings.ToLower(args[0])
|
||||
|
||||
if useLocal == "true" {
|
||||
|
||||
+17
-5
@@ -24,7 +24,7 @@ func init() {
|
||||
basePath = filepath.Join(os.Getenv("HOME"), ".local", "share", "Dehasher")
|
||||
logPath = filepath.Join(basePath, "logs")
|
||||
storePath = filepath.Join(basePath, "keystore")
|
||||
dbPath = filepath.Join(basePath, "db")
|
||||
// dbPath will be set in main() after badger is initialized
|
||||
}
|
||||
|
||||
func createDirectories() {
|
||||
@@ -74,6 +74,22 @@ func main() {
|
||||
zap.L().Info("creating_directories")
|
||||
createDirectories()
|
||||
|
||||
zap.L().Info("starting_badger")
|
||||
db := badger.Start(storePath)
|
||||
defer db.Close()
|
||||
|
||||
// Set database path based on useLocalDatabase flag
|
||||
useLocalDB := badger.GetUseLocalDB()
|
||||
if useLocalDB {
|
||||
// Use local database in current directory
|
||||
dbPath = "./dehasher.sqlite"
|
||||
zap.L().Info("Using local database", zap.String("path", dbPath))
|
||||
} else {
|
||||
// Use default database path
|
||||
dbPath = filepath.Join(basePath, "db")
|
||||
zap.L().Info("Using default database path", zap.String("path", dbPath))
|
||||
}
|
||||
|
||||
zap.L().Info("initializing_database")
|
||||
_, err := sqlite.InitDB(dbPath)
|
||||
if err != nil {
|
||||
@@ -85,10 +101,6 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
zap.L().Info("starting_badger")
|
||||
db := badger.Start(storePath)
|
||||
defer db.Close()
|
||||
|
||||
zap.L().Info("executing_command")
|
||||
cmd.Execute()
|
||||
}
|
||||
|
||||
+25
-8
@@ -15,17 +15,34 @@ import (
|
||||
var DB *gorm.DB
|
||||
|
||||
// InitDB initializes the database connection
|
||||
func InitDB(dbDir string) (*gorm.DB, error) {
|
||||
zap.L().Info("Initializing database")
|
||||
func InitDB(dbPath string) (*gorm.DB, error) {
|
||||
zap.L().Info("Initializing database", zap.String("path", dbPath))
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if err := os.MkdirAll(dbDir, 0755); err != nil {
|
||||
zap.L().Error("Failed to create database directory", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to create database directory: %w", err)
|
||||
// Check if the path is a file or directory
|
||||
fileInfo, err := os.Stat(dbPath)
|
||||
var finalDbPath string
|
||||
|
||||
// If path doesn't exist or is a directory
|
||||
if os.IsNotExist(err) || (err == nil && fileInfo.IsDir()) {
|
||||
// Treat as directory path
|
||||
if err := os.MkdirAll(dbPath, 0755); err != nil {
|
||||
zap.L().Error("Failed to create database directory", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to create database directory: %w", err)
|
||||
}
|
||||
finalDbPath = filepath.Join(dbPath, "dehashed.sqlite")
|
||||
} else {
|
||||
// Treat as file path
|
||||
// Ensure the directory exists
|
||||
dir := filepath.Dir(dbPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
zap.L().Error("Failed to create parent directory for database", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to create parent directory for database: %w", err)
|
||||
}
|
||||
finalDbPath = dbPath
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(dbDir, "dehashed.sqlite")
|
||||
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||
zap.L().Info("Opening database", zap.String("finalPath", finalDbPath))
|
||||
db, err := gorm.Open(sqlite.Open(finalDbPath), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package cmd
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"dehasher/internal/sqlite"
|
||||
"strings"
|
||||
)
|
||||
import "strings"
|
||||
|
||||
type Table int64
|
||||
|
||||
@@ -39,17 +36,17 @@ func GetTable(userInput string) Table {
|
||||
func (t Table) Object() interface{} {
|
||||
switch t {
|
||||
case ResultsTable:
|
||||
return sqlite.Result{}
|
||||
return Result{}
|
||||
case RunsTable:
|
||||
return sqlite.QueryOptions{}
|
||||
return QueryOptions{}
|
||||
case CredsTable:
|
||||
return sqlite.Creds{}
|
||||
return Creds{}
|
||||
case WhoIsTable:
|
||||
return sqlite.WhoisRecord{}
|
||||
return WhoisRecord{}
|
||||
case SubdomainsTable:
|
||||
return sqlite.SubdomainRecord{}
|
||||
return SubdomainRecord{}
|
||||
case HistoryTable:
|
||||
return sqlite.HistoryRecord{}
|
||||
return HistoryRecord{}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user