UNPKG

gitrecon

Version:

This CLI tool is designed to retrieve exposed email addresses from a GitHub user’s public activity and to identify a GitHub username associated with a given email address. It is intended strictly for educational use and ethical security research. Please u

288 lines (236 loc) 9.92 kB
// Main scanning orchestrator - orijinal main function logic const Commands = require('../cli/commands'); const CliParser = require('../cli/parser'); const HelpSystem = require('../cli/help'); const ConsoleFormatter = require('../formatters/consoleFormatter'); const ColorUtils = require('../utils/colors'); const RateLimiter = require('./rateLimiter'); const ProgressTracker = require('./progressTracker'); class Scanner { constructor() { this.parser = new CliParser(); this.commands = new Commands(); this.helpSystem = new HelpSystem(); this.rateLimiter = new RateLimiter(); this.progressTracker = new ProgressTracker(); } // Main scanning entry point - orijinal main function async run(argv = null) { let args = null; try { // Display banner - orijinal koddan ConsoleFormatter.displayBanner(); // Parse command line arguments args = this.parser.parse(argv); // Validate arguments const validation = this.parser.validate(args); if (!validation.isValid) { validation.errors.forEach(error => { ConsoleFormatter.displayError(error); }); console.log(''); this.parser.printHelp(); return; } // Validate command requirements const commandValidation = this.commands.validateCommand(args); if (!commandValidation.isValid) { ConsoleFormatter.displayError(commandValidation.error); return; } // Initialize rate limiting if needed if (args.token) { this.rateLimiter.setToken(args.token, args.site); } // Execute the command const result = await this.commands.execute(args); if (result) { // Display completion message console.log(ColorUtils.green('Reconnaissance completed.')); // Display legal disclaimer - orijinal koddan ConsoleFormatter.displayLegalDisclaimer(); return result; } } catch (error) { ConsoleFormatter.displayError('Scanning failed', error.message); if (args && args.verbose) { console.error(error.stack); } throw error; } } // Run with custom configuration async runWithConfig(config) { const args = this.parseConfig(config); return await this.run(args); } // Parse configuration object to CLI args format parseConfig(config) { const args = []; Object.entries(config).forEach(([key, value]) => { if (value === true) { args.push(`--${key}`); } else if (value !== false && value !== null && value !== undefined) { args.push(`--${key}`, value.toString()); } }); return args; } // Scan multiple targets async scanMultiple(targets) { const results = []; for (let i = 0; i < targets.length; i++) { const target = targets[i]; ConsoleFormatter.displayInfo(`Scanning ${i + 1}/${targets.length}: ${target.username || target.org || target.email}`); try { const result = await this.runWithConfig(target); results.push({ target, result, status: 'success' }); } catch (error) { results.push({ target, error: error.message, status: 'error' }); ConsoleFormatter.displayError(`Failed to scan ${target.username || target.org || target.email}`, error.message); } // Add delay between scans if (i < targets.length - 1) { await new Promise(resolve => setTimeout(resolve, 2000)); } } return results; } // Interactive scanning mode async runInteractive() { const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const question = (query) => new Promise(resolve => rl.question(query, resolve)); try { ConsoleFormatter.displayBanner(); console.log(ColorUtils.bright('\n=== INTERACTIVE MODE ===\n')); // Get target type const targetType = await question(ColorUtils.cyan('Target type (user/org/email): ')); if (!['user', 'org', 'email'].includes(targetType)) { ConsoleFormatter.displayError('Invalid target type'); return; } // Get target value const target = await question(ColorUtils.cyan(`Enter ${targetType}: `)); // Get platform const platform = await question(ColorUtils.cyan('Platform (github/gitlab) [github]: ')) || 'github'; // Get options const verbose = await question(ColorUtils.cyan('Verbose output? (y/n) [n]: ')); const includeOutput = await question(ColorUtils.cyan('Save output? (json/html/all/n) [n]: ')); // Build config const config = { [targetType === 'org' ? 'org' : targetType === 'email' ? 'email' : 'user']: target, site: platform, verbose: verbose.toLowerCase() === 'y' }; if (includeOutput && includeOutput !== 'n') { config.output = includeOutput; } console.log(ColorUtils.bright('\n=== STARTING SCAN ===\n')); const result = await this.runWithConfig(config); if (result) { console.log(ColorUtils.bright('\n=== SCAN COMPLETE ===')); ConsoleFormatter.displaySummary(result); } } catch (error) { ConsoleFormatter.displayError('Interactive scan failed', error.message); } finally { rl.close(); } } // Validate scan environment async validateEnvironment() { const checks = []; // Check Node.js version const nodeVersion = process.version; const majorVersion = parseInt(nodeVersion.split('.')[0].substring(1)); checks.push({ name: 'Node.js Version', status: majorVersion >= 14 ? 'pass' : 'fail', details: `${nodeVersion} (requires >= 14.0.0)` }); // Check network connectivity try { const https = require('https'); await new Promise((resolve, reject) => { const req = https.get('https://api.github.com', { timeout: 5000 }, resolve); req.on('error', reject); req.on('timeout', () => reject(new Error('timeout'))); }); checks.push({ name: 'GitHub API Connectivity', status: 'pass', details: 'Successfully connected' }); } catch (error) { checks.push({ name: 'GitHub API Connectivity', status: 'fail', details: error.message }); } // Check write permissions const fs = require('fs'); const path = require('path'); try { const testFile = path.join(process.cwd(), '.gitrecon-test'); fs.writeFileSync(testFile, 'test'); fs.unlinkSync(testFile); checks.push({ name: 'Write Permissions', status: 'pass', details: 'Output directory writable' }); } catch (error) { checks.push({ name: 'Write Permissions', status: 'fail', details: 'Cannot write to current directory' }); } return checks; } // Display environment validation results async displayEnvironmentCheck() { console.log(ColorUtils.bright('\n=== ENVIRONMENT CHECK ===\n')); const checks = await this.validateEnvironment(); checks.forEach(check => { const status = check.status === 'pass' ? ColorUtils.green('✓ PASS') : ColorUtils.red('✗ FAIL'); console.log(`${check.name}: ${status} - ${check.details}`); }); const allPassed = checks.every(check => check.status === 'pass'); if (allPassed) { console.log(ColorUtils.green('\n✓ Environment ready for scanning')); } else { console.log(ColorUtils.red('\n✗ Environment issues detected')); } return allPassed; } // Get scanner status and statistics getStatus() { return { version: '0.0.3', rateLimiter: this.rateLimiter.getStatus(), progressTracker: this.progressTracker.getStatus(), availableCommands: this.commands.getAvailableCommands(), supportedPlatforms: ['github', 'gitlab'] }; } // Cleanup resources cleanup() { this.rateLimiter.cleanup(); this.progressTracker.cleanup(); } } module.exports = Scanner;