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(&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 != "" {
|
||||||
|
|||||||
+259
-104
@@ -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
|
|
||||||
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
|
// Add flags specific to whois command
|
||||||
queryCmd = &cobra.Command{
|
queryCmd.Flags().StringVarP(&dbQueryTableName, "table", "t", "", "Table to query (results, creds, whois, subdomains, history, query_options)")
|
||||||
Use: "query",
|
queryCmd.Flags().IntVarP(&dbQueryLimitRows, "limit", "l", 100, "Limit number of results")
|
||||||
Short: "Query the Dehashed API",
|
queryCmd.Flags().StringVarP(&dbQueryNotNull, "not-null", "n", "", "Filter for non-null values (comma-separated list, e.g., 'password,email')")
|
||||||
Long: `Query the Dehashed API for emails, usernames, passwords, hashes, IP addresses, and names.`,
|
queryCmd.Flags().StringVarP(&dbQueryColumns, "columns", "c", "", "Columns to display in output (comma-separated list, e.g., 'username,email,password')")
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
queryCmd.Flags().StringVarP(&dbQueryUserQuery, "user-query", "q", "", "User query to execute")
|
||||||
key := getStoredApiKey()
|
queryCmd.Flags().StringVarP(&dbQueryRawQuery, "raw-query", "r", "", "Raw SQL query to execute")
|
||||||
|
queryCmd.Flags().BoolVarP(&dbQueryListAll, "list-all", "a", false, "List all columns")
|
||||||
|
|
||||||
// Validate credentials
|
// Add mutually exclusive flags to query and raw-query
|
||||||
if key == "" {
|
// Cannot use query and raw-query at the same time
|
||||||
fmt.Println("API key is required. Set the key with the \"set-key\" command. [dehasher set-key <api_key>]")
|
queryCmd.MarkFlagsMutuallyExclusive("user-query", "raw-query")
|
||||||
return
|
// 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new QueryOptions
|
var (
|
||||||
queryOptions := sqlite.NewQueryOptions(
|
dbQueryTableName string
|
||||||
maxRecords,
|
dbQueryLimitRows int
|
||||||
maxRequests,
|
dbQueryNotNull string
|
||||||
startingPage,
|
dbQueryColumns string
|
||||||
outputFormat,
|
dbQueryUserQuery string
|
||||||
outputFile,
|
dbQueryRawQuery string
|
||||||
usernameQuery,
|
dbQueryListAll bool
|
||||||
emailQuery,
|
|
||||||
ipQuery,
|
|
||||||
passwordQuery,
|
|
||||||
hashQuery,
|
|
||||||
nameQuery,
|
|
||||||
domainQuery,
|
|
||||||
vinQuery,
|
|
||||||
licensePlateQuery,
|
|
||||||
addressQuery,
|
|
||||||
phoneQuery,
|
|
||||||
socialQuery,
|
|
||||||
cryptoCurrencyAddressQuery,
|
|
||||||
regexMatch,
|
|
||||||
wildcardMatch,
|
|
||||||
printBalance,
|
|
||||||
credsOnly,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create new Dehasher
|
queryCmd = &cobra.Command{
|
||||||
dehasher := query.NewDehasher(queryOptions)
|
Use: "query",
|
||||||
dehasher.SetClientCredentials(
|
Short: "Query the database",
|
||||||
key,
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
// Start querying
|
// Determine which table to query based on the tableTypeDBQuery parameter
|
||||||
dehasher.Start()
|
table := sqlite.GetTable(dbQueryTableName)
|
||||||
fmt.Println("\n[*] Completing Process")
|
if table == sqlite.UnknownTable {
|
||||||
|
fmt.Printf("Error: Unknown table type '%s'.\n", dbQueryTableName)
|
||||||
sqlite.StoreQueryOptions(queryOptions)
|
cmd.Help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("[*] Querying Database...")
|
||||||
|
tableQuery(table)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
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(®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
|
// Get the not null fields
|
||||||
func getStoredApiKey() string {
|
notNullFields := []string{}
|
||||||
return badger.GetKey()
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -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{
|
||||||
@@ -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
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-6
@@ -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)
|
||||||
|
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))
|
zap.L().Error("Failed to create database directory", zap.Error(err))
|
||||||
return nil, fmt.Errorf("failed to create database directory: %w", 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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user