Skip to content

Commit 6d36d97

Browse files
committed
init commit
1 parent b0b6493 commit 6d36d97

File tree

4 files changed

+180
-1
lines changed

4 files changed

+180
-1
lines changed

README.md

+64-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,64 @@
1-
# gitpaths
1+
# gitpaths
2+
3+
![](https://img.shields.io/badge/license-MIT-green)
4+
[![](https://img.shields.io/badge/LinkedIn-0077B5?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/mllamazares/)
5+
[![Watch on GitHub](https://img.shields.io/github/watchers/mllamazares/gitpaths.svg?style=social)](https://github.com/mllamazares/gitpaths/watchers)
6+
[![Star on GitHub](https://img.shields.io/github/stars/mllamazares/gitpaths.svg?style=social)](https://github.com/mllamazares/gitpaths/stargazers)
7+
[![Tweet](https://img.shields.io/twitter/url/https/github.com/mllamazares/gitpaths.svg?style=social)](https://twitter.com/intent/tweet?text=Check%20out%20gitpaths%21%20https%3A%2F%2Fgithub.com%2Fmllamazares%2Fgitpaths)
8+
9+
`gitpaths` is a lightweight tool written in Go that retrieves the folder structure of a GitHub repository without needing to clone the entire content.
10+
11+
It's perfect for quickly creating custom wordlists for fuzzing open-source apps or plugins, helping you identify which endpoints in the default repository are accessible.
12+
13+
![gitpaths demo screenshot](demo.png)
14+
15+
## Features
16+
17+
- Fetches file paths from a repository using the GitHub API.
18+
- No API key required.
19+
- Supports specifying a branch within the target repository.
20+
- Minimal dependencies and lightweight.
21+
- Blazing fast! 🚀
22+
23+
## Installation
24+
25+
`gitpaths` requires Go 1.23 or later to install successfully. Simply run the following command to get it:
26+
27+
```shell
28+
go install -v github.com/mllamazares/gitpaths@latest
29+
```
30+
31+
## Usage
32+
33+
```
34+
gitpaths -h
35+
```
36+
37+
This will display help for the tool. Here are all the parameters it supports:
38+
39+
```
40+
Usage of gitpaths:
41+
-b string
42+
Branch name (optional) (default "master")
43+
-h Display help
44+
-o string
45+
Output file (optional)
46+
-silent
47+
Omit banner and sysout printing
48+
-u string
49+
GitHub repository URL
50+
```
51+
52+
### Examples
53+
54+
To create a wordlist, run the following command:
55+
56+
```
57+
gitpaths -u https://github.com/example/plugin -o plugin_wordlist.txt
58+
```
59+
60+
You can then use that wordlist to test which endpoints are reachable on your target:
61+
62+
```
63+
ffuf -u https://supersecret.com/FUZZ -w plugin_wordlist.txt
64+
```

demo.png

168 KB
Loading

gitpaths.go

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"fmt"
7+
"net/http"
8+
"os"
9+
"strings"
10+
)
11+
const yellow = "\033[33m"
12+
const reset = "\033[0m"
13+
14+
const banner = yellow + `
15+
_ __ __ __
16+
___ _(_) /____ ___ _/ /_/ / ___
17+
/ _ \/ / __/ _ \/ _ \/ __/ _ \(_-<
18+
\_, /_/\__/ .__/\_,_/\__/_//_/___/
19+
/___/ /_/ ` + reset + ` v0.0.1
20+
21+
Made by https://linkedin.com/in/mllamazares
22+
23+
---
24+
25+
`
26+
27+
type ApiResponse struct {
28+
Tree []struct {
29+
Path string `json:"path"`
30+
} `json:"tree"`
31+
}
32+
33+
func main() {
34+
repoUrl := flag.String("u", "", "GitHub repository URL")
35+
outputFile := flag.String("o", "", "Output file (optional)")
36+
branch := flag.String("b", "master", "Branch name (optional, default: master)")
37+
silent := flag.Bool("silent", false, "Omit banner and sysout printing")
38+
help := flag.Bool("help", false, "Display help")
39+
40+
flag.Parse()
41+
42+
fmt.Print(banner)
43+
44+
// Display help if -h is provided
45+
if *help {
46+
flag.Usage()
47+
return
48+
}
49+
50+
// Validate input
51+
if *repoUrl == "" {
52+
fmt.Println("Repository URL is required.")
53+
flag.Usage()
54+
os.Exit(1)
55+
}
56+
57+
// Extract owner and repo name from URL provided
58+
parts := strings.Split(strings.TrimPrefix(*repoUrl, "https://github.com/"), "/")
59+
if len(parts) != 2 {
60+
fmt.Println("Invalid repository URL format.")
61+
os.Exit(1)
62+
}
63+
owner := parts[0]
64+
repo := parts[1]
65+
66+
// Get the GitHub API URL
67+
apiUrl := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1", owner, repo, *branch)
68+
69+
resp, err := http.Get(apiUrl)
70+
if err != nil {
71+
fmt.Println("Error making request:", err)
72+
os.Exit(1)
73+
}
74+
defer resp.Body.Close()
75+
76+
if resp.StatusCode != http.StatusOK {
77+
fmt.Printf("Failed to retrieve data: %s\n", resp.Status)
78+
os.Exit(1)
79+
}
80+
81+
// Parse the JSON response
82+
var apiResponse ApiResponse
83+
err = json.NewDecoder(resp.Body).Decode(&apiResponse)
84+
if err != nil {
85+
fmt.Println("Error parsing JSON:", err)
86+
os.Exit(1)
87+
}
88+
89+
// Create the output file if defined
90+
var file *os.File
91+
if *outputFile != "" {
92+
file, err = os.Create(*outputFile)
93+
if err != nil {
94+
fmt.Println("Error creating output file:", err)
95+
os.Exit(1)
96+
}
97+
defer file.Close()
98+
}
99+
100+
// Print to sysout and optionally write the paths to the file
101+
for _, item := range apiResponse.Tree {
102+
if !*silent {
103+
fmt.Println(item.Path)
104+
}
105+
if file != nil {
106+
_, err := file.WriteString(item.Path + "\n")
107+
if err != nil {
108+
fmt.Println("Error writing to output file:", err)
109+
os.Exit(1)
110+
}
111+
}
112+
}
113+
}

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/mllamazares/gitpaths
2+
3+
go 1.23.0

0 commit comments

Comments
 (0)