|
13 | 13 |
|
14 | 14 | CONFIG_DIR = os.path.expanduser("~/.config/dumpdork") |
15 | 15 | CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yaml") |
16 | | -HOST = "google-search74.p.rapidapi.com" |
| 16 | + |
| 17 | +PROVIDERS = { |
| 18 | + "google": { |
| 19 | + "host": "google-search74.p.rapidapi.com", |
| 20 | + "url_pattern": "https://google-search74.p.rapidapi.com/" |
| 21 | + }, |
| 22 | + "brave": { |
| 23 | + "host": "brave-web-search.p.rapidapi.com", |
| 24 | + "url_pattern": "https://brave-web-search.p.rapidapi.com/search" |
| 25 | + }, |
| 26 | + "github": { |
| 27 | + "is_official": True, |
| 28 | + "url_pattern": "https://api.github.com/search/repositories" |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +def print_banner(): |
| 33 | + banner = rf""" |
| 34 | +{Fore.CYAN} ____ ____ _ |
| 35 | +{Fore.CYAN} | _ \ _ _ _ __ ___ _ __ | _ \ ___ _ __| | __ |
| 36 | +{Fore.CYAN} | | | | | | | '_ ` _ \| '_ \| | | |/ _ \| '__| |/ / |
| 37 | +{Fore.CYAN} | |_| | |_| | | | | | | |_) | |_| | (_) | | | < |
| 38 | +{Fore.CYAN} |____/ \__,_|_| |_| |_| .__/|____/ \___/|_| |_|\_\ |
| 39 | +{Fore.CYAN} |_| |
| 40 | +{Fore.YELLOW} Advanced Dorking Tool v1.0 |
| 41 | +{Fore.WHITE} Created by: Mateo Fumis (hackermater) |
| 42 | + """ |
| 43 | + print(banner) |
17 | 44 |
|
18 | 45 | def load_config(config_file): |
19 | 46 | try: |
20 | 47 | with open(config_file, 'r') as file: |
21 | 48 | return yaml.safe_load(file) |
22 | 49 | except FileNotFoundError: |
23 | | - print(f"{Fore.RED}Error: Configuration file '{config_file}' not found or is empty.") |
| 50 | + print(f"{Fore.RED}Error: Configuration file '{config_file}' not found.") |
| 51 | + print(f"{Fore.YELLOW}Tip: Run with -w to set up your API keys.") |
24 | 52 | sys.exit(1) |
25 | 53 | except yaml.YAMLError as e: |
26 | 54 | print(f"{Fore.RED}Error: Failed to parse configuration file. {e}") |
27 | 55 | sys.exit(1) |
28 | 56 |
|
29 | | -def save_config(config_file, key): |
| 57 | +def save_config(config_file, keys_dict): |
30 | 58 | os.makedirs(CONFIG_DIR, exist_ok=True) |
31 | 59 | config = { |
32 | 60 | 'rapidapi': { |
33 | | - 'host': HOST, |
34 | | - 'key': key |
| 61 | + 'host': PROVIDERS["google"]["host"], |
| 62 | + 'keys': keys_dict |
35 | 63 | } |
36 | 64 | } |
37 | 65 | with open(config_file, 'w') as file: |
38 | | - yaml.dump(config, file) |
| 66 | + yaml.dump(config, file, default_flow_style=False) |
39 | 67 | print(f"{Fore.GREEN}Configuration saved to '{config_file}'") |
40 | 68 |
|
41 | | -def rapidapi_search(query, limit, key): |
42 | | - encoded_query = urllib.parse.quote(query) |
43 | | - |
44 | | - url = f"https://{HOST}/?query={encoded_query}&limit={limit}&related_keywords=true" |
45 | | - |
46 | | - headers = { |
47 | | - 'x-rapidapi-host': HOST, |
48 | | - 'x-rapidapi-key': key, |
49 | | - 'Content-Type': "application/json" |
50 | | - } |
51 | | - |
52 | | - response = requests.get(url, headers=headers) |
53 | | - |
54 | | - if response.status_code == 200: |
55 | | - return response |
56 | | - else: |
57 | | - print(f"{Fore.RED}Error: {response.status_code}") |
| 69 | +def perform_search(source, query, limit, key): |
| 70 | + if source not in PROVIDERS: |
58 | 71 | return None |
59 | 72 |
|
60 | | -def print_help(): |
61 | | - print("🔍 Welcome to DumpDork !!") |
62 | | - print("\nUsage: dumpdork 'query' [--limit number] [--output filename.json] [--config-file config.yaml]") |
63 | | - print("\nOptions:") |
64 | | - print(" query The search query.") |
65 | | - print(" --limit Number of results to return (default is 50. Limit: 300).") |
66 | | - print(" --output Output file to save results in JSON format.") |
67 | | - print(" --config-file Path to custom YAML config file containing API credentials. Default is: ~/.config/dumpdork/config.yaml") |
68 | | - print(" --wizard Set up your API key for dumpdork, step by step with easy.") |
69 | | - print("\n📋 Examples:") |
70 | | - print(" $: dumpdork 'site:*.example.com AND (intext:\"aws_access_key_id\" | intext:\"aws_secret_access_key\" filetype:json | filetype:yaml) ' --limit 200 --output aws_credentials.json ") |
71 | | - print(" $: dumpdork '(site:*.example.com AND -site:docs.example.com) AND (inurl:\"/login\" | inurl:\"/signup\" | inurl:\"/admin\" | inurl:\"/register\") AND (ext:php | ext:aspx)' --limit 300 --output sqli_forms.json") |
72 | | - print(" $: dumpdork 'site:*.example.com AND (intitle:\"Index of /\" | intitle:\"index of\") AND (intext:\".log\" | intext:\".sql\" | intext:\".txt\" | intext:\".sh\")' --config-file ~/.config/dumpdork/config_files/credentials_01.yaml --output sensitive_files.json") |
| 73 | + provider = PROVIDERS[source] |
| 74 | + headers = {} |
| 75 | + params = {} |
| 76 | + |
| 77 | + if source == "github": |
| 78 | + url = provider["url_pattern"] |
| 79 | + params = {'q': query, 'per_page': limit} |
| 80 | + if key and key.strip() != "" and key != "Not configured": |
| 81 | + headers['Authorization'] = f"token {key}" |
| 82 | + headers['Accept'] = "application/vnd.github.v3+json" |
| 83 | + headers['User-Agent'] = 'DumpDork-Tool' |
| 84 | + |
| 85 | + elif source == "google": |
| 86 | + url = provider["url_pattern"] |
| 87 | + params = {'query': query, 'limit': limit} |
| 88 | + headers = { |
| 89 | + 'x-rapidapi-host': provider["host"], |
| 90 | + 'x-rapidapi-key': key |
| 91 | + } |
73 | 92 |
|
74 | | -def wizard_setup(): |
75 | | - print(f"{Fore.YELLOW}Welcome to the API Key Setup Wizard!") |
76 | | - print(f"\033[1m[*] See detailed instructions at: https://github.com/mateofumis/dumpdork/blob/main/API_SETUP_GUIDE.md") |
77 | | - print("1. Sign up at: https://rapidapi.com/herosAPI/api/google-search74/playground") |
78 | | - print("2. Subscribe for free and copy the API key.") |
79 | | - |
80 | | - key = input(f"\033[1mEnter your RapidAPI key: ").strip() |
81 | | - if not key: |
82 | | - print(f"{Fore.RED}Error: API key cannot be empty.") |
83 | | - sys.exit(1) |
| 93 | + elif source == "brave": |
| 94 | + url = provider["url_pattern"] |
| 95 | + params = {'q': query, 'count': limit} |
| 96 | + headers = { |
| 97 | + 'x-rapidapi-host': provider["host"], |
| 98 | + 'x-rapidapi-key': key |
| 99 | + } |
| 100 | + |
| 101 | + try: |
| 102 | + response = requests.get(url, headers=headers, params=params) |
| 103 | + if response.status_code == 200: |
| 104 | + return response.json() |
| 105 | + elif response.status_code == 401: |
| 106 | + print(f"{Fore.RED}Error 401: Unauthorized. Your {source} token/key is invalid.") |
| 107 | + elif response.status_code == 403: |
| 108 | + print(f"{Fore.RED}Error 403: Forbidden for {source}.") |
| 109 | + else: |
| 110 | + print(f"{Fore.RED}Error {response.status_code} from {source}") |
| 111 | + except Exception as e: |
| 112 | + print(f"{Fore.RED}Connection Error: {e}") |
| 113 | + return None |
84 | 114 |
|
85 | | - save_config(CONFIG_FILE, key) |
| 115 | +def wizard_setup(): |
| 116 | + print(f"{Fore.YELLOW}{Style.BRIGHT}Welcome to the DumpDork API Setup Wizard!") |
| 117 | + |
| 118 | + keys_dict = {} |
| 119 | + if os.path.exists(CONFIG_FILE): |
| 120 | + try: |
| 121 | + existing_config = load_config(CONFIG_FILE) |
| 122 | + keys_dict = existing_config.get('rapidapi', {}).get('keys', {}) |
| 123 | + except: |
| 124 | + pass |
| 125 | + |
| 126 | + for source in PROVIDERS.keys(): |
| 127 | + print(f"\n{Fore.CYAN}--- {source.upper()} ---") |
| 128 | + if source == "github": |
| 129 | + print("Using official GitHub API (api.github.com)") |
| 130 | + else: |
| 131 | + print(f"RapidAPI Host: {PROVIDERS[source]['host']}") |
| 132 | + |
| 133 | + current_key = keys_dict.get(source, "Not configured") |
| 134 | + print(f"Current Key: {current_key}") |
| 135 | + |
| 136 | + prompt = f"Enter API key/token for {source} (leave blank to skip): " |
| 137 | + new_key = input(prompt).strip() |
| 138 | + |
| 139 | + if new_key.lower() == 'clear': |
| 140 | + keys_dict[source] = "" |
| 141 | + elif new_key: |
| 142 | + keys_dict[source] = new_key |
| 143 | + |
| 144 | + save_config(CONFIG_FILE, keys_dict) |
86 | 145 |
|
87 | 146 | def main(): |
88 | | - parser = argparse.ArgumentParser(description='Perform a search using Google Dorks') |
89 | | - parser.add_argument('query', nargs='?', type=str, help='The search query.') |
90 | | - parser.add_argument('--limit', type=int, default=50, help='Number of results to return (default is 50. Limit: 300).') |
91 | | - parser.add_argument('--output', type=str, help='Output file to save results in JSON format.') |
92 | | - parser.add_argument('--config-file', type=str, default=CONFIG_FILE, help='Path to the YAML config file containing API credentials. Default is: ~/.config/dumpdork/config.yaml') |
93 | | - parser.add_argument('--wizard', action='store_true', help='Set up your API key for dumpdork, step by step with easy.') |
| 147 | + parser = argparse.ArgumentParser(description='Perform a search using Dorks across multiple platforms', prog='dumpdork.py') |
| 148 | + parser.add_argument('query', nargs='?', type=str, help='Search query or dork') |
| 149 | + parser.add_argument('-s', '--source', type=str, default='google', choices=['google', 'github', 'brave'], help='Search engine source') |
| 150 | + parser.add_argument('-l', '--limit', type=int, default=50, help='Maximum number of results') |
| 151 | + parser.add_argument('-o', '--output', type=str, help='Save results to a JSON file') |
| 152 | + parser.add_argument('-w', '--wizard', action='store_true', help='Run API configuration wizard') |
| 153 | + |
| 154 | + print_banner() |
| 155 | + |
| 156 | + if len(sys.argv) == 1: |
| 157 | + parser.print_usage() |
| 158 | + print(f"\nUse {Fore.YELLOW}-h{Fore.RESET} or {Fore.YELLOW}--help{Fore.RESET} for full details.\n") |
| 159 | + sys.exit(0) |
94 | 160 |
|
95 | 161 | args = parser.parse_args() |
96 | 162 |
|
97 | | - if args.limit > 300: |
98 | | - print(f"{Fore.RED}Error: Maximum limit allowed for the API is 300.") |
99 | | - sys.exit(1) |
100 | | - |
101 | 163 | if args.wizard: |
102 | 164 | wizard_setup() |
103 | 165 | sys.exit(0) |
104 | 166 |
|
105 | 167 | if args.query is None: |
106 | | - print_help() |
| 168 | + parser.print_usage() |
| 169 | + print(f"{Fore.RED}Error: A search query is required unless using -w.") |
107 | 170 | sys.exit(1) |
108 | 171 |
|
109 | | - config = load_config(args.config_file) |
110 | | - key = config['rapidapi']['key'] |
| 172 | + config = load_config(CONFIG_FILE) |
| 173 | + keys_dict = config.get('rapidapi', {}).get('keys', {}) |
| 174 | + api_key = keys_dict.get(args.source) |
111 | 175 |
|
112 | | - response = rapidapi_search(args.query, args.limit, key) |
| 176 | + if not api_key and args.source != "github": |
| 177 | + print(f"{Fore.RED}Error: No API key found for {args.source}. Run with -w to setup.") |
| 178 | + sys.exit(1) |
113 | 179 |
|
114 | | - if response: |
115 | | - results = response.json() |
116 | | - items = results.get('results', []) |
117 | | - for item in items: |
118 | | - title = item.get('title', 'No Title') |
119 | | - url = urllib.parse.unquote(item.get('url', 'No URL')) |
120 | | - description = item.get('description', 'No Description') |
| 180 | + print(f"{Fore.YELLOW}Searching {args.source} for: {args.query}...\n") |
| 181 | + results = perform_search(args.source, args.query, args.limit, api_key) |
121 | 182 |
|
122 | | - print(f"{Fore.CYAN}Title: {Style.BRIGHT}{title}") |
123 | | - print(f"{Fore.GREEN}URL: {Style.BRIGHT}{url}") |
124 | | - print(f"{Fore.MAGENTA}Description: {Style.BRIGHT}{description}\n") |
| 183 | + if results: |
| 184 | + items = [] |
| 185 | + if args.source == "brave": |
| 186 | + items = results.get('results', []) or results.get('web', {}).get('results', []) |
| 187 | + elif args.source == "github": |
| 188 | + items = results.get('items', []) |
| 189 | + else: # Google |
| 190 | + items = results.get('results', []) |
125 | 191 |
|
126 | | - total_results = len(items) |
127 | | - print(f"{Fore.YELLOW}Total results: {total_results}") |
| 192 | + for item in items: |
| 193 | + title = item.get('title') or item.get('full_name') or 'No Title' |
| 194 | + url = item.get('url') or item.get('html_url') or item.get('link') or 'No URL' |
| 195 | + desc = item.get('description') or item.get('snippet') or 'No Description' |
128 | 196 |
|
| 197 | + print(f"{Fore.CYAN}Title: {Style.BRIGHT}{title}") |
| 198 | + print(f"{Fore.GREEN}URL: {Style.BRIGHT}{urllib.parse.unquote(url)}") |
| 199 | + print(f"{Fore.MAGENTA}Description: {Style.BRIGHT}{desc}\n") |
| 200 | + |
| 201 | + print(f"{Fore.YELLOW}{Style.BRIGHT}Execution finished. Total results found: {len(items)}") |
| 202 | + |
| 203 | + if args.output: |
| 204 | + with open(args.output, 'w', encoding='utf-8') as json_file: |
| 205 | + json.dump(results, json_file, ensure_ascii=False, indent=4) |
| 206 | + print(f"{Fore.YELLOW}Results saved to '{args.output}'") |
129 | 207 | else: |
130 | | - print(f"{Fore.RED}No results found or an error occurred.") |
131 | | - |
132 | | - if args.output: |
133 | | - with open(args.output, 'w', encoding='utf-8') as json_file: |
134 | | - json.dump(response.json(), json_file, ensure_ascii=False, indent=4) |
135 | | - print(f"{Fore.YELLOW}Results saved to '{args.output}'") |
| 208 | + print(f"{Fore.RED}No results found.") |
| 209 | + print(f"{Fore.YELLOW}{Style.BRIGHT}Execution finished. Total results found: 0") |
136 | 210 |
|
137 | 211 | if __name__ == "__main__": |
138 | 212 | main() |
0 commit comments