Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 375aac0fca | |||
| 32150ce6ee | |||
| 91fd75abe2 | |||
| cc3016c5fb | |||
| 86ceeba6d4 | |||
| e8e8cede33 | |||
| f5a5f07997 |
@@ -1,2 +1,3 @@
|
|||||||
.idea/*
|
.idea/*
|
||||||
build/*
|
build/*
|
||||||
|
.DS_Store
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
@@ -16,7 +16,7 @@ PLATFORMS=linux darwin windows
|
|||||||
ARCHS=amd64 arm64
|
ARCHS=amd64 arm64
|
||||||
|
|
||||||
# Version info from git tag or default
|
# Version info from git tag or default
|
||||||
VERSION=$(shell git describe --tags 2>/dev/null || echo "v1.0.1")
|
VERSION=$(shell git describe --tags 2>/dev/null || echo "v1.2.0")
|
||||||
|
|
||||||
.PHONY: all clean build build-all
|
.PHONY: all clean build build-all
|
||||||
|
|
||||||
|
|||||||
@@ -238,11 +238,17 @@ dehasher query -a
|
|||||||
|
|
||||||
The current tables available for query are:
|
The current tables available for query are:
|
||||||
- results
|
- results
|
||||||
|
- Results from a dehashed query
|
||||||
- creds
|
- creds
|
||||||
|
- Credentials parsed from dehashed results
|
||||||
- whois
|
- whois
|
||||||
|
- Results from a whois record lookup
|
||||||
- subdomains
|
- subdomains
|
||||||
- history
|
- Subdomains discovered in a whois subdomain scan
|
||||||
- runs
|
- runs
|
||||||
|
- Previous query runs to the dehashed API
|
||||||
|
- lookup
|
||||||
|
- Results of any Whois NS, MX, or IP lookup
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -265,11 +271,29 @@ The logs can be easily queried from the Dehasher CLI.
|
|||||||
dehasher logs -l 10
|
dehasher logs -l 10
|
||||||
|
|
||||||
# Show logs from the last 24 hours
|
# Show logs from the last 24 hours
|
||||||
dehasher logs -s "24 hours ago"
|
dehasher logs -s "last 24 hours"
|
||||||
|
|
||||||
# Show logs from the last 24 hours with a severity of error or fatal
|
# Show logs from the last 24 hours with a severity of error or fatal
|
||||||
dehasher logs -s "24 hours ago" -v error,fatal
|
dehasher logs -s "05-01-2025" -v error,fatal
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Logs Dates
|
||||||
|
#### Dehasher utilized 'easy time' to determine the appropriate time for a given query.
|
||||||
|

|
||||||
|
#### You may also used dates mixed with easy time to perform queries.
|
||||||
|

|
||||||
|
#### The following formats are supported:
|
||||||
|
- `last 24 hours`
|
||||||
|
- `last 2 days`
|
||||||
|
- `30 minutes ago`
|
||||||
|
- `45 seconds ago`
|
||||||
|
- `1 week ago`
|
||||||
|
- `05-01-2025`
|
||||||
|
- `05/01/2025`
|
||||||
|
- `05/01/25`
|
||||||
|
- `05-01-25`
|
||||||
|
- `May 01, 2025`
|
||||||
|
|
||||||
## 🎉 Sample Run
|
## 🎉 Sample Run
|
||||||
```bash
|
```bash
|
||||||
ar1ste1a@kali:~$ dehasher api -D <redacted>.com -o <redacted> -f json
|
ar1ste1a@kali:~$ dehasher api -D <redacted>.com -o <redacted> -f json
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"dehasher/internal/badger"
|
"dehasher/internal/badger"
|
||||||
|
"dehasher/internal/debug"
|
||||||
"dehasher/internal/dehashed"
|
"dehasher/internal/dehashed"
|
||||||
"dehasher/internal/sqlite"
|
"dehasher/internal/sqlite"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -116,7 +118,18 @@ var (
|
|||||||
dehasher.Start()
|
dehasher.Start()
|
||||||
fmt.Println("\n[*] Completing Process")
|
fmt.Println("\n[*] Completing Process")
|
||||||
|
|
||||||
sqlite.StoreQueryOptions(queryOptions)
|
err := sqlite.StoreQueryOptions(queryOptions)
|
||||||
|
if err != nil {
|
||||||
|
if debugGlobal {
|
||||||
|
debug.PrintInfo("failed to store query options")
|
||||||
|
debug.PrintError(err)
|
||||||
|
}
|
||||||
|
zap.L().Error("store_query_options",
|
||||||
|
zap.String("message", "failed to store query options"),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
fmt.Printf("Error storing query options: %v\n", err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"dehasher/internal/easyTime"
|
||||||
"dehasher/internal/pretty"
|
"dehasher/internal/pretty"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -73,6 +74,11 @@ var (
|
|||||||
allLogs = append(allLogs, filepath.Join(logsPath, "info.log"), filepath.Join(logsPath, "error.log"))
|
allLogs = append(allLogs, filepath.Join(logsPath, "info.log"), filepath.Join(logsPath, "error.log"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var timeChunk easyTime.TimeChunk
|
||||||
|
if logStartDate != "" {
|
||||||
|
timeChunk = easyTime.NewTimeChunk(logStartDate, logEndDate, debugGlobal)
|
||||||
|
}
|
||||||
|
|
||||||
var parsedLogs []LogEntry
|
var parsedLogs []LogEntry
|
||||||
for _, logFile := range allLogs {
|
for _, logFile := range allLogs {
|
||||||
// Read the log file
|
// Read the log file
|
||||||
@@ -97,7 +103,7 @@ var (
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also unmarshal to get additional fields
|
// Unmarshal to get additional fields
|
||||||
if err := json.Unmarshal([]byte(line), &rawEntry); err != nil {
|
if err := json.Unmarshal([]byte(line), &rawEntry); err != nil {
|
||||||
fmt.Printf("Error parsing raw log entry: %v\n", err)
|
fmt.Printf("Error parsing raw log entry: %v\n", err)
|
||||||
continue
|
continue
|
||||||
@@ -106,10 +112,10 @@ var (
|
|||||||
// Parse the timestamp
|
// Parse the timestamp
|
||||||
parsedTime, err := time.Parse("2006-01-02T15:04:05.999-0700", entry.Timestamp)
|
parsedTime, err := time.Parse("2006-01-02T15:04:05.999-0700", entry.Timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Try alternative formats
|
// Try RFC3339
|
||||||
parsedTime, err = time.Parse(time.RFC3339, entry.Timestamp)
|
parsedTime, err = time.Parse(time.RFC3339, entry.Timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Try another format
|
// Try RFC3339Nano
|
||||||
parsedTime, err = time.Parse(time.RFC3339Nano, entry.Timestamp)
|
parsedTime, err = time.Parse(time.RFC3339Nano, entry.Timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error parsing timestamp '%s': %v\n", entry.Timestamp, err)
|
fmt.Printf("Error parsing timestamp '%s': %v\n", entry.Timestamp, err)
|
||||||
@@ -133,22 +139,8 @@ var (
|
|||||||
(logFatal && strings.EqualFold(entry.Level, "FATAL")) {
|
(logFatal && strings.EqualFold(entry.Level, "FATAL")) {
|
||||||
|
|
||||||
// Filter by date range if specified
|
// Filter by date range if specified
|
||||||
if logStartDate != "" {
|
if timeChunk.IsSet() {
|
||||||
startDate, err := time.Parse("2006-01-02", logStartDate)
|
if entry.ParsedTime.Before(timeChunk.StartTime) || entry.ParsedTime.After(timeChunk.EndTime) {
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error parsing start date: %v\n", err)
|
|
||||||
} else if entry.ParsedTime.Before(startDate) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if logEndDate != "" {
|
|
||||||
endDate, err := time.Parse("2006-01-02", logEndDate)
|
|
||||||
// Add one day to include the end date
|
|
||||||
endDate = endDate.Add(24 * time.Hour)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error parsing end date: %v\n", err)
|
|
||||||
} else if entry.ParsedTime.After(endDate) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,16 +203,3 @@ const (
|
|||||||
FATAL
|
FATAL
|
||||||
UNKNOWN Severity = -1
|
UNKNOWN Severity = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSeverity(logLevel string) Severity {
|
|
||||||
switch logLevel {
|
|
||||||
case "INFO":
|
|
||||||
return INFO
|
|
||||||
case "ERROR":
|
|
||||||
return ERROR
|
|
||||||
case "FATAL":
|
|
||||||
return FATAL
|
|
||||||
default:
|
|
||||||
return UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,31 +12,38 @@ import (
|
|||||||
|
|
||||||
// Map of available tables and their columns
|
// Map of available tables and their columns
|
||||||
var availableTables = map[string][]string{
|
var availableTables = map[string][]string{
|
||||||
"results": {
|
|
||||||
"id", "created_at", "updated_at", "deleted_at", "dehashed_id", "email", "ip_address", "username",
|
|
||||||
"password", "hashed_password", "hash_type", "name", "vin", "license_plate", "url", "social",
|
|
||||||
"cryptocurrency_address", "address", "phone", "company", "database_name",
|
|
||||||
},
|
|
||||||
"creds": {
|
"creds": {
|
||||||
"id", "created_at", "updated_at", "deleted_at", "email", "username", "password",
|
"id", "created_at", "updated_at", "deleted_at", "email", "username", "password",
|
||||||
},
|
},
|
||||||
"whois": {
|
//"history": {
|
||||||
"id", "created_at", "updated_at", "deleted_at", "contact_email", "created_date",
|
// "id", "created_at", "updated_at", "deleted_at", "domain_name", "domain_type",
|
||||||
"domain_name", "domain_name_ext", "expires_date", "status", "whois_server",
|
// "registrar_name", "whois_server", "created_date_iso8601", "updated_date_iso8601", "expires_date_iso8601",
|
||||||
},
|
//},
|
||||||
"subdomains": {
|
"lookup": {
|
||||||
"id", "created_at", "updated_at", "deleted_at", "domain", "first_seen", "last_seen",
|
"id", "created_at", "updated_at", "deleted_at", "search_term", "type", "first_seen", "last_visit",
|
||||||
},
|
"name",
|
||||||
"history": {
|
|
||||||
"id", "created_at", "updated_at", "deleted_at", "domain_name", "domain_type",
|
|
||||||
"registrar_name", "whois_server", "created_date_iso8601", "updated_date_iso8601", "expires_date_iso8601",
|
|
||||||
},
|
},
|
||||||
|
// Query Options
|
||||||
"runs": {
|
"runs": {
|
||||||
"id", "created_at", "updated_at", "deleted_at", "max_records", "max_requests", "starting_page",
|
"id", "created_at", "updated_at", "deleted_at", "max_records", "max_requests", "starting_page",
|
||||||
"output_format", "output_file", "regex_match", "wildcard_match", "username_query", "email_query",
|
"output_format", "output_file", "regex_match", "wildcard_match", "username_query", "email_query",
|
||||||
"ip_query", "pass_query", "hash_query", "name_query", "domain_query", "vin_query", "license_plate_query",
|
"ip_query", "pass_query", "hash_query", "name_query", "domain_query", "vin_query", "license_plate_query",
|
||||||
"address_query", "phone_query", "social_query", "crypto_address_query", "print_balance", "creds_only",
|
"address_query", "phone_query", "social_query", "crypto_address_query", "print_balance", "creds_only",
|
||||||
},
|
},
|
||||||
|
"results": {
|
||||||
|
"id", "created_at", "updated_at", "deleted_at", "dehashed_id", "email", "ip_address", "username",
|
||||||
|
"password", "hashed_password", "hash_type", "name", "vin", "license_plate", "url", "social",
|
||||||
|
"cryptocurrency_address", "address", "phone", "company", "database_name",
|
||||||
|
},
|
||||||
|
"subdomains": {
|
||||||
|
"id", "created_at", "updated_at", "deleted_at", "domain", "first_seen", "last_seen",
|
||||||
|
},
|
||||||
|
"whois": {
|
||||||
|
"id", "created_at", "updated_at", "deleted_at", "audit", "contact_email", "created_date", "created_date_normalized",
|
||||||
|
"domain_name", "domain_name_ext", "estimated_domain_age", "expires_date", "expires_date_normalized", "footer", "header",
|
||||||
|
"name_servers", "parse_code", "raw_text", "registrant", "registrar_iana_id", "registrar_name", "registry_data",
|
||||||
|
"status", "stripped_text", "updated_date", "updated_date_normalized",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to list available tables and their columns
|
// Function to list available tables and their columns
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ var (
|
|||||||
// rootCmd is the base command for the CLI.
|
// rootCmd is the base command for the CLI.
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "dehasher",
|
Use: "dehasher",
|
||||||
Short: `Dehasher is a cli tool for querying query.`,
|
Short: `Dehasher is a cli tool for querying the dehashed api.`,
|
||||||
Long: fmt.Sprintf(
|
Long: fmt.Sprintf(
|
||||||
"%s\n%s",
|
"%s\n%s",
|
||||||
`
|
`
|
||||||
@@ -42,7 +42,7 @@ var (
|
|||||||
––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•––
|
––•–√\/––√\/––•––––•–√\/––√\/––•––––•–√\/––√\/––•––√\/––•––––•–√\/––√\/––•––
|
||||||
`,
|
`,
|
||||||
),
|
),
|
||||||
Version: "v1.0",
|
Version: "v1.2.1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ func init() {
|
|||||||
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
||||||
|
|
||||||
// Add global flags
|
// Add global flags
|
||||||
rootCmd.PersistentFlags().BoolVar(&debugGlobal, "debug", false, "Show debugGlobal information")
|
rootCmd.PersistentFlags().BoolVar(&debugGlobal, "debug", false, "Show debug information")
|
||||||
|
|
||||||
// Add subcommands
|
// Add subcommands
|
||||||
rootCmd.AddCommand(setKeyCmd)
|
rootCmd.AddCommand(setKeyCmd)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -97,15 +98,9 @@ var (
|
|||||||
// Show credits if requested
|
// Show credits if requested
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
fmt.Println("[*] Getting WHOIS balance...")
|
fmt.Println("[*] Getting WHOIS balance...")
|
||||||
balance, err := w.Balance()
|
if whoisShowCredits {
|
||||||
if err != nil {
|
checkBalance(w)
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
}
|
||||||
fmt.Printf("WHOIS Credits: %d\n", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if domain is provided for history and subdomain scan
|
// Check if domain is provided for history and subdomain scan
|
||||||
@@ -115,15 +110,7 @@ var (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,19 +134,7 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
if debugGlobal {
|
|
||||||
debug.PrintInfo("failed to get whois balance")
|
|
||||||
debug.PrintError(err)
|
|
||||||
}
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix the output format to use proper formatting
|
// Fix the output format to use proper formatting
|
||||||
@@ -212,19 +187,7 @@ var (
|
|||||||
fmt.Printf("[!] Error performing WHOIS history lookup: %v\n", err)
|
fmt.Printf("[!] Error performing WHOIS history lookup: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
if debugGlobal {
|
|
||||||
debug.PrintInfo("failed to get whois balance")
|
|
||||||
debug.PrintError(err)
|
|
||||||
}
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write history records to file if any
|
// Write history records to file if any
|
||||||
@@ -274,19 +237,7 @@ var (
|
|||||||
subdomains, err := w.WhoisSubdomainScan(whoisDomain)
|
subdomains, err := w.WhoisSubdomainScan(whoisDomain)
|
||||||
|
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
if debugGlobal {
|
|
||||||
debug.PrintInfo("failed to get whois balance")
|
|
||||||
debug.PrintError(err)
|
|
||||||
}
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -371,19 +322,7 @@ var (
|
|||||||
|
|
||||||
// Get credits
|
// Get credits
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
if debugGlobal {
|
|
||||||
debug.PrintInfo("failed to get whois balance")
|
|
||||||
debug.PrintError(err)
|
|
||||||
}
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result) == 0 {
|
if len(result) == 0 {
|
||||||
@@ -445,19 +384,7 @@ var (
|
|||||||
|
|
||||||
// Get credits
|
// Get credits
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
if debugGlobal {
|
|
||||||
debug.PrintInfo("failed to get whois balance")
|
|
||||||
debug.PrintError(err)
|
|
||||||
}
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result) == 0 {
|
if len(result) == 0 {
|
||||||
@@ -519,19 +446,7 @@ var (
|
|||||||
|
|
||||||
// Get credits
|
// Get credits
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
balance, err := w.Balance()
|
checkBalance(w)
|
||||||
if err != nil {
|
|
||||||
if debugGlobal {
|
|
||||||
debug.PrintInfo("failed to get whois balance")
|
|
||||||
debug.PrintError(err)
|
|
||||||
}
|
|
||||||
zap.L().Error("get_whois_credits",
|
|
||||||
zap.String("message", "failed to get whois balance"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
|
||||||
}
|
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result) == 0 {
|
if len(result) == 0 {
|
||||||
@@ -625,6 +540,18 @@ var (
|
|||||||
fmt.Println(result)
|
fmt.Println(result)
|
||||||
|
|
||||||
if whoisShowCredits {
|
if whoisShowCredits {
|
||||||
|
checkBalance(w)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no specific operation was requested
|
||||||
|
cmd.Help()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkBalance(w *whois.DehashedWhoIs) {
|
||||||
balance, err := w.Balance()
|
balance, err := w.Balance()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if debugGlobal {
|
if debugGlobal {
|
||||||
@@ -638,12 +565,8 @@ var (
|
|||||||
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
fmt.Printf("Error getting WHOIS balance: %v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Println("WHOIS Credits: ", balance)
|
fmt.Println("WHOIS Credits: ", balance)
|
||||||
|
if balance == 0 {
|
||||||
|
fmt.Println("[!] No WHOIS credits remaining.")
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no specific operation was requested
|
|
||||||
cmd.Help()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
package easyTime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dehasher/internal/debug"
|
||||||
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TimeChunk struct {
|
||||||
|
StartTime time.Time
|
||||||
|
EndTime time.Time
|
||||||
|
set bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TimeChunk) isValid() bool {
|
||||||
|
if !tc.StartTime.IsZero() && !tc.EndTime.IsZero() && tc.StartTime.Before(tc.EndTime) {
|
||||||
|
tc.set = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
tc.set = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *TimeChunk) IsSet() bool {
|
||||||
|
return tc.set
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimeChunk(start, end string, debugOn bool) TimeChunk {
|
||||||
|
if debugOn {
|
||||||
|
debug.PrintInfo("parsing time chunk")
|
||||||
|
debug.PrintInfo(fmt.Sprintf("Start: %s, End: %s", start, end))
|
||||||
|
zap.L().Info("parsing time chunk",
|
||||||
|
zap.String("start", start),
|
||||||
|
zap.String("end", end),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if end == "" {
|
||||||
|
if debugOn {
|
||||||
|
debug.PrintInfo("no end time provided, using now")
|
||||||
|
}
|
||||||
|
end = "now"
|
||||||
|
}
|
||||||
|
|
||||||
|
tc := TimeChunk{
|
||||||
|
StartTime: parseUserTime(start),
|
||||||
|
EndTime: parseUserTime(end),
|
||||||
|
}
|
||||||
|
|
||||||
|
if debugOn {
|
||||||
|
debug.PrintInfo("checking if time chunk is valid")
|
||||||
|
debug.PrintInfo(fmt.Sprintf("Start: %s, End: %s", tc.StartTime, tc.EndTime))
|
||||||
|
}
|
||||||
|
if !tc.isValid() {
|
||||||
|
fmt.Println("[!] Invalid time chunk")
|
||||||
|
zap.L().Fatal("invalid_time_chunk",
|
||||||
|
zap.String("message", "invalid time chunk"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tc
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseUserTime(args string) time.Time {
|
||||||
|
args = strings.TrimSpace(args)
|
||||||
|
|
||||||
|
if strings.EqualFold(args, "now") {
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if time contains a space, if so, it's in 'last 24 hours' format
|
||||||
|
if strings.Contains(args, " ") && !containsMonth(strings.Split(args, " ")) {
|
||||||
|
splitArgs := strings.Split(args, " ")
|
||||||
|
if len(splitArgs) == 0 {
|
||||||
|
fmt.Println("[!] No time provided")
|
||||||
|
zap.L().Fatal("no_time_provided",
|
||||||
|
zap.String("message", "no time provided"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
} else if len(splitArgs) < 3 {
|
||||||
|
fmt.Println("[!] Invalid time format")
|
||||||
|
zap.L().Fatal("invalid_time_format",
|
||||||
|
zap.String("message", "invalid time format"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle 'last 24 hours' format
|
||||||
|
var (
|
||||||
|
tense string
|
||||||
|
amount int
|
||||||
|
duration time.Duration
|
||||||
|
)
|
||||||
|
for _, arg := range splitArgs {
|
||||||
|
if isPasteTense(arg) {
|
||||||
|
tense = arg
|
||||||
|
} else if isNumber(arg) {
|
||||||
|
amount, _ = strconv.Atoi(arg)
|
||||||
|
} else if isDuration(arg) {
|
||||||
|
duration = getDuration(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tense == "" {
|
||||||
|
fmt.Println("[!] Invalid time format: tense not found")
|
||||||
|
zap.L().Fatal("invalid_time_format",
|
||||||
|
zap.String("message", "invalid time format"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
} else if amount == 0 {
|
||||||
|
fmt.Println("[!] Invalid time format: amount not found")
|
||||||
|
zap.L().Fatal("invalid_time_format",
|
||||||
|
zap.String("message", "invalid time format"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
} else if duration == 0 {
|
||||||
|
fmt.Println("[!] Invalid time format: duration not found")
|
||||||
|
zap.L().Fatal("invalid_time_format",
|
||||||
|
zap.String("message", "invalid time format"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the appropriate time
|
||||||
|
if tense == "last" {
|
||||||
|
return time.Now().Add(-time.Duration(amount) * duration)
|
||||||
|
} else if tense == "ago" {
|
||||||
|
return time.Now().Add(-time.Duration(amount) * duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle possible formats 'May 01, 2025', '05-01-2025', '05/01/2025', '05/01/25', '05-01-25'
|
||||||
|
var (
|
||||||
|
t time.Time
|
||||||
|
err error
|
||||||
|
found bool
|
||||||
|
)
|
||||||
|
possible := []string{"01-02-2006", "01/02/2006", "01/02/06", "01-02-06", "Jan 02, 2006", "Jan 2, 2006"}
|
||||||
|
for _, format := range possible {
|
||||||
|
t, err = time.Parse(format, args)
|
||||||
|
if err == nil {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
fmt.Println("[!] Invalid time format")
|
||||||
|
zap.L().Fatal("invalid_time_format",
|
||||||
|
zap.String("message", "invalid time format"),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert UTC time to local time
|
||||||
|
local, err := time.LoadLocation("Local")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[!] Error loading local timezone")
|
||||||
|
zap.L().Error("load_timezone",
|
||||||
|
zap.String("message", "failed to load local timezone"),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the parsed time to local time
|
||||||
|
return time.Date(
|
||||||
|
t.Year(),
|
||||||
|
t.Month(),
|
||||||
|
t.Day(),
|
||||||
|
t.Hour(),
|
||||||
|
t.Minute(),
|
||||||
|
t.Second(),
|
||||||
|
t.Nanosecond(),
|
||||||
|
local,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPasteTense(value string) bool {
|
||||||
|
for _, v := range []string{"last", "ago"} {
|
||||||
|
if strings.EqualFold(value, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDuration(value string) bool {
|
||||||
|
for _, v := range []string{"hour", "hours", "minute", "minutes", "second", "seconds", "day", "days", "week", "weeks", "month", "months", "year", "years"} {
|
||||||
|
if strings.EqualFold(value, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNumber(value string) bool {
|
||||||
|
_, err := strconv.Atoi(value)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDuration(timeBlock string) time.Duration {
|
||||||
|
timeBlock = strings.TrimSpace(strings.ToLower(timeBlock))
|
||||||
|
|
||||||
|
switch timeBlock {
|
||||||
|
case "hour":
|
||||||
|
return time.Hour
|
||||||
|
case "hours":
|
||||||
|
return time.Hour
|
||||||
|
case "minute":
|
||||||
|
return time.Minute
|
||||||
|
case "minutes":
|
||||||
|
return time.Minute
|
||||||
|
case "second":
|
||||||
|
return time.Second
|
||||||
|
case "seconds":
|
||||||
|
return time.Second
|
||||||
|
case "day":
|
||||||
|
return 24 * time.Hour
|
||||||
|
case "days":
|
||||||
|
return 24 * time.Hour
|
||||||
|
case "week":
|
||||||
|
return 7 * 24 * time.Hour
|
||||||
|
case "weeks":
|
||||||
|
return 7 * 24 * time.Hour
|
||||||
|
case "month":
|
||||||
|
return 30 * 24 * time.Hour
|
||||||
|
case "months":
|
||||||
|
return 30 * 24 * time.Hour
|
||||||
|
case "year":
|
||||||
|
return 365 * 24 * time.Hour
|
||||||
|
case "years":
|
||||||
|
return 365 * 24 * time.Hour
|
||||||
|
default:
|
||||||
|
fmt.Printf("[!] Unknown duration: %s", timeBlock)
|
||||||
|
zap.L().Fatal("unknown_duration",
|
||||||
|
zap.String("message", "unknown duration"),
|
||||||
|
zap.String("duration", timeBlock),
|
||||||
|
)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsMonth(arr []string) bool {
|
||||||
|
for _, v := range arr {
|
||||||
|
if isMonth(v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMonth(value string) bool {
|
||||||
|
for _, v := range []string{"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"} {
|
||||||
|
if strings.EqualFold(value, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -1,419 +0,0 @@
|
|||||||
package sqlite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// QueryResults queries the database for results based on the provided options
|
|
||||||
func QueryResults(options *DBOptions) ([]Result, error) {
|
|
||||||
db := GetDB()
|
|
||||||
var results []Result
|
|
||||||
query := db.Model(&Result{})
|
|
||||||
|
|
||||||
// Apply filters based on the provided options
|
|
||||||
query = applyFilters(query, options)
|
|
||||||
|
|
||||||
// Apply limit
|
|
||||||
if options.Limit > 0 {
|
|
||||||
query = query.Limit(options.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the query
|
|
||||||
if err := query.Find(&results).Error; err != nil {
|
|
||||||
zap.L().Error("query_results",
|
|
||||||
zap.String("message", "failed to query results"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return nil, fmt.Errorf("failed to query results: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyFilters applies filters to the query based on the provided options
|
|
||||||
func applyFilters(query *gorm.DB, options *DBOptions) *gorm.DB {
|
|
||||||
// Helper function to apply filter based on exact match setting
|
|
||||||
applyFilter := func(field, value string) *gorm.DB {
|
|
||||||
if value == "" {
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.ExactMatch {
|
|
||||||
return query.Where(field+" = ?", value)
|
|
||||||
} else {
|
|
||||||
return query.Where(field+" LIKE ?", "%"+value+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply filters for each field if provided
|
|
||||||
if options.Email != "" {
|
|
||||||
query = applyFilter("email", options.Email)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Username != "" {
|
|
||||||
query = applyFilter("username", options.Username)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.IPAddress != "" {
|
|
||||||
query = applyFilter("ip_address", options.IPAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Password != "" {
|
|
||||||
query = applyFilter("password", options.Password)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.HashedPassword != "" {
|
|
||||||
query = applyFilter("hashed_password", options.HashedPassword)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Name != "" {
|
|
||||||
query = applyFilter("name", options.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Vin != "" {
|
|
||||||
query = applyFilter("vin", options.Vin)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.LicensePlate != "" {
|
|
||||||
query = applyFilter("license_plate", options.LicensePlate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Address != "" {
|
|
||||||
query = applyFilter("address", options.Address)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Phone != "" {
|
|
||||||
query = applyFilter("phone", options.Phone)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Social != "" {
|
|
||||||
query = applyFilter("social", options.Social)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.CryptoCurrencyAddress != "" {
|
|
||||||
query = applyFilter("cryptocurrency_address", options.CryptoCurrencyAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Domain != "" {
|
|
||||||
query = applyFilter("url", options.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply non-empty field filters
|
|
||||||
for _, field := range options.NonEmptyFields {
|
|
||||||
switch field {
|
|
||||||
case "username":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(username) > 0")
|
|
||||||
case "email":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(email) > 0")
|
|
||||||
case "ip_address", "ipaddress", "ip":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(ip_address) > 0")
|
|
||||||
case "password":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(password) > 0")
|
|
||||||
case "hashed_password", "hash":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(hashed_password) > 0")
|
|
||||||
case "name":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(name) > 0")
|
|
||||||
case "vin":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(vin) > 0")
|
|
||||||
case "license_plate", "license":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(license_plate) > 0")
|
|
||||||
case "address":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(address) > 0")
|
|
||||||
case "phone":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(phone) > 0")
|
|
||||||
case "social":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(social) > 0")
|
|
||||||
case "cryptocurrency_address", "crypto":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(cryptocurrency_address) > 0")
|
|
||||||
case "url", "domain":
|
|
||||||
query = query.Where("JSON_ARRAY_LENGTH(url) > 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetResultsCount returns the count of results matching the provided options
|
|
||||||
func GetResultsCount(options *DBOptions) (int64, error) {
|
|
||||||
db := GetDB()
|
|
||||||
var count int64
|
|
||||||
query := db.Model(&Result{})
|
|
||||||
|
|
||||||
// Apply filters based on the provided options
|
|
||||||
query = applyFilters(query, options)
|
|
||||||
|
|
||||||
// Count the results
|
|
||||||
if err := query.Count(&count).Error; err != nil {
|
|
||||||
zap.L().Error("get_results_count",
|
|
||||||
zap.String("message", "failed to count results"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return 0, fmt.Errorf("failed to count results: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryRuns queries the database for previous query runs (QueryOptions) based on the provided filters
|
|
||||||
func QueryRuns(limit, lastXRuns int, startDate, endDate time.Time, containsQuery string) ([]QueryOptions, error) {
|
|
||||||
db := GetDB()
|
|
||||||
var runs []QueryOptions
|
|
||||||
query := db.Model(&QueryOptions{})
|
|
||||||
|
|
||||||
// Apply date range filter if provided
|
|
||||||
if lastXRuns > 0 {
|
|
||||||
query = query.Order("created_at DESC").Limit(lastXRuns)
|
|
||||||
} else if !startDate.IsZero() && !endDate.IsZero() {
|
|
||||||
query = query.Where("created_at BETWEEN ? AND ?", startDate, endDate)
|
|
||||||
} else if !startDate.IsZero() {
|
|
||||||
query = query.Where("created_at >= ?", startDate)
|
|
||||||
} else if !endDate.IsZero() {
|
|
||||||
query = query.Where("created_at <= ?", endDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply query filter if provided
|
|
||||||
if containsQuery != "" {
|
|
||||||
// SearchTerm in all query fields
|
|
||||||
query = query.Where(
|
|
||||||
"username_query LIKE ? OR "+
|
|
||||||
"email_query LIKE ? OR "+
|
|
||||||
"ip_query LIKE ? OR "+
|
|
||||||
"pass_query LIKE ? OR "+
|
|
||||||
"hash_query LIKE ? OR "+
|
|
||||||
"name_query LIKE ? OR "+
|
|
||||||
"domain_query LIKE ? OR "+
|
|
||||||
"vin_query LIKE ? OR "+
|
|
||||||
"license_plate_query LIKE ? OR "+
|
|
||||||
"address_query LIKE ? OR "+
|
|
||||||
"phone_query LIKE ? OR "+
|
|
||||||
"social_query LIKE ? OR "+
|
|
||||||
"crypto_address_query LIKE ?",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply limit
|
|
||||||
if limit > 0 {
|
|
||||||
query = query.Limit(limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order by most recent first
|
|
||||||
query = query.Order("created_at DESC")
|
|
||||||
|
|
||||||
// Execute the query
|
|
||||||
if err := query.Find(&runs).Error; err != nil {
|
|
||||||
zap.L().Error("query_runs",
|
|
||||||
zap.String("message", "failed to query runs"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return nil, fmt.Errorf("failed to query runs: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return runs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRunsCount returns the count of runs matching the provided filters
|
|
||||||
func GetRunsCount(lastXRuns int, startDate, endDate time.Time, containsQuery string) (int64, error) {
|
|
||||||
db := GetDB()
|
|
||||||
var count int64
|
|
||||||
query := db.Model(&QueryOptions{})
|
|
||||||
|
|
||||||
// Apply date range filter if provided
|
|
||||||
if lastXRuns > 0 {
|
|
||||||
query = query.Order("created_at DESC").Limit(lastXRuns)
|
|
||||||
} else if !startDate.IsZero() && !endDate.IsZero() {
|
|
||||||
query = query.Where("created_at BETWEEN ? AND ?", startDate, endDate)
|
|
||||||
} else if !startDate.IsZero() {
|
|
||||||
query = query.Where("created_at >= ?", startDate)
|
|
||||||
} else if !endDate.IsZero() {
|
|
||||||
query = query.Where("created_at <= ?", endDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply query filter if provided
|
|
||||||
if containsQuery != "" {
|
|
||||||
// SearchTerm in all query fields
|
|
||||||
query = query.Where(
|
|
||||||
"username_query LIKE ? OR "+
|
|
||||||
"email_query LIKE ? OR "+
|
|
||||||
"ip_query LIKE ? OR "+
|
|
||||||
"pass_query LIKE ? OR "+
|
|
||||||
"hash_query LIKE ? OR "+
|
|
||||||
"name_query LIKE ? OR "+
|
|
||||||
"domain_query LIKE ? OR "+
|
|
||||||
"vin_query LIKE ? OR "+
|
|
||||||
"license_plate_query LIKE ? OR "+
|
|
||||||
"address_query LIKE ? OR "+
|
|
||||||
"phone_query LIKE ? OR "+
|
|
||||||
"social_query LIKE ? OR "+
|
|
||||||
"crypto_address_query LIKE ?",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%", "%"+containsQuery+"%", "%"+containsQuery+"%",
|
|
||||||
"%"+containsQuery+"%",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count the results
|
|
||||||
if err := query.Count(&count).Error; err != nil {
|
|
||||||
zap.L().Error("get_runs_count",
|
|
||||||
zap.String("message", "failed to count runs"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return 0, fmt.Errorf("failed to count runs: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryCreds queries the database for credentials based on the provided filters
|
|
||||||
func QueryCreds(options *DBOptions) ([]Creds, error) {
|
|
||||||
db := GetDB()
|
|
||||||
var creds []Creds
|
|
||||||
query := db.Model(&Creds{})
|
|
||||||
|
|
||||||
// Apply filters based on the provided options
|
|
||||||
if options.Username != "" {
|
|
||||||
if options.ExactMatch {
|
|
||||||
query = query.Where("username = ?", options.Username)
|
|
||||||
} else {
|
|
||||||
query = query.Where("username LIKE ?", "%"+options.Username+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Email != "" {
|
|
||||||
if options.ExactMatch {
|
|
||||||
query = query.Where("email = ?", options.Email)
|
|
||||||
} else {
|
|
||||||
query = query.Where("email LIKE ?", "%"+options.Email+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Password != "" {
|
|
||||||
if options.ExactMatch {
|
|
||||||
query = query.Where("password = ?", options.Password)
|
|
||||||
} else {
|
|
||||||
query = query.Where("password LIKE ?", "%"+options.Password+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply limit
|
|
||||||
if options.Limit > 0 {
|
|
||||||
query = query.Limit(options.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the query
|
|
||||||
if err := query.Find(&creds).Error; err != nil {
|
|
||||||
zap.L().Error("query_creds",
|
|
||||||
zap.String("message", "failed to query credentials"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return nil, fmt.Errorf("failed to query credentials: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return creds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCredsCount returns the count of credentials matching the provided filters
|
|
||||||
func GetCredsCount(options *DBOptions) (int64, error) {
|
|
||||||
db := GetDB()
|
|
||||||
var count int64
|
|
||||||
query := db.Model(&Creds{})
|
|
||||||
|
|
||||||
// Apply filters based on the provided options
|
|
||||||
if options.Username != "" {
|
|
||||||
if options.ExactMatch {
|
|
||||||
query = query.Where("username = ?", options.Username)
|
|
||||||
} else {
|
|
||||||
query = query.Where("username LIKE ?", "%"+options.Username+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Email != "" {
|
|
||||||
if options.ExactMatch {
|
|
||||||
query = query.Where("email = ?", options.Email)
|
|
||||||
} else {
|
|
||||||
query = query.Where("email LIKE ?", "%"+options.Email+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Password != "" {
|
|
||||||
if options.ExactMatch {
|
|
||||||
query = query.Where("password = ?", options.Password)
|
|
||||||
} else {
|
|
||||||
query = query.Where("password LIKE ?", "%"+options.Password+"%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count the results
|
|
||||||
if err := query.Count(&count).Error; err != nil {
|
|
||||||
zap.L().Error("get_creds_count",
|
|
||||||
zap.String("message", "failed to count credentials"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return 0, fmt.Errorf("failed to count credentials: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecuteRawQuery executes a raw SQL query and returns the results as a slice of maps
|
|
||||||
func ExecuteRawQuery(query string) ([]map[string]interface{}, error) {
|
|
||||||
db := GetDB()
|
|
||||||
rows, err := db.Raw(query).Rows()
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("raw_query",
|
|
||||||
zap.String("message", "failed to execute raw query"),
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return nil, fmt.Errorf("failed to execute raw query: %w", 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),
|
|
||||||
)
|
|
||||||
return nil, fmt.Errorf("failed to get columns from raw query: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var results []map[string]interface{}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
// Create a slice of interface{} to hold the values
|
|
||||||
values := make([]interface{}, len(columns))
|
|
||||||
pointers := make([]interface{}, len(columns))
|
|
||||||
for i := range values {
|
|
||||||
pointers[i] = &values[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan the result into the pointers
|
|
||||||
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),
|
|
||||||
)
|
|
||||||
return nil, fmt.Errorf("failed to scan row from raw query: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a map for this row
|
|
||||||
rowMap := make(map[string]interface{})
|
|
||||||
for i, col := range columns {
|
|
||||||
val := values[i]
|
|
||||||
rowMap[col] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, rowMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
@@ -11,6 +11,7 @@ const (
|
|||||||
WhoIsTable
|
WhoIsTable
|
||||||
SubdomainsTable
|
SubdomainsTable
|
||||||
HistoryTable
|
HistoryTable
|
||||||
|
LookupTable
|
||||||
UnknownTable
|
UnknownTable
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,6 +29,8 @@ func GetTable(userInput string) Table {
|
|||||||
return SubdomainsTable
|
return SubdomainsTable
|
||||||
case "history":
|
case "history":
|
||||||
return HistoryTable
|
return HistoryTable
|
||||||
|
case "lookup":
|
||||||
|
return LookupTable
|
||||||
default:
|
default:
|
||||||
return UnknownTable
|
return UnknownTable
|
||||||
}
|
}
|
||||||
@@ -47,6 +50,8 @@ func (t Table) Object() interface{} {
|
|||||||
return SubdomainRecord{}
|
return SubdomainRecord{}
|
||||||
case HistoryTable:
|
case HistoryTable:
|
||||||
return HistoryRecord{}
|
return HistoryRecord{}
|
||||||
|
case LookupTable:
|
||||||
|
return LookupResult{}
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||