feat: modernize Python package structure · techgaun/github-dorks@ad9ab90 · GitHub
Skip to content

Commit ad9ab90

Browse files
committed
feat: modernize Python package structure
1 parent 337b4c9 commit ad9ab90

11 files changed

Lines changed: 306 additions & 260 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 2 additions & 0 deletions

‎Dockerfile‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ FROM python:3.12-slim
44
WORKDIR /app
55

66
# Copy only the files needed to install and run the project
7-
COPY github-dork.py /app/
7+
COPY github_dorks /app/github_dorks
88
COPY github-dorks.txt /app/
9-
COPY setup.py /app/
9+
COPY pyproject.toml /app/
1010
COPY README.md /app/
1111

1212
RUN pip install --no-cache-dir .
@@ -18,4 +18,4 @@ ENV PYTHONIOENCODING=UTF-8
1818
# Create volume for potential output files
1919
VOLUME ["/app/output"]
2020

21-
ENTRYPOINT ["python", "github-dork.py"]
21+
ENTRYPOINT ["github-dorks"]

‎README.md‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
## GitHub Dork Search Tool
88

9-
[github-dork.py](github-dork.py) is a simple python tool that can search through your repository or your organization/user repositories. It's not a perfect tool at the moment but provides basic functionality to automate the search on your repositories against the dorks specified in the text file.
9+
`github-dorks` is a Python command-line tool that searches a repository or an
10+
organization/user's repositories using the queries in a dorks file.
1011

1112
### Installation
1213

@@ -48,19 +49,22 @@ GH_URL - Environment variable to specify GitHub Enterprise base URL
4849
Some example usages are listed below:
4950

5051
```shell
51-
github-dork.py -r techgaun/github-dorks # search a single repo
52+
github-dorks -r techgaun/github-dorks # search a single repo
5253

53-
github-dork.py -u techgaun # search all repos of a user
54+
github-dorks -u techgaun # search all repos of a user
5455

55-
github-dork.py -u dev-nepal # search all repos of an organization
56+
github-dorks -u dev-nepal # search all repos of an organization
5657

57-
GH_USER=techgaun GH_PWD=<mypass> github-dork.py -u dev-nepal # search as authenticated user
58+
GH_USER=techgaun GH_PWD=<mypass> github-dorks -u dev-nepal # search as authenticated user
5859

59-
GH_TOKEN=<github_token> github-dork.py -u dev-nepal # search using auth token
60+
GH_TOKEN=<github_token> github-dorks -u dev-nepal # search using auth token
6061

61-
GH_URL=https://github.example.com github-dork.py -u dev-nepal # search a GitHub Enterprise instance
62+
GH_URL=https://github.example.com github-dorks -u dev-nepal # search a GitHub Enterprise instance
6263
```
6364

65+
The legacy `python github-dork.py ...` invocation remains available for
66+
compatibility. The package can also run as `python -m github_dorks ...`.
67+
6468
### Development
6569

6670
Run the dependency-free unit test suite with:

‎github-dork.py‎

Lines changed: 2 additions & 221 deletions
Original file line numberDiff line numberDiff line change
@@ -1,226 +1,7 @@
11
#!/usr/bin/env python
2-
# -*- encoding: utf-8 -*-
2+
"""Backward-compatible entry point for existing users."""
33

