🔍 Search
+ +🔍 Search
{result.LeakResult.Rows.length} results in {convertNanoSeconds( @@ -186,7 +193,7 @@
+ Found a result in {convertNanoSeconds( + result.GravatarResult.Duration, + )} +
+From 8729b0c7794613a1a9009e681ab75dd116383086 Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Thu, 25 Sep 2025 19:47:06 +0200 Subject: [PATCH] Init gravatar recon Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com> --- back/go.mod | 3 +- back/go.sum | 6 +- back/search/dataleak/dataleak.go | 3 +- back/search/osint/github.go | 69 ++++-------- back/search/osint/gravatar.go | 32 ++++++ back/search/search.go | 87 ++++++++++++--- back/server/settings.go | 2 + .../index/search/id/gravatarResult.svelte | 104 ++++++++++++++++++ .../components/index/search/id/stats.svelte | 9 +- .../components/index/search/searchbar.svelte | 11 +- .../components/index/search/services.svelte | 4 +- front/src/lib/components/table.svelte | 6 +- front/src/lib/types.ts | 43 ++++---- front/src/routes/search/[id]/index.svelte | 73 +++++++++++- nix/back.nix | 10 ++ 15 files changed, 359 insertions(+), 103 deletions(-) create mode 100644 back/search/osint/gravatar.go create mode 100644 front/src/lib/components/index/search/id/gravatarResult.svelte diff --git a/back/go.mod b/back/go.mod index 6b45ca6..e223966 100644 --- a/back/go.mod +++ b/back/go.mod @@ -4,6 +4,7 @@ go 1.25.0 require ( github.com/anotherhadi/github-recon v1.5.6 + github.com/anotherhadi/gravatar-recon v1.0.1 github.com/charmbracelet/log v0.4.2 github.com/gin-gonic/gin v1.10.1 github.com/marcboeker/go-duckdb v1.8.5 @@ -49,7 +50,7 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/saran13raj/go-pixels v0.0.0-20250629121333-58b240a3ae51 // indirect - github.com/spf13/pflag v1.0.7 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect diff --git a/back/go.sum b/back/go.sum index edf6922..fd642a6 100644 --- a/back/go.sum +++ b/back/go.sum @@ -2,6 +2,8 @@ github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7X github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/anotherhadi/github-recon v1.5.6 h1:IN3lQZRqqNbPpSyP5fvNoJrYODbM2tNwS5tiRgD+i1s= github.com/anotherhadi/github-recon v1.5.6/go.mod h1:E2tmCmjEZdJeBx8u1J8sSMtnmU8aDQ6IjCoq3ykoHtY= +github.com/anotherhadi/gravatar-recon v1.0.1 h1:Js3NCrVXhJb/ShG6PMzma1bsER0lQi9qbFHK1uABMm4= +github.com/anotherhadi/gravatar-recon v1.0.1/go.mod h1:cMP1mqW5vxwRCIZDbQGr0gb/SzbAveM2EcdJ/BwXQN8= github.com/apache/arrow-go/v18 v18.1.0 h1:agLwJUiVuwXZdwPYVrlITfx7bndULJ/dggbnLFgDp/Y= github.com/apache/arrow-go/v18 v18.1.0/go.mod h1:tigU/sIgKNXaesf5d7Y95jBBKS5KsxTqYBKXFsvKzo0= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= @@ -115,8 +117,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/saran13raj/go-pixels v0.0.0-20250629121333-58b240a3ae51 h1:H/XUfYcLxI3CBmDlgBpnOeTntRgqWvIoUXnqhCF5a0s= github.com/saran13raj/go-pixels v0.0.0-20250629121333-58b240a3ae51/go.mod h1:sqhdZVLvqzTEBtmZBuTnFDUW0Lsryw2X2/wrLgqLEYg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/back/search/dataleak/dataleak.go b/back/search/dataleak/dataleak.go index 5d0705d..6cac1a3 100644 --- a/back/search/dataleak/dataleak.go +++ b/back/search/dataleak/dataleak.go @@ -15,13 +15,14 @@ type LeakResult struct { Duration time.Duration Rows []map[string]string Error string + Inactive bool LimitHit bool // Whether the search hit the limit } func Search(s *server.Server, queryText, column string, exactMatch bool) LeakResult { if len(*(s.Dataleaks)) == 0 { return LeakResult{ - Error: "No dataleak configured", + Inactive: true, } } now := time.Now() diff --git a/back/search/osint/github.go b/back/search/osint/github.go index 3ec1fbc..998d207 100644 --- a/back/search/osint/github.go +++ b/back/search/osint/github.go @@ -14,15 +14,13 @@ import ( type GithubResult struct { Duration time.Duration Error string + Inactive bool UsernameResult *recon_username.UsernameResult EmailResult *recon_email.EmailResult } -func Search(s *server.Server, queryText, column string) *GithubResult { - if !s.Settings.GithubRecon { - return nil - } +func GithubSearch(s *server.Server, queryText, queryType string) GithubResult { gr := GithubResult{} now := time.Now() settings := github_recon_settings.GetDefaultSettings() @@ -35,56 +33,27 @@ func Search(s *server.Server, queryText, column string) *GithubResult { queryText = strings.TrimSpace(queryText) - if column == "email" || strings.HasSuffix(column, "_email") || - column == "username" || strings.HasSuffix(column, "_username") || - column == "" || column == "all" { - if isValidEmail(queryText) { - settings.Target = queryText - settings.TargetType = github_recon_settings.TargetEmail - result := recon_email.Email(settings) - gr.EmailResult = &result - } else if isValidUsername(queryText) { - settings.Target = queryText - settings.TargetType = github_recon_settings.TargetUsername - result, err := recon_username.Username(settings) - if err != nil { - gr.Error = err.Error() - } - if result.User.Username == "" { - gr.UsernameResult = nil - } else { - gr.UsernameResult = &result - } + if queryType == "email" { + settings.Target = queryText + settings.TargetType = github_recon_settings.TargetEmail + result := recon_email.Email(settings) + gr.EmailResult = &result + } else if queryType == "username" { + settings.Target = queryText + settings.TargetType = github_recon_settings.TargetUsername + result, err := recon_username.Username(settings) + if err != nil { + gr.Error = err.Error() + } + if result.User.Username == "" { + gr.UsernameResult = nil } else { - return nil + gr.UsernameResult = &result } } else { - return nil + return GithubResult{Inactive: true} } gr.Duration = time.Since(now) - return &gr -} - -func isValidEmail(email string) bool { - if !strings.Contains(email, "@") || !strings.Contains(email, ".") { - return false - } - if strings.HasPrefix(email, "@") || strings.HasSuffix(email, "@") { - return false - } - if strings.Contains(email, " ") { - return false - } - return true -} - -func isValidUsername(username string) bool { - if len(username) < 1 || len(username) > 39 { - return false - } - if strings.Contains(username, " ") { - return false - } - return true + return gr } diff --git a/back/search/osint/gravatar.go b/back/search/osint/gravatar.go new file mode 100644 index 0000000..6f949e8 --- /dev/null +++ b/back/search/osint/gravatar.go @@ -0,0 +1,32 @@ +package osint + +import ( + "time" + + "github.com/anotherhadi/eleakxir/backend/server" + gravatar_recon "github.com/anotherhadi/gravatar-recon" +) + +type GravatarResult struct { + Duration time.Duration + Error string + Inactive bool + + Results []gravatar_recon.GravatarProfile +} + +func GravatarSearch(s *server.Server, queryText string) GravatarResult { + gr := GravatarResult{} + now := time.Now() + results, err := gravatar_recon.GetGravatarProfiles(queryText) + + if err != nil { + gr.Error = err.Error() + return gr + } + + gr.Results = *results + + gr.Duration = time.Since(now) + return gr +} diff --git a/back/search/search.go b/back/search/search.go index a03e146..896bb2b 100644 --- a/back/search/search.go +++ b/back/search/search.go @@ -19,8 +19,9 @@ type Query struct { ExactMatch bool // Whether to search for an exact match // Services - Datawells bool // Whether to include datawells in the search - GithubRecon bool // Whether to include github-recon in the search + Datawells bool // Whether to include datawells in the search + GithubRecon bool // Whether to include github-recon in the search + GravatarRecon bool // Whether to include gravatar-recon in the search } type Result struct { @@ -29,27 +30,25 @@ type Result struct { Status string // "pending", "completed" Query Query - LeakResult dataleak.LeakResult - GithubResult osint.GithubResult + LeakResult dataleak.LeakResult + GithubResult osint.GithubResult + GravatarResult osint.GravatarResult } func Search(s *server.Server, q Query, r *Result, mu *sync.RWMutex) { var wg sync.WaitGroup - cleanQueryText := strings.TrimPrefix(q.Text, "^") - cleanQueryText = strings.TrimSuffix(q.Text, "$") - mu.Lock() r.Date = time.Now() r.Status = "pending" r.Query = q mu.Unlock() - wg.Add(2) + wg.Add(3) go func() { if !q.Datawells { mu.Lock() - r.LeakResult = dataleak.LeakResult{Error: "not enabled"} + r.LeakResult = dataleak.LeakResult{Inactive: true} mu.Unlock() wg.Done() return @@ -61,21 +60,52 @@ func Search(s *server.Server, q Query, r *Result, mu *sync.RWMutex) { wg.Done() }() + cleanQueryText := strings.TrimPrefix(q.Text, "^") + cleanQueryText = strings.TrimSuffix(q.Text, "$") + isEmail := false + isUsername := false + + if q.Column == "email" || strings.HasSuffix(q.Column, "_email") || + q.Column == "username" || strings.HasSuffix(q.Column, "_username") || + q.Column == "" || q.Column == "all" { + if isValidEmail(cleanQueryText) { + isEmail = true + } else if isValidUsername(cleanQueryText) { + isUsername = true + } + } + go func() { - if !q.GithubRecon { + if !q.GithubRecon || !s.Settings.GithubRecon || (!isEmail && !isUsername) { mu.Lock() - r.GithubResult = osint.GithubResult{Error: "not enabled"} + r.GithubResult = osint.GithubResult{Inactive: true} mu.Unlock() wg.Done() return } - githubResult := osint.Search(s, cleanQueryText, q.Column) - mu.Lock() - if githubResult == nil { - r.GithubResult = osint.GithubResult{} - } else { - r.GithubResult = *githubResult + var githubResult osint.GithubResult + if isEmail { + githubResult = osint.GithubSearch(s, cleanQueryText, "email") + } else if isUsername { + githubResult = osint.GithubSearch(s, cleanQueryText, "username") } + mu.Lock() + r.GithubResult = githubResult + mu.Unlock() + wg.Done() + }() + + go func() { + if !q.GravatarRecon || !s.Settings.GravatarRecon || !isEmail { + mu.Lock() + r.GravatarResult = osint.GravatarResult{Inactive: true} + mu.Unlock() + wg.Done() + return + } + gravatarResult := osint.GravatarSearch(s, cleanQueryText) + mu.Lock() + r.GravatarResult = gravatarResult mu.Unlock() wg.Done() }() @@ -91,3 +121,26 @@ func EncodeQueryID(q Query, dataleaksCount uint64) string { raw, _ := json.Marshal(q) return fmt.Sprintf("%d:%s", dataleaksCount, base64.URLEncoding.EncodeToString(raw)) } + +func isValidEmail(email string) bool { + if !strings.Contains(email, "@") || !strings.Contains(email, ".") { + return false + } + if strings.HasPrefix(email, "@") || strings.HasSuffix(email, "@") { + return false + } + if strings.Contains(email, " ") { + return false + } + return true +} + +func isValidUsername(username string) bool { + if len(username) < 1 || len(username) > 39 { + return false + } + if strings.Contains(username, " ") { + return false + } + return true +} diff --git a/back/server/settings.go b/back/server/settings.go index b0fdb49..6f3c225 100644 --- a/back/server/settings.go +++ b/back/server/settings.go @@ -28,6 +28,7 @@ type ServerSettings struct { GithubToken string `json:"-"` // Github token for github-recon GithubTokenLoaded bool GithubDeepMode bool // Deep mode for github-recon + GravatarRecon bool // Activate gravatar-recon OSINT tool } func LoadServerSettings() ServerSettings { @@ -49,6 +50,7 @@ func LoadServerSettings() ServerSettings { GithubRecon: getEnvBoolOrDefault("GITHUB_RECON", true), GithubToken: getEnvStringOrDefault("GITHUB_TOKEN", "null"), GithubDeepMode: getEnvBoolOrDefault("GITHUB_DEEP_MODE", false), + GravatarRecon: getEnvBoolOrDefault("GRAVATAR_RECON", true), } if ss.GithubToken == "null" || strings.TrimSpace(ss.GithubToken) == "" { diff --git a/front/src/lib/components/index/search/id/gravatarResult.svelte b/front/src/lib/components/index/search/id/gravatarResult.svelte new file mode 100644 index 0000000..c0570a7 --- /dev/null +++ b/front/src/lib/components/index/search/id/gravatarResult.svelte @@ -0,0 +1,104 @@ + + +
+ @{r.preferredUsername} +
+{r.aboutMe}
+