CoolFace
Apppublic

Fuckingbase/github-keyhunter

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
index.html546 linesDownload Raw Back to root
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