4-
import github3 as github
5-
import os
6-
import argparse
7-
import csv
8-
import time
9-
import feedparser
10-
from copy import copy
11-
from contextlib import nullcontext
12-
from sys import stderr, prefix
13-
14-
__version__ = '0.1.1'
15-
16-
gh_user = os.getenv('GH_USER', None)
17-
gh_pass = os.getenv('GH_PWD', None)
18-
gh_token = os.getenv('GH_TOKEN', None)
19-
gh_url = os.getenv('GH_URL', None)
20-
21-
if gh_url is None:
22-
gh = github.GitHub(username=gh_user, password=gh_pass, token=gh_token)
23-
else:
24-
gh = github.GitHubEnterprise(
25-
url=gh_url, username=gh_user, password=gh_pass, token=gh_token)
26-
27-
28-
def search_wrapper(gen):
29-
while True:
30-
gen_back = copy(gen)
31-
try:
32-
yield next(gen)
33-
except StopIteration:
34-
return
35-
except github.exceptions.ForbiddenError:
36-
search_rate_limit = gh.rate_limit()['resources']['search']
37-
# limit_remaining = search_rate_limit['remaining']
38-
reset_time = search_rate_limit['reset']
39-
current_time = int(time.time())
40-
sleep_time = reset_time - current_time + 1
41-
stderr.write(
42-
'GitHub Search API rate limit reached. Sleeping for %d seconds.\n\n'
43-
% (sleep_time))
44-
time.sleep(sleep_time)
45-
yield next(gen_back)
46-
except Exception as e:
47-
raise e
48-
49-
50-
def metasearch(repo_to_search=None,
51-
user_to_search=None,
52-
gh_dorks_file=None,
53-
active_monit=None,
54-
output_filename=None,
55-
refresh_time=60):
56-
if active_monit is None:
57-
search(repo_to_search, user_to_search, gh_dorks_file, active_monit, output_filename)
58-
else:
59-
monit(gh_dorks_file, active_monit, refresh_time)
60-
61-
62-
def monit(gh_dorks_file=None, active_monit=None, refresh_time=60):
63-
if gh_user is None:
64-
raise Exception('Error, env Github user variable needed')
65-
else:
66-
print(
67-
'Monitoring user private feed searching new code to be dorked.' +
68-
'Every new merged pull request trigger user scan.'
69-
)
70-
print('-----')
71-
items_history = list()
72-
gh_private_feed = "https://github.com/{}.private.atom?token={}".format(
73-
gh_user, active_monit)
74-
while True:
75-
feed = feedparser.parse(gh_private_feed)
76-
for i in feed['items']:
77-
if 'merged pull' in i['title']:
78-
if i['title'] not in items_history:
79-
search(
80-
user_to_search=i['author_detail']['name'],
81-
gh_dorks_file=gh_dorks_file)
82-
items_history.append(i['title'])
83-
print('Waiting for new items...')
84-
time.sleep(refresh_time)
85-
86-
87-
def search(repo_to_search=None,
88-
user_to_search=None,
89-
gh_dorks_file=None,
90-
active_monit=None,
91-
output_filename=None):
92-
93-
if gh_dorks_file is None:
94-
for path_prefix in ['.', os.path.join(prefix, 'github-dorks/')]:
95-
filename = os.path.join(path_prefix, 'github-dorks.txt')
96-
if os.path.isfile(filename):
97-
gh_dorks_file = filename
98-
break
99-
100-
if gh_dorks_file is None or not os.path.isfile(gh_dorks_file):
101-
raise Exception('Error, the dorks file path is not valid')
102-
if user_to_search:
103-
print("Scanning User: ", user_to_search)
104-
if repo_to_search:
105-
print("Scanning Repo: ", repo_to_search)
106-
found = False
107-
108-
output_context = (
109-
open(output_filename, 'w', newline='', encoding='utf-8')
110-
if output_filename else nullcontext(None)
111-
)
112-
113-
with open(gh_dorks_file, 'r', encoding='utf-8') as dork_file, output_context as output_file:
114-
# Write CSV Header
115-
csv_writer = None
116-
if output_file:
117-
csv_writer = csv.writer(output_file)
118-
csv_writer.writerow([
119-
'Issue Type (Dork)', 'Text Matches', 'File Path',
120-
'Score/Relevance', 'URL of File'
121-
])
122-
for dork in dork_file:
123-
dork = dork.strip()
124-
if not dork or dork[0] in '#;':
125-
continue
126-
addendum = ''
127-
if repo_to_search:
128-
addendum = ' repo:' + repo_to_search
129-
elif user_to_search:
130-
addendum = ' user:' + user_to_search
131-
132-
dork = dork + addendum
133-
search_results = search_wrapper(gh.search_code(dork))
134-
try:
135-
for search_result in search_results:
136-
found = True
137-
fmt_args = {
138-
'dork': dork,
139-
'text_matches': search_result.text_matches,
140-
'path': search_result.path,
141-
'score': search_result.score,
142-
'url': search_result.html_url
143-
}
144-
145-
# Either write to file or print output
146-
if csv_writer:
147-
csv_writer.writerow([
148-
fmt_args['dork'], fmt_args['text_matches'],
149-
fmt_args['path'], fmt_args['score'], fmt_args['url']
150-
])
151-
else:
152-
result = '\n'.join([
153-
'Found result for {dork}',
154-
'Text matches: {text_matches}', 'File path: {path}',
155-
'Score/Relevance: {score}', 'URL of File: {url}', ''
156-
]).format(**fmt_args)
157-
print(result)
158-
159-
except github.exceptions.GitHubError as e:
160-
print('GitHubError encountered on search of dork: ' + dork)
161-
print(e)
162-
return
163-
except Exception as e:
164-
print(e)
165-
print('Error encountered on search of dork: ' + dork)
166-
167-
if not found:
168-
print('No results for your dork search' + addendum + '. Hurray!')
169-
170-
171-
def main():
172-
parser = argparse.ArgumentParser(
173-
description='Search github for github dorks',
174-
epilog='Use responsibly, Enjoy pentesting')
175-
176-
parser.add_argument(
177-
'-v', '--version', action='version', version='%(prog)s ' + __version__)
178-
179-
group = parser.add_mutually_exclusive_group(required=True)
180-
group.add_argument(
181-
'-u',
182-
'--user',
183-
dest='user_to_search',
184-
action='store',
185-
help='Github user/org to search within. Eg: techgaun')
186-
187-
group.add_argument(
188-
'-r',
189-
'--repo',
190-
dest='repo_to_search',
191-
action='store',
192-
help='Github repo to search within. Eg: techgaun/github-dorks')
193-
194-
parser.add_argument(
195-
'-d',
196-
'--dork',
197-
dest='gh_dorks_file',
198-
action='store',
199-
help='Github dorks file. Eg: github-dorks.txt')
200-
201-
group.add_argument(
202-
'-m',
203-
'--monit',
204-
dest='active_monit',
205-
action='store',
206-
help='Monitors Github user private feed with feed token'
207-
)
208-
209-
parser.add_argument(
210-
'-o',
211-
'--outputFile',
212-
dest='output_filename',
213-
action='store',
214-
help='CSV File to write results to. This overwrites the file provided! Eg: out.csv'
215-
)
216-
217-
args = parser.parse_args()
218-
metasearch(
219-
repo_to_search=args.repo_to_search,
220-
user_to_search=args.user_to_search,
221-
gh_dorks_file=args.gh_dorks_file,
222-
active_monit=args.active_monit,
223-
output_filename=args.output_filename)
4+
from github_dorks.cli import main
2245

2256

2267
if __name__ == '__main__':

‎github_dorks/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Search GitHub repositories for accidentally committed sensitive data."""
2+
3+
__version__ = '0.1.1'

‎github_dorks/__main__.py‎

Lines changed: 5 additions & 0 deletions

0 commit comments

Comments
 (0)