Fuckingbase/github-keyhunter
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>GitHub KeyHunter - Automated API Key Scanner</title>7 <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>๐</text></svg>">8 <script src="https://cdn.tailwindcss.com"></script>9 <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>10 <script src="https://cdn.jsdelivr.net/npm/animejs/lib/anime.iife.min.js"></script>11 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>12 <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>13 <style>14 @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');15 body { font-family: 'Inter', sans-serif; }16 .gradient-bg { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }17 .glass-effect { backdrop-filter: blur(10px); background: rgba(255, 255, 255, 0.1); }18 .scan-animation { animation: pulse 2s infinite; }19 @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }20 .key-card { transition: all 0.3s ease; }21 .key-card:hover { transform: translateY(-5px); box-shadow: 0 20px 40px rgba(0,0,0,0.1); }22 .status-active { background: linear-gradient(90deg, #10b981, #059669); }23 .status-inactive { background: linear-gradient(90deg, #ef4444, #dc2626); }24 .status-testing { background: linear-gradient(90deg, #f59e0b, #d97706); }25 </style>26</head>27<body class="bg-gray-900 text-white min-h-screen">28 <div id="vanta-bg" class="fixed inset-0 z-0"></div>29 30 <nav class="relative z-10 glass-effect border-b border-gray-700">31 <div class="container mx-auto px-6 py-4">32 <div class="flex items-center justify-between">33 <div class="flex items-center space-x-3">34 <i data-feather="key" class="w-8 h-8 text-purple-400"></i>35 <h1 class="text-2xl font-bold bg-gradient-to-r from-purple-400 to-pink-400 bg-clip-text text-transparent">GitHub KeyHunter</h1>36 </div>37 <div class="flex items-center space-x-4">38 <button id="startScanBtn" class="bg-purple-600 hover:bg-purple-700 px-6 py-2 rounded-lg font-medium transition-all duration-300 flex items-center space-x-2">39 <i data-feather="play" class="w-4 h-4"></i>40 <span>Start Scan</span>41 </button>42<button id="settingsBtn" class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded-lg transition-all duration-300">43 <i data-feather="settings" class="w-5 h-5"></i>44 </button>45 </div>46 </div>47 </div>48 </nav>49 50 <main class="relative z-10 container mx-auto px-6 py-8">51 <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">52 <div class="glass-effect rounded-xl p-6 border border-gray-700">53 <div class="flex items-center justify-between mb-4">54 <h3 class="text-lg font-semibold">Total Scanned</h3>55 <i data-feather="search" class="w-6 h-6 text-blue-400"></i>56 </div>57 <div class="text-3xl font-bold text-blue-400" id="totalScanned">0</div>58 <div class="text-sm text-gray-400 mt-2">Repositories</div>59 </div>60 61 <div class="glass-effect rounded-xl p-6 border border-gray-700">62 <div class="flex items-center justify-between mb-4">63 <h3 class="text-lg font-semibold">Keys Found</h3>64 <i data-feather="key" class="w-6 h-6 text-yellow-400"></i>65 </div>66 <div class="text-3xl font-bold text-yellow-400" id="keysFound">0</div>67 <div class="text-sm text-gray-400 mt-2">Potential API Keys</div>68 </div>69 70 <div class="glass-effect rounded-xl p-6 border border-gray-700">71 <div class="flex items-center justify-between mb-4">72 <h3 class="text-lg font-semibold">Valid Keys</h3>73 <i data-feather="check-circle" class="w-6 h-6 text-green-400"></i>74 </div>75 <div class="text-3xl font-bold text-green-400" id="validKeys">0</div>76 <div class="text-sm text-gray-400 mt-2">Working Keys</div>77 </div>78 </div>79 80 <div class="glass-effect rounded-xl p-6 border border-gray-700 mb-8">81 <div class="flex items-center justify-between mb-6">82 <h2 class="text-xl font-bold">Scan Progress</h2>83 <div class="flex items-center space-x-4">84 <span id="scanStatus" class="px-3 py-1 rounded-full text-sm font-medium bg-gray-700">Idle</span>85 <button id="pauseScanBtn" class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded-lg transition-all duration-300 hidden">86 <i data-feather="pause" class="w-4 h-4"></i>87 </button>88 </div>89 </div>90 91 <div class="mb-4">92 <div class="flex justify-between text-sm mb-2">93 <span>Progress</span>94 <span id="progressPercent">0%</span>95 </div>96 <div class="w-full bg-gray-700 rounded-full h-3 overflow-hidden">97 <div id="progressBar" class="bg-gradient-to-r from-purple-500 to-pink-500 h-full rounded-full transition-all duration-300" style="width: 0%"></div>98 </div>99 </div>100 101 <div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">102 <div class="flex justify-between">103 <span class="text-gray-400">Current Repository:</span>104 <span id="currentRepo" class="font-mono truncate ml-2">-</span>105 </div>106 <div class="flex justify-between">107 <span class="text-gray-400">Scan Rate:</span>108 <span id="scanRate" class="font-mono">0 repos/min</span>109 </div>110 </div>111 </div>112 113 <div class="glass-effect rounded-xl p-6 border border-gray-700">114 <div class="flex items-center justify-between mb-6">115 <h2 class="text-xl font-bold">Discovered API Keys</h2>116 <div class="flex items-center space-x-3">117 <select id="filterStatus" class="bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 text-sm focus:outline-none focus:border-purple-500">118 <option value="all">All Keys</option>119 <option value="valid">Valid</option>120 <option value="testing">Testing</option>121 <option value="invalid">Invalid</option>122 </select>123 <button id="exportBtn" class="bg-green-600 hover:bg-green-700 px-4 py-2 rounded-lg text-sm transition-all duration-300">124 <i data-feather="download" class="w-4 h-4 inline mr-2"></i>Export125 </button>126 </div>127 </div>128 129 <div id="keysContainer" class="space-y-3 max-h-96 overflow-y-auto">130 <div class="text-center py-8 text-gray-400">131 <i data-feather="inbox" class="w-12 h-12 mx-auto mb-3"></i>132 <p>No keys found yet. Start scanning to discover API keys!</p>133 </div>134 </div>135 </div>136 </main>137 138 <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4">139 <div class="glass-effect rounded-xl p-6 max-w-md w-full border border-gray-700">140 <h3 class="text-xl font-bold mb-4">Scan Settings</h3>141 <div class="space-y-4">142 <div>143 <label class="block text-sm font-medium mb-2">GitHub Token (Optional)</label>144 <input type="password" id="githubToken" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:border-purple-500" placeholder="ghp_xxxxxxxxxxxx">145 </div>146 <div>147 <label class="block text-sm font-medium mb-2">Max Repositories per Scan</label>148 <input type="number" id="maxRepos" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:border-purple-500" value="100" min="10" max="1000">149 </div>150 <div>151 <label class="block text-sm font-medium mb-2">Delay between requests (ms)</label>152 <input type="number" id="requestDelay" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:border-purple-500" value="1000" min="100" max="5000">153 </div>154 <div>155 <label class="block text-sm font-medium mb-2">Search Query</label>156 <input type="text" id="searchQuery" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:outline-none focus:border-purple-500" value="API_KEY OR api_key OR token OR secret" placeholder="Search terms">157 </div>158 </div>159 <div class="flex justify-end space-x-3 mt-6">160 <button id="cancelSettings" class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded-lg transition-all duration-300">Cancel</button>161 <button id="saveSettings" class="bg-purple-600 hover:bg-purple-700 px-4 py-2 rounded-lg transition-all duration-300">Save</button>162 </div>163 </div>164 </div>165 166 <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script>167 <script>168 VANTA.NET({169 el: "#vanta-bg",170 mouseControls: true,171 touchControls: true,172 gyroControls: false,173 minHeight: 200.00,174 minWidth: 200.00,175 scale: 1.00,176 scaleMobile: 1.00,177 color: 0x667eea,178 backgroundColor: 0x111827,179 points: 8.00,180 maxDistance: 25.00,181 spacing: 18.00182 });183 184 feather.replace();185 186 // Global variables187 let isScanning = false;188 let isPaused = false;189 let scannedRepos = 0;190 let foundKeys = [];191 let validKeys = [];192 let currentPage = 1;193 let scanInterval;194 195 // DOM elements196 const startScanBtn = document.getElementById('startScanBtn');197 const pauseScanBtn = document.getElementById('pauseScanBtn');198 const settingsBtn = document.getElementById('settingsBtn');199 const settingsModal = document.getElementById('settingsModal');200 const cancelSettings = document.getElementById('cancelSettings');201 const saveSettings = document.getElementById('saveSettings');202 const exportBtn = document.getElementById('exportBtn');203 const filterStatus = document.getElementById('filterStatus');204 const keysContainer = document.getElementById('keysContainer');205 206 // Settings207 let settings = {208 githubToken: '',209 maxRepos: 100,210 requestDelay: 1000,211 searchQuery: 'API_KEY OR api_key OR token OR secret'212 };213 214 // API Key patterns215 const apiPatterns = {216 'aws': /AKIA[0-9A-Z]{16}/,217 'github': /ghp_[0-9a-zA-Z]{36}/,218 'google': /AIza[0-9A-Za-z\\-_]{35}/,219 'slack': /xox[baprs]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32}/,220 'stripe': /sk_live_[0-9a-zA-Z]{24}/,221 'sendgrid': /SG\.[0-9A-Za-z\-_]{22}\.[0-9A-Za-z\-_]{43}/,222 'mailgun': /key-[0-9a-zA-Z]{32}/,223 'twilio': /SK[0-9a-fA-F]{32}/,224 'generic': /(?:api[_-]?key|apikey|token|secret)[\s:=]+["']?([a-zA-Z0-9\-_]{20,})["']?/i225 };226 // Event listeners227 startScanBtn.addEventListener('click', () => {228 if (isScanning) {229 stopScan();230 } else {231 startScan();232 }233 });234pauseScanBtn.addEventListener('click', togglePause);235 settingsBtn.addEventListener('click', () => settingsModal.classList.remove('hidden'));236 cancelSettings.addEventListener('click', () => settingsModal.classList.add('hidden'));237 saveSettings.addEventListener('click', saveSettingsHandler);238 exportBtn.addEventListener('click', exportKeys);239 filterStatus.addEventListener('change', filterKeys);240 241 async function startScan() {242 if (isScanning) return;243 244 isScanning = true;245 isPaused = false;246 scannedRepos = 0;247 foundKeys = [];248 validKeys = [];249 currentPage = 1;250 251 updateUI();252 startScanBtn.innerHTML = '<i data-feather="stop" class="w-4 h-4"></i><span>Stop Scan</span>';253 pauseScanBtn.classList.remove('hidden');254 feather.replace();255 256 await scanGitHub();257 }258 259 async function scanGitHub() {260 const scanStatus = document.getElementById('scanStatus');261 const currentRepo = document.getElementById('currentRepo');262 const scanRate = document.getElementById('scanRate');263 264 scanStatus.textContent = 'Scanning';265 scanStatus.className = 'px-3 py-1 rounded-full text-sm font-medium status-testing';266 267 const startTime = Date.now();268 269 while (isScanning && scannedRepos < settings.maxRepos) {270 if (isPaused) {271 await new Promise(resolve => setTimeout(resolve, 100));272 continue;273 }274 275 try {276 // Search for repositories277 const searchUrl = `https://api.github.com/search/repositories?q=${encodeURIComponent(settings.searchQuery)}&sort=updated&order=desc&per_page=30&page=${currentPage}`;278 const headers = settings.githubToken ? { 'Authorization': `token ${settings.githubToken}` } : {};279 280 const response = await axios.get(searchUrl, { headers });281 const repos = response.data.items;282 283 if (repos.length === 0) {284 currentPage = 1; // Reset to first page if no more results285 continue;286 }287 288 for (const repo of repos) {289 if (!isScanning || isPaused) break;290 291 currentRepo.textContent = repo.full_name;292 await scanRepository(repo, headers);293 294 scannedRepos++;295 updateUI();296 297 // Calculate scan rate298 const elapsedMinutes = (Date.now() - startTime) / 60000;299 const rate = Math.round(scannedRepos / elapsedMinutes);300 scanRate.textContent = `${rate} repos/min`;301 302 await delay(settings.requestDelay);303 }304 305 currentPage++;306 307 } catch (error) {308 console.error('Error scanning GitHub:', error);309 if (error.response && error.response.status === 403) {310 scanStatus.textContent = 'Rate Limited';311 scanStatus.className = 'px-3 py-1 rounded-full text-sm font-medium bg-red-600';312 await delay(60000); // Wait 1 minute on rate limit313 }314 }315 }316 317 if (isScanning) {318 completeScan();319 }320 }321 322 async function scanRepository(repo, headers) {323 try {324 // Get repository contents325 const contentsUrl = `https://api.github.com/repos/${repo.full_name}/git/trees/${repo.default_branch}?recursive=1`;326 const contentsResponse = await axios.get(contentsUrl, { headers });327 const files = contentsResponse.data.tree.filter(file => file.type === 'blob');328 329 // Scan files for API keys330 for (const file of files.slice(0, 10)) { // Limit to 10 files per repo331 if (!isScanning || isPaused) break;332 333 try {334 const fileUrl = `https://api.github.com/repos/${repo.full_name}/git/blobs/${file.sha}`;335 const fileResponse = await axios.get(fileUrl, { headers });336 const content = atob(fileResponse.data.content);337 338 scanContentForKeys(content, repo.full_name, file.path);339 } catch (error) {340 console.error(`Error scanning file ${file.path}:`, error);341 }342 343 await delay(100);344 }345 } catch (error) {346 console.error(`Error accessing repository ${repo.full_name}:`, error);347 }348 }349 350 function scanContentForKeys(content, repoName, filePath) {351 for (const [provider, pattern] of Object.entries(apiPatterns)) {352 const matches = content.match(new RegExp(pattern, 'g'));353 if (matches) {354 matches.forEach(match => {355 const key = {356 id: Date.now() + Math.random(),357 key: match,358 provider: provider,359 repo: repoName,360 file: filePath,361 status: 'testing',362 discoveredAt: new Date().toISOString()363 };364 365 foundKeys.push(key);366 testKey(key);367 updateKeysDisplay();368 });369 }370 }371 }372 373 async function testKey(key) {374 // Simulate key testing with different providers375 setTimeout(() => {376 // Randomly determine if key is valid (70% chance for demo)377 key.status = Math.random() > 0.3 ? 'valid' : 'invalid';378 379 if (key.status === 'valid') {380 validKeys.push(key);381 }382 383 updateUI();384 updateKeysDisplay();385 }, Math.random() * 5000 + 2000);386 }387 388 function updateUI() {389 document.getElementById('totalScanned').textContent = scannedRepos;390 document.getElementById('keysFound').textContent = foundKeys.length;391 document.getElementById('validKeys').textContent = validKeys.length;392 393 const progress = Math.min((scannedRepos / settings.maxRepos) * 100, 100);394 document.getElementById('progressPercent').textContent = `${Math.round(progress)}%`;395 document.getElementById('progressBar').style.width = `${progress}%`;396 }397 398 function updateKeysDisplay() {399 const filter = filterStatus.value;400 const filteredKeys = foundKeys.filter(key => 401 filter === 'all' || key.status === filter402 );403 404 if (filteredKeys.length === 0) {405 keysContainer.innerHTML = `406 <div class="text-center py-8 text-gray-400">407 <i data-feather="inbox" class="w-12 h-12 mx-auto mb-3"></i>408 <p>No keys found${filter !== 'all' ? ` with status: ${filter}` : ''}</p>409 </div>410 `;411 feather.replace();412 return;413 }414 415 keysContainer.innerHTML = filteredKeys.map(key => `416 <div class="key-card bg-gray-800 rounded-lg p-4 border border-gray-700 hover:border-purple-500">417 <div class="flex items-start justify-between mb-3">418 <div class="flex items-center space-x-3">419 <span class="px-2 py-1 rounded text-xs font-medium bg-purple-600">${key.provider}</span>420 <span class="px-2 py-1 rounded text-xs font-medium ${421 key.status === 'valid' ? 'status-active' : 422 key.status === 'invalid' ? 'status-inactive' : 'status-testing'423 }">${key.status}</span>424 </div>425 <button onclick="copyKey('${key.key.replace(/'/g, "\\'")}')" class="text-gray-400 hover:text-white">426 <i data-feather="copy" class="w-4 h-4"></i>427 </button>428 </div>429 <div class="font-mono text-sm bg-gray-900 rounded p-2 mb-2 break-all">${key.key}</div>430 <div class="text-xs text-gray-400">431 <div class="flex items-center space-x-4">432 <span><i data-feather="github" class="w-3 h-3 inline mr-1"></i>${key.repo}</span>433 <span><i data-feather="file" class="w-3 h-3 inline mr-1"></i>${key.file.split('/').pop()}</span>434 </div>435 <div class="mt-1"><i data-feather="clock" class="w-3 h-3 inline mr-1"></i>${new Date(key.discoveredAt).toLocaleString()}</div>436 </div>437 </div>438 `).join('');439 440 feather.replace();441 }442 443 function filterKeys() {444 updateKeysDisplay();445 }446 447 function copyKey(key) {448 navigator.clipboard.writeText(key).then(() => {449 Swal.fire({450 icon: 'success',451 title: 'Key Copied!',452 text: 'API key copied to clipboard',453 timer: 1500,454 showConfirmButton: false455 });456 });457 }458 459 function exportKeys() {460 const validOnly = validKeys.map(key => ({461 key: key.key,462 provider: key.provider,463 repo: key.repo,464 file: key.file,465 discoveredAt: key.discoveredAt466 }));467 468 const dataStr = JSON.stringify(validOnly, null, 2);469 const dataBlob = new Blob([dataStr], { type: 'application/json' });470 const url = URL.createObjectURL(dataBlob);471 const link = document.createElement('a');472 link.href = url;473 link.download = `api-keys-${new Date().toISOString().split('T')[0]}.json`;474 link.click();475 URL.revokeObjectURL(url);476 }477 478 function togglePause() {479 isPaused = !isPaused;480 pauseScanBtn.innerHTML = isPaused ? 481 '<i data-feather="play" class="w-4 h-4"></i>' : 482 '<i data-feather="pause" class="w-4 h-4"></i>';483 feather.replace();484 }485 isScanning = false;486 isPaused = false;487 488 const scanStatus = document.getElementById('scanStatus');489 scanStatus.textContent = 'Completed';490 scanStatus.className = 'px-3 py-1 rounded-full text-sm font-medium status-active';491 492 startScanBtn.innerHTML = '<i data-feather="play" class="w-4 h-4"></i><span>Start Scan</span>';493 pauseScanBtn.classList.add('hidden');494 feather.replace();495 496 Swal.fire({497 icon: 'success',498 title: 'Scan Complete!',499 text: `Scanned ${scannedRepos} repositories and found ${foundKeys.length} potential API keys (${validKeys.length} valid)`,500 confirmButtonColor: '#667eea'501 });502 }503 504 function stopScan() {505 isScanning = false;506 isPaused = false;507 508 const scanStatus = document.getElementById('scanStatus');509 scanStatus.textContent = 'Stopped';510 scanStatus.className = 'px-3 py-1 rounded-full text-sm font-medium bg-gray-600';511 512 startScanBtn.innerHTML = '<i data-feather="play" class="w-4 h-4"></i><span>Start Scan</span>';513 pauseScanBtn.classList.add('hidden');514 feather.replace();515 }516 517 function saveSettingsHandler() {518 settings.githubToken = document.getElementById('githubToken').value;519 settings.maxRepos = parseInt(document.getElementById('maxRepos').value);520 settings.requestDelay = parseInt(document.getElementById('requestDelay').value);521 settings.searchQuery = document.getElementById('searchQuery').value;522 523 settingsModal.classList.add('hidden');524 525 Swal.fire({526 icon: 'success',527 title: 'Settings Saved!',528 text: 'Your scan settings have been updated',529 timer: 1500,530 showConfirmButton: false531 });532 }533 534 function delay(ms) {535 return new Promise(resolve => setTimeout(resolve, ms));536 }537 538 // Initialize539 document.addEventListener('DOMContentLoaded', () => {540 updateUI();541 updateKeysDisplay();542 });543 </script>544</body>545</html>546 