Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
beescuit committed Jul 28, 2024
0 parents commit 6ec3b3c
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 0 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# GithubID

GithubID is an OSINT tool that can be used to retrieve the identities (name/email) that a given Github user has used in their public commits.

Under the hood, this uses Github's GraphQL API to query for the commits a user has pushed and then extracts their contact information from them.

![Screenshot highlighting basic usage of this tool](./img/screenshot.png)

## Usage

You'll need a Github Token to use this tool. You can generate a Personal Access Token [here](https://github.com/settings/tokens).

You can set your token as the `GH_TOKEN` environment variable or pass it through a flag:
```bash
$ githubid -user torvalds -token <your github token>
```

## TODO

- [ ] Add pagination support for the GraphQL call;
- [ ] Add [gharchive.org](https://www.gharchive.org/)/bigquery support to allow finding deleted commits (accidentally got a $100 bill from google cloud and am too depressed to do this now);
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/beescuit/githubid

go 1.22.4

require (
github.com/machinebox/graphql v0.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo=
github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Binary file added img/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
164 changes: 164 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"

"github.com/machinebox/graphql"
)

var query = `
query($userName:String!, $id:ID) {
user(login: $userName){
repositoriesContributedTo(includeUserRepositories: true, contributionTypes: COMMIT, first: 100) {
pageInfo {
hasNextPage
endCursor
}
nodes {
defaultBranchRef {
target {
... on Commit {
history(author: {id: $id}) {
pageInfo {
hasNextPage
endCursor
}
nodes {
commitUrl
author {
email
name
}
}
}
}
}
}
}
}
}
}`

func main() {
username := flag.String("user", "", "(REQUIRED) Username of the target github account")
printsource := flag.Bool("source", false, "Print commit URLs alongside discovered identities")
showall := flag.Bool("all", false, "Print all commits (will repeat duplicate identities)")
flagtoken := flag.String("token", "", "Github API Bearer token (can also be set from the GH_TOKEN env variable)")

flag.Parse()

if *username == "" {
flag.PrintDefaults()
os.Exit(0)
}

var token = ""

if *flagtoken == "" {
token = os.Getenv("GH_TOKEN")
} else {
token = *flagtoken
}

if token == "" {
fmt.Println("Github token missing. Please generate one and set it through the -token flag or the GH_TOKEN environment variable")
os.Exit(0)
}

userreq, err := http.NewRequest("GET", fmt.Sprintf("https://api.github.com/users/%s", *username), nil)
if err != nil {
panic(err)
}

userreq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))

httpclient := http.Client{}
res, err := httpclient.Do(userreq)
if err != nil {
fmt.Printf("Error fetching user ID: %s\n", err)
os.Exit(1)
}

if res.StatusCode == 401 {
fmt.Println("Your Github token seems to be invalid.")
os.Exit(1)
}

var userres struct {
NodeID string `json:"node_id"`
}

err = json.NewDecoder(res.Body).Decode(&userres)
if err != nil {
fmt.Printf("Error parsing github api response: %s\n", err)
os.Exit(1)
}

userid := userres.NodeID

client := graphql.NewClient("https://api.github.com/graphql")

req := graphql.NewRequest(query)

req.Var("userName", username)
req.Var("id", userid)

req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))

var respData struct {
User struct {
RepositoriesContributedTo struct {
PageInfo struct {
HasNextPage bool
EndCursor string
}
Nodes []struct {
DefaultBranchRef struct {
Target struct {
History struct {
PageInfo struct {
HasNextPage bool
EndCursor string
}
Nodes []struct {
CommitURL string
Author struct {
Email string
Name string
}
}
}
}
}
}
}
}
}

err = client.Run(context.Background(), req, &respData)
if err != nil {
log.Fatalf("Failed to execute request: %v", err)
}

unique := make(map[string]bool)

for _, repo := range respData.User.RepositoriesContributedTo.Nodes {
for _, commit := range repo.DefaultBranchRef.Target.History.Nodes {
identity := fmt.Sprintf("%s <%s>", commit.Author.Name, commit.Author.Email)
if _, exists := unique[identity]; *showall || !exists {
unique[identity] = true
if *printsource {
fmt.Printf("%s - %s\n", identity, commit.CommitURL)
} else {
fmt.Println(identity)
}
}
}
}
}

0 comments on commit 6ec3b3c

Please sign in to comment.