Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- Dockerfile +17 -0
- README.md +12 -10
- app.py +42 -0
- dorker.py +58 -0
- dorks/alldorks.txt +33 -0
- requirements.txt +4 -0
- templates/index.html +94 -0
Dockerfile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use an official Python runtime as a parent image
|
| 2 |
+
FROM python:3.9-slim
|
| 3 |
+
|
| 4 |
+
# Set the working directory in the container
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# Copy the current directory contents into the container at /app
|
| 8 |
+
COPY . .
|
| 9 |
+
|
| 10 |
+
# Install any needed packages specified in requirements.txt
|
| 11 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 12 |
+
|
| 13 |
+
# Make port 7860 available to the world outside this container
|
| 14 |
+
EXPOSE 7860
|
| 15 |
+
|
| 16 |
+
# Run app.py when the container launches
|
| 17 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk: docker
|
| 7 |
-
|
| 8 |
-
---
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: HF GitDorker
|
| 3 |
+
emoji: 🕵️
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# HF GitDorker
|
| 11 |
+
|
| 12 |
+
A custom-built, real-time GitHub dorking tool designed for Hugging Face Spaces.
|
app.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import asyncio
|
| 3 |
+
from fastapi import FastAPI, Query, Request
|
| 4 |
+
from fastapi.responses import HTMLResponse, StreamingResponse
|
| 5 |
+
from fastapi.templating import Jinja2Templates
|
| 6 |
+
from dorker import search
|
| 7 |
+
|
| 8 |
+
app = FastAPI()
|
| 9 |
+
templates = Jinja2Templates(directory="templates")
|
| 10 |
+
|
| 11 |
+
async def stream_dorker_results(tokens, query, dork_file_path):
|
| 12 |
+
"""Wraps the dorker.search generator and formats output for SSE."""
|
| 13 |
+
try:
|
| 14 |
+
with open(dork_file_path, 'r', encoding='utf-8') as f:
|
| 15 |
+
dorks = [line.strip() for line in f if line.strip()]
|
| 16 |
+
except FileNotFoundError:
|
| 17 |
+
yield f"data: [ERROR] Dorks file not found: {dork_file_path}\n\n"
|
| 18 |
+
yield f"data: [STREAM_COMPLETE]\n\n"
|
| 19 |
+
return
|
| 20 |
+
|
| 21 |
+
async for result_line in search(tokens, query, dorks):
|
| 22 |
+
yield f"data: {result_line}\n\n"
|
| 23 |
+
await asyncio.sleep(0.01)
|
| 24 |
+
|
| 25 |
+
yield f"data: [STREAM_COMPLETE]\n\n"
|
| 26 |
+
|
| 27 |
+
@app.get("/", response_class=HTMLResponse)
|
| 28 |
+
async def read_root(request: Request):
|
| 29 |
+
return templates.TemplateResponse("index.html", {"request": request})
|
| 30 |
+
|
| 31 |
+
@app.get("/run", response_class=StreamingResponse)
|
| 32 |
+
async def run_dorker_stream(query: str = Query(...), dork_file: str = Query(...)):
|
| 33 |
+
tokens_str = os.environ.get("GHA_TOKENS", "")
|
| 34 |
+
tokens = [token.strip() for token in tokens_str.split(',') if token.strip()]
|
| 35 |
+
|
| 36 |
+
if not tokens:
|
| 37 |
+
async def error_generator():
|
| 38 |
+
yield "data: [ERROR] GHA_TOKENS is not set in the Space secrets.\n\n"
|
| 39 |
+
yield "data: [STREAM_COMPLETE]\n\n"
|
| 40 |
+
return StreamingResponse(error_generator(), media_type="text/event-stream")
|
| 41 |
+
|
| 42 |
+
return StreamingResponse(stream_dorker_results(tokens, query, dork_file), media_type="text/event-stream")
|
dorker.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
+
import httpx
|
| 3 |
+
from itertools import cycle
|
| 4 |
+
|
| 5 |
+
GITHUB_API_URL = "https://api.github.com/search/code"
|
| 6 |
+
|
| 7 |
+
def urlencode(s: str) -> str:
|
| 8 |
+
"""A simple URL encoder for query strings."""
|
| 9 |
+
return s.replace(':', '%3A').replace('"', '%22').replace(' ', '+')
|
| 10 |
+
|
| 11 |
+
async def search(tokens: list, query: str, dorks: list):
|
| 12 |
+
"""
|
| 13 |
+
Async generator to search GitHub for dorks and stream results in real-time.
|
| 14 |
+
"""
|
| 15 |
+
if not tokens:
|
| 16 |
+
yield "[ERROR] No GitHub tokens provided in GHA_TOKENS secret."
|
| 17 |
+
return
|
| 18 |
+
|
| 19 |
+
token_cycler = cycle(tokens)
|
| 20 |
+
headers = {"Accept": "application/vnd.github.v3+json"}
|
| 21 |
+
|
| 22 |
+
async with httpx.AsyncClient() as client:
|
| 23 |
+
for i, dork in enumerate(dorks):
|
| 24 |
+
full_query = f"{query} {dork}"
|
| 25 |
+
url = f"{GITHUB_API_URL}?q={urlencode(full_query)}"
|
| 26 |
+
|
| 27 |
+
current_token = next(token_cycler)
|
| 28 |
+
headers["Authorization"] = f"token {current_token}"
|
| 29 |
+
|
| 30 |
+
yield f"[INFO] [{i+1}/{len(dorks)}] Searching with dork: {dork}"
|
| 31 |
+
|
| 32 |
+
try:
|
| 33 |
+
res = await client.get(url, headers=headers)
|
| 34 |
+
|
| 35 |
+
if res.status_code == 403 and 'rate limit' in res.text.lower():
|
| 36 |
+
yield "[WARN] Rate limit hit. Sleeping for 60 seconds..."
|
| 37 |
+
await asyncio.sleep(60)
|
| 38 |
+
res = await client.get(url, headers=headers) # Retry
|
| 39 |
+
|
| 40 |
+
res.raise_for_status()
|
| 41 |
+
|
| 42 |
+
data = res.json()
|
| 43 |
+
count = data.get("total_count", 0)
|
| 44 |
+
|
| 45 |
+
github_search_url = f"https://github.com/search?q={urlencode(full_query)}&type=Code"
|
| 46 |
+
|
| 47 |
+
if count > 0:
|
| 48 |
+
yield f"[+] FOUND ({count} results): {dork} -> {github_search_url}"
|
| 49 |
+
else:
|
| 50 |
+
yield f"[-] Not Found: {dork}"
|
| 51 |
+
|
| 52 |
+
except httpx.HTTPStatusError as e:
|
| 53 |
+
yield f"[ERROR] HTTP Error for '{dork}': {e.response.status_code}"
|
| 54 |
+
except Exception as e:
|
| 55 |
+
yield f"[ERROR] Unexpected error for '{dork}': {str(e)}"
|
| 56 |
+
|
| 57 |
+
# Sleep to stay within the 30 requests/minute limit
|
| 58 |
+
await asyncio.sleep(2.1)
|
dorks/alldorks.txt
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
filename:.env
|
| 2 |
+
filename:.bash_profile
|
| 3 |
+
filename:.bashrc
|
| 4 |
+
filename:.gitconfig
|
| 5 |
+
filename:credentials
|
| 6 |
+
filename:secrets
|
| 7 |
+
filename:config.json
|
| 8 |
+
|
| 9 |
+
NPM_TOKEN
|
| 10 |
+
GITHUB_TOKEN
|
| 11 |
+
HEROKU_API_KEY
|
| 12 |
+
|
| 13 |
+
language:yaml "aws_access_key"
|
| 14 |
+
|
| 15 |
+
"\.mlab.com" password
|
| 16 |
+
|
| 17 |
+
extension:pem private
|
| 18 |
+
|
| 19 |
+
[WFClient] Password=
|
| 20 |
+
|
| 21 |
+
JEKYLL_GITHUB_TOKEN
|
| 22 |
+
|
| 23 |
+
SF_USERNAME salesforce
|
| 24 |
+
|
| 25 |
+
filename:sftp-config.json
|
| 26 |
+
|
| 27 |
+
filename:idea14.key
|
| 28 |
+
|
| 29 |
+
filename:hub oauth_token
|
| 30 |
+
|
| 31 |
+
filename:dbeaver-data-sources.xml
|
| 32 |
+
|
| 33 |
+
filename:LocalSettings.php
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
jinja2
|
| 4 |
+
httpx
|
templates/index.html
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<title>HF GitDorker</title>
|
| 5 |
+
<style>
|
| 6 |
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: #f4f4f9; color: #333; margin: 2em; }
|
| 7 |
+
.container { max-width: 900px; margin: auto; background: white; padding: 2em; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
| 8 |
+
h1 { color: #4a4a4a; }
|
| 9 |
+
form { display: flex; flex-direction: column; gap: 1em; margin-bottom: 2em;}
|
| 10 |
+
input[type=text], select { padding: 10px; border-radius: 4px; border: 1px solid #ccc; font-size: 1em; }
|
| 11 |
+
button { padding: 10px 20px; border: none; border-radius: 4px; background-color: #007bff; color: white; font-size: 1em; cursor: pointer; transition: background-color 0.2s; }
|
| 12 |
+
button:hover { background-color: #0056b3; }
|
| 13 |
+
button:disabled { background-color: #cccccc; cursor: not-allowed; }
|
| 14 |
+
#results-container h2 { margin-bottom: 0.5em; }
|
| 15 |
+
#results { min-height: 200px; max-height: 60vh; overflow-y: auto; background-color: #282c34; color: #abb2bf; padding: 1em; border-radius: 4px; white-space: pre-wrap; word-wrap: break-word; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.9em;}
|
| 16 |
+
#status { margin-top: 1em; font-style: italic; color: #555; }
|
| 17 |
+
.line-info { color: #61afef; }
|
| 18 |
+
.line-warn { color: #e5c07b; }
|
| 19 |
+
.line-error { color: #e06c75; }
|
| 20 |
+
.line-success { color: #98c379; }
|
| 21 |
+
</style>
|
| 22 |
+
</head>
|
| 23 |
+
<body>
|
| 24 |
+
<div class="container">
|
| 25 |
+
<h1>HF GitDorker</h1>
|
| 26 |
+
<form id="dorker-form">
|
| 27 |
+
<label for="query">Query (e.g., tesla.com):</label>
|
| 28 |
+
<input type="text" id="query" name="query" required>
|
| 29 |
+
|
| 30 |
+
<label for="dork_file">Dorks File:</label>
|
| 31 |
+
<select id="dork_file" name="dork_file">
|
| 32 |
+
<option value="dorks/alldorks.txt">All Dorks</option>
|
| 33 |
+
</select>
|
| 34 |
+
|
| 35 |
+
<button type="submit" id="run-button">Run Dorker</button>
|
| 36 |
+
</form>
|
| 37 |
+
|
| 38 |
+
<div id="results-container">
|
| 39 |
+
<h2>Live Output:</h2>
|
| 40 |
+
<pre id="results"></pre>
|
| 41 |
+
<p id="status"></p>
|
| 42 |
+
</div>
|
| 43 |
+
</div>
|
| 44 |
+
|
| 45 |
+
<script>
|
| 46 |
+
document.getElementById('dorker-form').addEventListener('submit', function(event) {
|
| 47 |
+
event.preventDefault();
|
| 48 |
+
|
| 49 |
+
const query = document.getElementById('query').value;
|
| 50 |
+
const dorkFile = document.getElementById('dork_file').value;
|
| 51 |
+
const resultsDiv = document.getElementById('results');
|
| 52 |
+
const statusDiv = document.getElementById('status');
|
| 53 |
+
const runButton = document.getElementById('run-button');
|
| 54 |
+
|
| 55 |
+
resultsDiv.innerHTML = '';
|
| 56 |
+
statusDiv.textContent = '🚀 Starting... please wait.';
|
| 57 |
+
runButton.disabled = true;
|
| 58 |
+
|
| 59 |
+
const evtSource = new EventSource(`/run?query=${encodeURIComponent(query)}&dork_file=${encodeURIComponent(dorkFile)}`);
|
| 60 |
+
|
| 61 |
+
evtSource.onmessage = function(event) {
|
| 62 |
+
const data = event.data;
|
| 63 |
+
if (data === '[STREAM_COMPLETE]') {
|
| 64 |
+
evtSource.close();
|
| 65 |
+
statusDiv.textContent = '✅ Done.';
|
| 66 |
+
runButton.disabled = false;
|
| 67 |
+
return;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
const line = document.createElement('span');
|
| 71 |
+
if (data.startsWith('[INFO]')) {
|
| 72 |
+
line.className = 'line-info';
|
| 73 |
+
} else if (data.startsWith('[WARN]')) {
|
| 74 |
+
line.className = 'line-warn';
|
| 75 |
+
} else if (data.startsWith('[ERROR]')) {
|
| 76 |
+
line.className = 'line-error';
|
| 77 |
+
} else if (data.startsWith('[+]')) {
|
| 78 |
+
line.className = 'line-success';
|
| 79 |
+
}
|
| 80 |
+
line.textContent = data + '\n';
|
| 81 |
+
resultsDiv.appendChild(line);
|
| 82 |
+
resultsDiv.scrollTop = resultsDiv.scrollHeight;
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
evtSource.onerror = function(err) {
|
| 86 |
+
console.error("EventSource failed:", err);
|
| 87 |
+
statusDiv.textContent = '❌ Error occurred. Connection closed. Check Space logs for details.';
|
| 88 |
+
runButton.disabled = false;
|
| 89 |
+
evtSource.close();
|
| 90 |
+
};
|
| 91 |
+
});
|
| 92 |
+
</script>
|
| 93 |
+
</body>
|
| 94 |
+
</html>
|