updates to db queries and exports

Updates to how queries to the db are made.
This commit is contained in:
Evan Hosinski
2025-05-15 15:35:02 -04:00
parent 93c9a353ca
commit 0783162d18
9 changed files with 454 additions and 423 deletions
+1
View File
@@ -0,0 +1 @@
.idea/*
+126
View File
@@ -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(&regexMatch, "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()
}
-281
View File
@@ -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
View File
@@ -20,18 +20,18 @@ func init() {
exportCmd.Flags().StringVarP(&exportTableName, "table", "t", "", "Table to export") 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(&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(&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(&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(&exportFormat, "format", "f", "json", "Output format (json, yaml, xml, txt)")
exportCmd.Flags().StringVarP(&exportFile, "file", "o", "export", "File to output results to including extension") exportCmd.Flags().StringVarP(&exportFile, "file", "o", "export", "File to output results to including extension")
// Add mutually exclusive flags to query and raw-query // Add mutually exclusive flags to query and raw-query
// Cannot use query and raw-query at the same time // 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 // 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 // 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 // DB export command
@@ -60,8 +60,8 @@ var (
} }
// Determine which table to query based on the tableTypeDBQuery parameter // Determine which table to query based on the tableTypeDBQuery parameter
table := GetTable(exportTableName) table := sqlite.GetTable(exportTableName)
if table == UnknownTable { if table == sqlite.UnknownTable {
fmt.Printf("Error: Unknown table type '%s'.\n", exportTableName) fmt.Printf("Error: Unknown table type '%s'.\n", exportTableName)
cmd.Help() cmd.Help()
return return
@@ -74,7 +74,7 @@ var (
) )
// exportTableQuery queries a table and exports the results // exportTableQuery queries a table and exports the results
func exportTableQuery(table Table) { func exportTableQuery(table sqlite.Table) {
// Get the columns to query // Get the columns to query
columns := []string{"*"} columns := []string{"*"}
if exportColumns != "" { if exportColumns != "" {
+258 -103
View File
@@ -1,126 +1,281 @@
package cmd package cmd
import ( import (
"dehasher/internal/badger" "dehasher/internal/pretty"
"dehasher/internal/query"
"dehasher/internal/sqlite" "dehasher/internal/sqlite"
"encoding/json"
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"go.uber.org/zap"
"os"
"strings"
) )
var ( func init() {
// Query command flags // Add whois command to root command
maxRecords int rootCmd.AddCommand(queryCmd)
maxRequests int
startingPage int // Add flags specific to whois command
credsOnly bool queryCmd.Flags().StringVarP(&dbQueryTableName, "table", "t", "", "Table to query (results, creds, whois, subdomains, history, query_options)")
printBalance bool queryCmd.Flags().IntVarP(&dbQueryLimitRows, "limit", "l", 100, "Limit number of results")
regexMatch bool queryCmd.Flags().StringVarP(&dbQueryNotNull, "not-null", "n", "", "Filter for non-null values (comma-separated list, e.g., 'password,email')")
wildcardMatch bool queryCmd.Flags().StringVarP(&dbQueryColumns, "columns", "c", "", "Columns to display in output (comma-separated list, e.g., 'username,email,password')")
outputFormat string queryCmd.Flags().StringVarP(&dbQueryUserQuery, "user-query", "q", "", "User query to execute")
outputFile string queryCmd.Flags().StringVarP(&dbQueryRawQuery, "raw-query", "r", "", "Raw SQL query to execute")
usernameQuery string queryCmd.Flags().BoolVarP(&dbQueryListAll, "list-all", "a", false, "List all columns")
emailQuery string
ipQuery string // Add mutually exclusive flags to query and raw-query
passwordQuery string // Cannot use query and raw-query at the same time
hashQuery string queryCmd.MarkFlagsMutuallyExclusive("user-query", "raw-query")
nameQuery string // Raw query does not require a table
domainQuery string queryCmd.MarkFlagsMutuallyExclusive("user-query", "table")
vinQuery string // List all columns does not require a query or raw-query
licensePlateQuery string queryCmd.MarkFlagsMutuallyExclusive("raw-query", "list-all")
addressQuery string }
phoneQuery string
socialQuery string var (
cryptoCurrencyAddressQuery string dbQueryTableName string
dbQueryLimitRows int
dbQueryNotNull string
dbQueryColumns string
dbQueryUserQuery string
dbQueryRawQuery string
dbQueryListAll bool
// Query command
queryCmd = &cobra.Command{ queryCmd = &cobra.Command{
Use: "query", Use: "query",
Short: "Query the Dehashed API", Short: "Query the database",
Long: `Query the Dehashed API for emails, usernames, passwords, hashes, IP addresses, and names.`, Long: `Query the database for various information.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
key := getStoredApiKey() // If Raw Query is set, execute it and return
if dbQueryRawQuery != "" {
// Validate credentials fmt.Println("[*] Executing Raw Query...")
if key == "" { rawDBQuery()
fmt.Println("API key is required. Set the key with the \"set-key\" command. [dehasher set-key <api_key>]") os.Exit(1)
return
} }
// Create new QueryOptions // Determine which table to query based on the tableTypeDBQuery parameter
queryOptions := sqlite.NewQueryOptions( table := sqlite.GetTable(dbQueryTableName)
maxRecords, if table == sqlite.UnknownTable {
maxRequests, fmt.Printf("Error: Unknown table type '%s'.\n", dbQueryTableName)
startingPage, cmd.Help()
outputFormat, return
outputFile, }
usernameQuery, fmt.Println("[*] Querying Database...")
emailQuery, tableQuery(table)
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() { func tableQuery(table sqlite.Table) {
// Add query command to root command
rootCmd.AddCommand(queryCmd)
// Add flags specific to query command // Get the columns to query
queryCmd.Flags().IntVarP(&maxRecords, "max-records", "m", 30000, "Maximum amount of records to return") columns := []string{"*"}
queryCmd.Flags().IntVarP(&maxRequests, "max-requests", "r", -1, "Maximum number of requests to make") if dbQueryColumns != "" {
queryCmd.Flags().IntVarP(&startingPage, "starting-page", "s", 1, "Starting page for requests") columns = strings.Split(dbQueryColumns, ",")
queryCmd.Flags().BoolVarP(&printBalance, "print-balance", "b", false, "Print remaining balance after requests") }
queryCmd.Flags().BoolVarP(&regexMatch, "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 // Get the not null fields
queryCmd.MarkFlagsMutuallyExclusive("regex-match", "wildcard-match") 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 rawDBQuery() {
func getStoredApiKey() string { db := sqlite.GetDB()
return badger.GetKey() 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
View File
@@ -11,7 +11,6 @@ import (
var ( var (
// Global Flags // Global Flags
useLocalDatabase bool
// rootCmd is the base command for the CLI. // rootCmd is the base command for the CLI.
rootCmd = &cobra.Command{ rootCmd = &cobra.Command{
@@ -20,15 +19,15 @@ var (
Long: fmt.Sprintf( Long: fmt.Sprintf(
"%s\n%s", "%s\n%s",
` `
______ _______ _______ _______ _______ _______ ______ _______ _______ _______ _______ _______
( __ \ ( ____ \|\ /|( ___ )( ____ \|\ /|( ____ \( ____ ) ( __ \ ( ____ \|\ /|( ___ )( ____ \|\ /|( ____ \( ____ )
| ( \ )| ( \/| ) ( || ( ) || ( \/| ) ( || ( \/| ( )| | ( \ )| ( \/| ) ( || ( ) || ( \/| ) ( || ( \/| ( )|
| | ) || (__ | (___) || (___) || (_____ | (___) || (__ | (____)| | | ) || (__ | (___) || (___) || (_____ | (___) || (__ | (____)|
| | | || __) | ___ || ___ |(_____ )| ___ || __) | __) | | | || __) | ___ || ___ |(_____ )| ___ || __) | __)
| | ) || ( | ( ) || ( ) | ) || ( ) || ( | (\ ( | | ) || ( | ( ) || ( ) | ) || ( ) || ( | (\ (
| (__/ )| (____/\| ) ( || ) ( |/\____) || ) ( || (____/\| ) \ \__ | (__/ )| (____/\| ) ( || ) ( |/\____) || ) ( || (____/\| ) \ \__
(______/ (_______/|/ \||/ \|\_______)|/ \|(_______/|/ \__/ (______/ (_______/|/ \||/ \|\_______)|/ \|(_______/|/ \__/
An Ar1ste1a Project An Ar1ste1a Project
`, `,
`––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•–– `––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•––
Dehasher can query the query API for: Dehasher can query the query API for:
@@ -59,12 +58,15 @@ func Execute() {
} }
func init() { func init() {
// Attempt to retreive the useLocalDB //// Attempt to retrieve the useLocalDB
useLocalDatabase = badger.GetUseLocalDB() //useLocalDatabase := badger.GetUseLocalDB()
// Hide the default help command // Hide the default help command
rootCmd.CompletionOptions.HiddenDefaultCmd = true 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 // Add subcommands
rootCmd.AddCommand(setKeyCmd) rootCmd.AddCommand(setKeyCmd)
rootCmd.AddCommand(setLocalDb) rootCmd.AddCommand(setLocalDb)
@@ -88,10 +90,12 @@ var setKeyCmd = &cobra.Command{
} }
var setLocalDb = &cobra.Command{ var setLocalDb = &cobra.Command{
Use: "set-local-db [true|false]", Use: "local-db [true|false]",
Short: "Set dehasher to use a local database path instead of the default (must be unset to use default)", Short: "Set dehasher to use a local database path instead of the default path",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
var useLocalDatabase bool
useLocal := strings.ToLower(args[0]) useLocal := strings.ToLower(args[0])
if useLocal == "true" { if useLocal == "true" {
+17 -5
View File
@@ -24,7 +24,7 @@ func init() {
basePath = filepath.Join(os.Getenv("HOME"), ".local", "share", "Dehasher") basePath = filepath.Join(os.Getenv("HOME"), ".local", "share", "Dehasher")
logPath = filepath.Join(basePath, "logs") logPath = filepath.Join(basePath, "logs")
storePath = filepath.Join(basePath, "keystore") storePath = filepath.Join(basePath, "keystore")
dbPath = filepath.Join(basePath, "db") // dbPath will be set in main() after badger is initialized
} }
func createDirectories() { func createDirectories() {
@@ -74,6 +74,22 @@ func main() {
zap.L().Info("creating_directories") zap.L().Info("creating_directories")
createDirectories() 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") zap.L().Info("initializing_database")
_, err := sqlite.InitDB(dbPath) _, err := sqlite.InitDB(dbPath)
if err != nil { if err != nil {
@@ -85,10 +101,6 @@ func main() {
os.Exit(1) os.Exit(1)
} }
zap.L().Info("starting_badger")
db := badger.Start(storePath)
defer db.Close()
zap.L().Info("executing_command") zap.L().Info("executing_command")
cmd.Execute() cmd.Execute()
} }
+25 -8
View File
@@ -15,17 +15,34 @@ import (
var DB *gorm.DB var DB *gorm.DB
// InitDB initializes the database connection // InitDB initializes the database connection
func InitDB(dbDir string) (*gorm.DB, error) { func InitDB(dbPath string) (*gorm.DB, error) {
zap.L().Info("Initializing database") zap.L().Info("Initializing database", zap.String("path", dbPath))
// Create directory if it doesn't exist // Check if the path is a file or directory
if err := os.MkdirAll(dbDir, 0755); err != nil { fileInfo, err := os.Stat(dbPath)
zap.L().Error("Failed to create database directory", zap.Error(err)) var finalDbPath string
return nil, fmt.Errorf("failed to create database directory: %w", err)
// 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") zap.L().Info("Opening database", zap.String("finalPath", finalDbPath))
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{ db, err := gorm.Open(sqlite.Open(finalDbPath), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent), Logger: logger.Default.LogMode(logger.Silent),
}) })
if err != nil { if err != nil {
+8 -11
View File
@@ -1,9 +1,6 @@
package cmd package sqlite
import ( import "strings"
"dehasher/internal/sqlite"
"strings"
)
type Table int64 type Table int64
@@ -39,17 +36,17 @@ func GetTable(userInput string) Table {
func (t Table) Object() interface{} { func (t Table) Object() interface{} {
switch t { switch t {
case ResultsTable: case ResultsTable:
return sqlite.Result{} return Result{}
case RunsTable: case RunsTable:
return sqlite.QueryOptions{} return QueryOptions{}
case CredsTable: case CredsTable:
return sqlite.Creds{} return Creds{}
case WhoIsTable: case WhoIsTable:
return sqlite.WhoisRecord{} return WhoisRecord{}
case SubdomainsTable: case SubdomainsTable:
return sqlite.SubdomainRecord{} return SubdomainRecord{}
case HistoryTable: case HistoryTable:
return sqlite.HistoryRecord{} return HistoryRecord{}
default: default:
return nil return nil
} }