Updated README.md

updated typos

added 'easy time' upgrade to log filtering
This commit is contained in:
Ar1ste1a
2025-05-16 20:21:36 -04:00
parent 91fd75abe2
commit 32150ce6ee
8 changed files with 345 additions and 146 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

+20 -2
View File
@@ -271,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.
![Alt text](.img/easy_time_parsing.png "Easy Time")
#### You may also used dates mixed with easy time to perform queries.
![Alt text](.img/easy_time_query_2.png "Mixed Time")
#### 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
+14 -1
View File
@@ -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)
}
}, },
} }
) )
+11 -32
View File
@@ -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
}
}
+3 -3
View File
@@ -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)
+31 -108
View File
@@ -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,19 +540,7 @@ var (
fmt.Println(result) fmt.Println(result)
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)
} }
return return
} }
@@ -647,3 +550,23 @@ var (
}, },
} }
) )
func checkBalance(w *whois.DehashedWhoIs) {
balance, err := w.Balance()
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 balance == 0 {
fmt.Println("[!] No WHOIS credits remaining.")
os.Exit(0)
}
}
+266
View File
@@ -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
}