UNPKG

ssh-bridge-ai

Version:

AI-Powered SSH Tool with Bulletproof Connections & Enterprise Sandbox Security + Cursor-like Confirmation - Enable AI assistants to securely SSH into your servers with persistent sessions, keepalive, automatic recovery, sandbox command testing, and user c

1,316 lines (1,127 loc) • 120 kB
#!/usr/bin/env node const { program, Command } = require('commander'); const chalk = require('chalk'); const ora = require('ora'); const inquirer = require('inquirer'); const path = require('path'); const { APIClient } = require('./api'); const { Config } = require('./config'); const { AutoUpdater } = require('./updater'); const { IntegrityChecker } = require('./security/integrity-checker'); const { FeatureGate } = require('./security/feature-gate'); // Initialize these lazily to avoid requiring environment variables for basic commands let api = null; let config = null; let updater = null; let integrityChecker = null; let featureGate = null; // Version selector function async function selectVersion() { // Skip version selection for help, version, and basic commands const args = process.argv.slice(2); const isBasicCommand = args.length === 0 || args.includes('-V') || args.includes('--version') || args.includes('-h') || args.includes('--help') || args.includes('--help-all') || args.includes('help-simple') || args.includes('list-all') || args.includes('install-help') || args.includes('setup') || args.includes('interactive') || args.includes('change-mode') || args.includes('quick-start') || args.includes('examples') || args.includes('troubleshoot') || args.includes('sandbox') || args.includes('security') || args.includes('license') || args.includes('keygen') || args.includes('keys') || args.includes('copy-key') || args.includes('exec') || args.includes('run') || args.includes('connect') || args.includes('session') || args.includes('copy') || args.includes('register') || args.includes('verify') || args.includes('update') || args.includes('config') || args.includes('servers') || args.includes('usage'); if (isBasicCommand) { return; // Skip version selection } // Check if user has already made a choice const userConfig = getConfig(); const preferredMode = userConfig.getPreferredMode(); if (preferredMode && !process.argv.includes('--change-mode')) { return; // User already has a preference } console.log(chalk.cyan('\nšŸš€ Welcome to SSHBridge! Choose your experience:\n')); const { mode } = await inquirer.prompt([ { type: 'list', name: 'mode', message: 'How would you like to use SSHBridge?', choices: [ { name: 'šŸŽÆ Interactive Mode (Beginner Friendly)', value: 'interactive', description: 'Step-by-step guidance, menus, and smart defaults' }, { name: '⚔ Direct Commands (Power User)', value: 'direct', description: 'Traditional CLI commands with enhanced security' } ], default: preferredMode || 'interactive' } ]); // Save user preference permanently userConfig.setPreferredMode(mode); if (mode === 'interactive') { console.log(chalk.green('\nāœ… Interactive mode enabled!')); console.log(chalk.blue('šŸ’” Use "sshbridge setup" to get started')); console.log(chalk.blue('šŸ’” Use "sshbridge --change-mode" to change later\n')); // Offer to start setup wizard const { startSetup } = await inquirer.prompt([ { type: 'confirm', name: 'startSetup', message: 'Would you like to start the setup wizard now?', default: true } ]); if (startSetup) { await startSetupWizard(); process.exit(0); } } else if (mode === 'direct') { console.log(chalk.green('\nāœ… Direct command mode enabled!')); console.log(chalk.blue('šŸ’” Use commands like: sshbridge exec user@server "ls -la"')); console.log(chalk.blue('šŸ’” Use "sshbridge --help" to see all commands')); console.log(chalk.blue('šŸ’” Use "sshbridge --change-mode" to change later\n')); } } // Interactive setup wizard async function startSetupWizard() { console.log(chalk.cyan('\nšŸŽÆ SSHBridge Setup Wizard\n')); console.log(chalk.gray('This wizard will help you get started with SSHBridge step by step.\n')); const { action } = await inquirer.prompt([ { type: 'list', name: 'action', message: 'What would you like to do?', choices: [ { name: 'šŸ”‘ Generate SSH Key', value: 'keygen', description: 'Create a new SSH key pair for secure connections' }, { name: 'šŸ“ Create Configuration', value: 'config', description: 'Set up server configurations for easy access' }, { name: 'šŸ” Register Account', value: 'register', description: 'Create account for advanced features and AI assistance' }, { name: 'šŸš€ Quick Start', value: 'quick', description: 'Complete setup with recommended defaults' }, { name: 'āŒ Skip Setup', value: 'skip', description: 'Exit setup and use SSHBridge directly' } ] } ]); switch (action) { case 'keygen': await setupSSHKey(); break; case 'config': await setupConfiguration(); break; case 'register': await setupRegistration(); break; case 'quick': await quickStartSetup(); break; case 'skip': console.log(chalk.blue('\nšŸ’” Setup skipped. You can run "sshbridge setup" anytime.\n')); break; } } // SSH Key setup async function setupSSHKey() { console.log(chalk.cyan('\nšŸ”‘ SSH Key Setup\n')); const { email } = await inquirer.prompt([ { type: 'input', name: 'email', message: 'Enter your email address:', validate: (input) => input.includes('@') || 'Please enter a valid email' } ]); // Check user's tier status console.log(chalk.blue('šŸ’” Email is used for unlocking pro tier plan features')); console.log(chalk.gray(' Free tier: 5 servers, 50 commands/month')); console.log(chalk.gray(' Pro tier: unlimited servers and commands')); // Show current tier status try { const { APIClient } = require('./api'); const api = new APIClient(); const userStatus = await api.getUserStatus(email); if (userStatus.tier === 'pro') { console.log(chalk.green(`āœ… You are currently on the Pro tier!`)); console.log(chalk.green(` Unlimited servers and commands available`)); } else { console.log(chalk.yellow(`šŸ“Š You are currently on the Free tier`)); console.log(chalk.yellow(` ${userStatus.serversUsed || 0}/5 servers, ${userStatus.commandsUsed || 0}/50 commands used this month`)); console.log(chalk.blue(` Upgrade to Pro for unlimited usage`)); } } catch (error) { console.log(chalk.gray(`šŸ“Š Checking tier status... (Free tier by default)`)); } const { keyType } = await inquirer.prompt([ { type: 'list', name: 'keyType', message: 'Choose key type:', choices: [ { name: 'ED25519 (Recommended)', value: 'ed25519', description: 'Most secure, fastest' }, { name: 'RSA 4096', value: 'rsa', description: 'Widely compatible' }, { name: 'ECDSA', value: 'ecdsa', description: 'Good balance of security and speed' } ], default: 'ed25519' } ]); const { usePassphrase } = await inquirer.prompt([ { type: 'confirm', name: 'usePassphrase', message: 'Would you like to encrypt your key with a passphrase?', default: true } ]); // Check if key already exists before asking about force overwrite const { SSHKeyManager } = require('./ssh-key-manager'); const keyManager = new SSHKeyManager(); const defaultKeyPath = path.join(keyManager.sshDir, `id_${keyType}`); let forceOverwrite = false; if (require('fs').existsSync(defaultKeyPath)) { const { overwrite } = await inquirer.prompt([ { type: 'confirm', name: 'overwrite', message: `A key already exists at ${defaultKeyPath}. Would you like to overwrite it?`, default: false } ]); forceOverwrite = overwrite; } console.log(chalk.blue('\nšŸ”§ Generating your SSH key...')); try { const result = await keyManager.generateKey({ type: keyType, email: email, passphrase: usePassphrase ? undefined : '', // Will prompt interactively force: forceOverwrite }); console.log(chalk.green('\nāœ… SSH key generated successfully!')); console.log(chalk.blue('šŸ“ Private key:'), result.privateKeyPath); console.log(chalk.blue('šŸ“ Public key:'), result.publicKeyPath); // Offer to copy key to a server const { copyToServer } = await inquirer.prompt([ { type: 'confirm', name: 'copyToServer', message: 'Would you like to copy this key to a server now?', default: true } ]); if (copyToServer) { await setupKeyCopy(result.publicKeyPath); } } catch (error) { console.error(chalk.red(`āŒ Key generation failed: ${error.message}`)); } } // Key copy setup async function setupKeyCopy(keyPath) { console.log(chalk.cyan('\nšŸ“¤ Copy Key to Server\n')); const { server } = await inquirer.prompt([ { type: 'input', name: 'server', message: 'Enter server (user@hostname):', validate: (input) => input.includes('@') || 'Please enter format: user@hostname' } ]); const { authMethod } = await inquirer.prompt([ { type: 'list', name: 'authMethod', message: 'How will you authenticate to copy the key?', choices: [ { name: 'Password', value: 'password', description: 'Enter server password' }, { name: 'Existing SSH Key', value: 'key', description: 'Use another SSH key' } ] } ]); console.log(chalk.blue('\nšŸ”§ Copying key to server...')); try { const { SSHKeyManager } = require('./ssh-key-manager'); const keyManager = new SSHKeyManager(); const options = {}; if (authMethod === 'password') { const { password } = await inquirer.prompt([ { type: 'password', name: 'password', message: 'Enter server password:', mask: '*' } ]); options.password = password; } else { const { existingKey } = await inquirer.prompt([ { type: 'input', name: 'existingKey', message: 'Path to existing SSH key:', default: '~/.ssh/id_rsa' } ]); options.key = existingKey; } await keyManager.copyKeyToServer(server, options); console.log(chalk.green('\nāœ… Key copied successfully!')); console.log(chalk.blue('šŸ’” You can now connect without passwords')); } catch (error) { console.error(chalk.red(`āŒ Key copy failed: ${error.message}`)); } } // Configuration setup async function setupConfiguration() { console.log(chalk.cyan('\nšŸ“ Configuration Setup\n')); const { configType } = await inquirer.prompt([ { type: 'list', name: 'configType', message: 'Choose configuration format:', choices: [ { name: 'JSON (Recommended)', value: 'json', description: 'Easy to read and edit' }, { name: 'YAML', value: 'yaml', description: 'Human-readable format' }, { name: 'TOML', value: 'toml', description: 'Simple configuration format' } ], default: 'json' } ]); console.log(chalk.blue('\nšŸ”§ Creating configuration file...')); try { const { SSHCredentialsManager } = require('./credentials'); const credManager = new SSHCredentialsManager(); const examples = credManager.generateExampleConfigs(); const fileName = `sshbridge.${configType}`; const fs = require('fs-extra'); if (await fs.pathExists(fileName)) { const { overwrite } = await inquirer.prompt([ { type: 'confirm', name: 'overwrite', message: `${fileName} already exists. Overwrite?`, default: false } ]); if (!overwrite) return; } await fs.writeFile(fileName, examples[fileName]); console.log(chalk.green(`\nāœ… Configuration file created: ${fileName}`)); console.log(chalk.blue('šŸ’” Edit this file with your server details')); console.log(chalk.blue('šŸ’” Then use: sshbridge run server-name "command"')); // Show preview console.log(chalk.gray('\nšŸ“‹ Preview:')); console.log(examples[fileName]); } catch (error) { console.error(chalk.red(`āŒ Configuration creation failed: ${error.message}`)); } } // Registration setup async function setupRegistration() { console.log(chalk.cyan('\nšŸ” Account Registration\n')); const { email } = await inquirer.prompt([ { type: 'input', name: 'email', message: 'Enter your email address:', validate: (input) => input.includes('@') || 'Please enter a valid email' } ]); console.log(chalk.blue('\nšŸ”§ Creating your account...')); try { const result = await getAPI().register(email); if (result.needsVerification) { console.log(chalk.yellow('\nšŸ“§ Account created! Email verification required.')); if (result.verification_code) { console.log(chalk.cyan('šŸ”‘ Verification code:'), result.verification_code); } const { code } = await inquirer.prompt([ { type: 'input', name: 'code', message: 'Enter your 6-digit verification code:', validate: (input) => input.length === 6 && /^\d+$/.test(input) || 'Please enter a 6-digit code' } ]); const verifyResult = await getAPI().verifyEmail(email, code); console.log(chalk.green('\nāœ… Email verified successfully!')); console.log(chalk.blue('šŸŽÆ Free tier: 50 commands/month')); } else { console.log(chalk.green('\nāœ… Account created successfully!')); console.log(chalk.blue('šŸŽÆ Free tier: 50 commands/month')); } } catch (error) { console.error(chalk.red(`āŒ Registration failed: ${error.message}`)); } } // Quick start setup async function quickStartSetup() { console.log(chalk.cyan('\nšŸš€ Quick Start Setup\n')); console.log(chalk.blue('This will set up everything with recommended defaults.\n')); try { // 1. Generate SSH key console.log(chalk.blue('1ļøāƒ£ Generating SSH key...')); const { SSHKeyManager } = require('./ssh-key-manager'); const keyManager = new SSHKeyManager(); const keyResult = await keyManager.generateKey({ type: 'ed25519', email: 'your@email.com', // Will prompt interactively passphrase: undefined, // Will prompt interactively force: false }); console.log(chalk.green('āœ… SSH key generated')); // 2. Create configuration console.log(chalk.blue('\n2ļøāƒ£ Creating configuration...')); const { SSHCredentialsManager } = require('./credentials'); const credManager = new SSHCredentialsManager(); const examples = credManager.generateExampleConfigs(); const fs = require('fs-extra'); await fs.writeFile('sshbridge.json', examples['sshbridge.json']); console.log(chalk.green('āœ… Configuration created')); // 3. Register account console.log(chalk.blue('\n3ļøāƒ£ Setting up account...')); console.log(chalk.yellow('šŸ’” You can register later with: sshbridge register')); console.log(chalk.green('\nšŸŽ‰ Quick start setup complete!')); console.log(chalk.blue('šŸ’” Next steps:')); console.log(chalk.white(' 1. Edit sshbridge.json with your server details')); console.log(chalk.white(' 2. Use: sshbridge run server-name "command"')); console.log(chalk.white(' 3. Or: sshbridge exec user@server "command" --direct')); } catch (error) { console.error(chalk.red(`āŒ Quick start failed: ${error.message}`)); } } // Environment variable validation function validateEnvironment() { const issues = []; // Check for optional but recommended variables if (!process.env.SSHBRIDGE_LOG_LEVEL) { // Log level not set - using defaults } // Don't warn about missing API URL since we have a working fallback // if (!process.env.SSHBRIDGE_API_URL) { // console.log(chalk.blue('šŸ’” Tip: Set SSHBRIDGE_API_URL for custom backend')); // } if (issues.length > 0) { console.log(chalk.yellow('āš ļø Environment Configuration:')); issues.forEach(issue => console.log(chalk.yellow(` ${issue}`))); console.log(chalk.blue('šŸ’” For full features, set recommended environment variables\n')); } } // Lazy initialization functions function getAPI() { if (!api) { // API will use constants file fallback URL if environment variable not set api = new APIClient(); } return api; } function getConfig() { if (!config) { config = new Config(); } return config; } function getUpdater() { if (!updater) { updater = new AutoUpdater(); } return updater; } function getIntegrityChecker() { if (!integrityChecker) { integrityChecker = new IntegrityChecker(); } return integrityChecker; } function getFeatureGate() { if (!featureGate) { featureGate = new FeatureGate(); } return featureGate; } program .name('sshbridge') .description('AI-Powered SSH Tool - Simple & Secure') .version(require('../package.json').version) .option('--change-mode', 'Change your preferred mode (interactive/direct)') .option('--help-all', 'Show all available commands (advanced users)') // Override the helpInformation method to show only essential commands program.helpInformation = function() { return chalk.cyan('\nSSHBridge\n') + chalk.gray('Simple, secure SSH connections\n\n') + chalk.white('šŸš€ Quick Start:\n') + ' setup Set up your first connection\n' + ' connect Connect to a server\n' + ' run Execute commands\n\n' + chalk.white('šŸ”’ Security:\n') + ' keygen Create secure keys\n' + ' copy-key Deploy keys to servers\n\n' + chalk.white('šŸ‘¤ Account:\n') + ' register Create account\n' + ' update Stay updated\n\n' + chalk.gray('All commands: ') + 'sshbridge help-all\n' + chalk.gray('Command help: ') + 'sshbridge <command> --help\n\n' + chalk.yellow('šŸ’” Tip: Always start commands with "sshbridge" (e.g., sshbridge setup)'); }; // Override the default help command to show only essential commands program .command('help') .description('Show help for commands') .argument('[command]', 'Command to show help for') .action((command) => { if (command) { // Show help for specific command const cmd = program.commands.find(c => c.name() === command); if (cmd) { cmd.help(); } else { console.log(chalk.red(`āŒ Unknown command: ${command}`)); console.log(chalk.blue('šŸ’” Use "sshbridge --help" to see available commands')); } } else { // Show simplified help with only essential commands console.log(chalk.cyan('\nSSHBridge\n')); console.log(chalk.gray('Simple, secure SSH connections\n\n')); console.log(chalk.white('šŸš€ Quick Start:\n')); console.log(' setup Set up your first connection'); console.log(' connect Connect to a server'); console.log(' run Execute commands\n'); console.log(chalk.white('šŸ”’ Security:\n')); console.log(' keygen Create secure keys'); console.log(' copy-key Deploy keys to servers\n'); console.log(chalk.white('šŸ‘¤ Account:\n')); console.log(' register Create account'); console.log(' update Stay updated\n'); console.log(chalk.gray('All commands: sshbridge help-all')); console.log(chalk.yellow('\nšŸ’” Tip: Always start commands with "sshbridge" (e.g., sshbridge setup)')); } }); // Add a custom help-all command that shows all commands program .command('help-all') .description('Show all available commands (advanced users)') .action(() => { console.log(chalk.cyan('\nSSHBridge - All Commands\n')); console.log(chalk.gray('For beginners, use: sshbridge help-simple\n')); console.log(chalk.white('Connection & Execution:\n')); const connectionCommands = [ { name: 'setup', desc: 'Interactive setup wizard' }, { name: 'connect', desc: 'Connect to a server' }, { name: 'exec', desc: 'Execute single command' }, { name: 'run', desc: 'Run command on configured host' }, { name: 'session', desc: 'Interactive session' }, { name: 'copy', desc: 'Transfer files' } ]; connectionCommands.forEach(cmd => { console.log(` ${chalk.blue(cmd.name.padEnd(15))} ${cmd.desc}`); }); console.log(chalk.white('\nSecurity & Keys:\n')); const securityCommands = [ { name: 'keygen', desc: 'Generate SSH keys' }, { name: 'copy-key', desc: 'Deploy keys to servers' }, { name: 'keys', desc: 'Manage your keys' }, { name: 'security', desc: 'Security status' } ]; securityCommands.forEach(cmd => { console.log(` ${chalk.blue(cmd.name.padEnd(15))} ${cmd.desc}`); }); console.log(chalk.white('\nConfiguration:\n')); const configCommands = [ { name: 'config', desc: 'Manage configurations' }, { name: 'servers', desc: 'Manage server list' }, { name: 'change-mode', desc: 'Switch between modes' } ]; configCommands.forEach(cmd => { console.log(` ${chalk.blue(cmd.name.padEnd(15))} ${cmd.desc}`); }); console.log(chalk.white('\nAccount & Updates:\n')); const accountCommands = [ { name: 'register', desc: 'Create account' }, { name: 'verify', desc: 'Verify email' }, { name: 'update', desc: 'Check for updates' }, { name: 'usage', desc: 'View usage stats' } ]; accountCommands.forEach(cmd => { console.log(` ${chalk.blue(cmd.name.padEnd(15))} ${cmd.desc}`); }); console.log(chalk.white('\nHelp & Troubleshooting:\n')); const helpCommands = [ { name: 'help-simple', desc: 'Beginner help' }, { name: 'examples', desc: 'Usage examples' }, { name: 'troubleshoot', desc: 'Common issues' }, { name: 'install-help', desc: 'Installation help' } ]; helpCommands.forEach(cmd => { console.log(` ${chalk.blue(cmd.name.padEnd(15))} ${cmd.desc}`); }); console.log(chalk.gray('\nFor simple help: sshbridge help-simple')); }); // Custom help command for simplified view program .command('help-simple') .alias('hs') .description('Show simplified help (beginner friendly)') .action(() => { console.log(chalk.cyan('\nSSHBridge\n')); console.log(chalk.gray('Simple, secure SSH connections\n\n')); console.log(chalk.white('šŸš€ Quick Start:\n')); console.log(' sshbridge setup # First-time setup'); console.log(' sshbridge connect # Connect to a server'); console.log(' sshbridge run # Execute commands\n'); console.log(chalk.white('šŸ”’ Security:\n')); console.log(' sshbridge keygen # Create secure keys'); console.log(' sshbridge copy-key # Deploy keys to servers\n'); console.log(chalk.white('šŸ‘¤ Account:\n')); console.log(' sshbridge register # Create account'); console.log(' sshbridge update # Stay updated\n'); console.log(chalk.gray('\nNeed more? sshbridge help-all')); console.log(chalk.yellow('\nšŸ’” Tip: Always start commands with "sshbridge" (e.g., sshbridge setup)')); }); // Command to list all available commands program .command('list-all') .alias('la') .description('Show all available commands (advanced users)') .action(() => { console.log(chalk.cyan('\nšŸ“‹ SSHBridge - All Commands (Advanced Users)\n')); console.log(chalk.yellow('āš ļø This shows all 30+ commands. For beginners, use: sshbridge help-simple\n')); const allCommands = [ { name: 'setup', desc: 'Interactive setup wizard for new users' }, { name: 'interactive|i', desc: 'Enter interactive mode for guided SSH operations' }, { name: 'change-mode', desc: 'Change your preferred SSHBridge experience mode' }, { name: 'quick-start|qs', desc: 'Quick start guide for new users' }, { name: 'examples|ex', desc: 'Show usage examples' }, { name: 'register', desc: 'Register for a free account' }, { name: 'verify', desc: 'Verify your email address with SSHBridge' }, { name: 'exec', desc: 'Execute SSH command on remote server' }, { name: 'copy', desc: 'Copy files to/from remote server' }, { name: 'usage', desc: 'Check your current usage' }, { name: 'servers', desc: 'Manage your servers' }, { name: 'update|u', desc: 'Check for and install updates' }, { name: 'config', desc: 'Manage SSH configuration files' }, { name: 'keygen', desc: 'Generate SSH key pairs' }, { name: 'copy-key', desc: 'Copy SSH public key to remote server' }, { name: 'keys', desc: 'Manage SSH keys' }, { name: 'run', desc: 'Execute command on configured host (uses config file)' }, { name: 'session', desc: 'Start an interactive SSH session' }, { name: 'license|lic', desc: 'Manage SSHBridge license and features' }, { name: 'security|sec', desc: 'Show security and integrity status' }, { name: 'install-help', desc: 'Show installation troubleshooting' }, { name: 'sandbox', desc: 'Show sandbox status and statistics' }, { name: 'troubleshoot|ts', desc: 'Troubleshooting guide for common issues' }, { name: 'rollback|rb', desc: 'Rollback to previous version' }, { name: 'upgrade', desc: 'Quick upgrade (same as update)' }, { name: 'clear-passwords', desc: 'Clear cached SSH passwords' }, { name: 'help-simple|hs', desc: 'Show simplified help (beginner friendly)' }, { name: 'list-all|la', desc: 'Show all available commands (advanced users)' } ]; allCommands.forEach(cmd => { console.log(` ${chalk.blue(cmd.name.padEnd(20))} ${cmd.desc}`); }); console.log(chalk.gray('\nšŸ’” Simple help: sshbridge help-simple')); console.log(chalk.gray('šŸ’” Command help: sshbridge <command> --help')); }); // Installation help command // License management command program .command('license') .alias('lic') .description('Manage SSHBridge license and features') .option('-s, --status', 'Show license status') .option('-f, --features', 'Show available features') .option('-u, --upgrade', 'Show upgrade information') .action(async (options) => { const featureGate = getFeatureGate(); if (options.status) { const status = featureGate.getLicenseStatus(); console.log(chalk.cyan('\nšŸ”‘ SSHBridge License Status\n')); console.log(chalk.yellow('šŸ“‹ License Information:')); console.log(` Tier: ${chalk.green(status.tier)}`); console.log(` Status: ${chalk.green(status.status)}`); if (status.customerId) { console.log(` Customer ID: ${chalk.green(status.customerId)}`); console.log(` Issued: ${chalk.green(new Date(status.issuedAt).toLocaleDateString())}`); if (status.expiresAt) { console.log(` Expires: ${chalk.green(new Date(status.expiresAt).toLocaleDateString())}`); } } console.log(chalk.yellow('\nšŸ“Š Usage Quota:')); console.log(` Commands Used: ${chalk.blue(status.quota.commands)}`); console.log(` Commands Limit: ${chalk.blue(status.quota.maxCommands)}`); if (status.quota.resetDate) { console.log(` Resets: ${chalk.blue(new Date(status.quota.resetDate).toLocaleDateString())}`); } console.log(chalk.yellow('\nšŸš€ Available Features:')); status.features.forEach(feature => { const statusIcon = feature.enabled ? 'āœ…' : 'āŒ'; console.log(` ${statusIcon} ${chalk.green(feature.name)}: ${feature.description}`); }); } else if (options.features) { const features = featureGate.getAvailableFeatures(); console.log(chalk.cyan('\nšŸš€ Available Features\n')); features.forEach(feature => { console.log(`āœ… ${chalk.green(feature.name)}: ${feature.description}`); }); } else if (options.upgrade) { const upgradeInfo = featureGate.getUpgradeInfo(); if (!upgradeInfo) { console.log(chalk.green('\nšŸŽ‰ You already have the highest tier!')); return; } console.log(chalk.cyan('\nšŸš€ Upgrade Information\n')); console.log(chalk.yellow(`Current Tier: ${chalk.blue(upgradeInfo.currentTier)}`)); console.log(chalk.yellow(`Upgrade To: ${chalk.green(upgradeInfo.nextTier)}`)); const pricing = upgradeInfo.pricing; console.log(chalk.yellow('\nšŸ’° Pricing:')); console.log(` Monthly: $${chalk.green(pricing.monthly)}`); console.log(` Yearly: $${chalk.green(pricing.yearly)} (Save 17%)`); console.log(chalk.yellow('\nšŸš€ New Features:')); upgradeInfo.features.forEach(feature => { console.log(` āœ… ${chalk.green(feature.name)}: ${feature.description}`); }); } else { // Show help for license command console.log(chalk.cyan('\nšŸ”‘ SSHBridge License Management\n')); console.log(chalk.yellow('Available Options:')); console.log(' --status, -s Show license status and features'); console.log(' --features, -f Show available features'); console.log(' --upgrade, -u Show upgrade information'); console.log('\nExamples:'); console.log(' sshbridge license --status'); console.log(' sshbridge license --features'); console.log(' sshbridge license --upgrade'); } }); // Security status command program .command('security') .alias('sec') .description('Show security and integrity status') .action(() => { const integrityChecker = getIntegrityChecker(); const featureGate = getFeatureGate(); console.log(chalk.cyan('\nšŸ”’ SSHBridge Security Status\n')); // Integrity checker status const integrityStatus = integrityChecker.getSecurityStatus(); console.log(chalk.yellow('šŸ›”ļø Integrity Protection:')); console.log(` Status: ${chalk.green('Active')}`); console.log(` Checks Performed: ${chalk.blue(integrityStatus.integrityChecks)}`); console.log(` Last Check: ${chalk.blue(new Date(integrityStatus.lastCheck).toLocaleTimeString())}`); console.log(` Checksums Verified: ${chalk.green(integrityStatus.checksumsVerified ? 'Yes' : 'No')}`); // Feature gate status const licenseStatus = featureGate.getLicenseStatus(); console.log(chalk.yellow('\nšŸ”‘ License Security:')); console.log(` Tier: ${chalk.green(licenseStatus.tier)}`); console.log(` Status: ${chalk.green(licenseStatus.status)}`); if (licenseStatus.tier === 'free') { console.log(chalk.blue('\nšŸ’” Upgrade to Pro or Enterprise for advanced security features')); } console.log(chalk.yellow('\n🚨 Security Features:')); console.log(' āœ… Code integrity verification'); console.log(' āœ… Runtime tampering detection'); console.log(' āœ… Performance monitoring'); if (licenseStatus.tier !== 'free') { console.log(' āœ… Advanced security features'); console.log(' āœ… Enterprise integrations'); console.log(' āœ… Audit logging'); } }); // Installation help command program .command('install-help') .description('Show installation troubleshooting') .action(() => { console.log(chalk.cyan('\nšŸ”§ SSHBridge Installation Help\n')); console.log(chalk.yellow('šŸ“¦ Installation Command:')); console.log(chalk.green('sudo npm install -g ssh-bridge-ai\n')); console.log(chalk.yellow('ā“ Why sudo?')); console.log('• Global npm packages need admin permissions'); console.log('• This installs to /usr/local/lib/node_modules/'); console.log('• Same requirement as other CLI tools\n'); console.log(chalk.yellow('🚨 Permission Error (EACCES)?')); console.log('• Run: ' + chalk.green('sudo npm install -g ssh-bridge-ai')); console.log('• Enter your macOS/Linux password when prompted'); console.log('• This is normal and safe for npm global installs\n'); console.log(chalk.yellow('🪟 Windows Users:')); console.log('• Run Command Prompt as Administrator'); console.log('• Then: ' + chalk.green('npm install -g ssh-bridge-ai')); console.log('• No sudo needed on Windows\n'); console.log(chalk.yellow('āœ… After Installation:')); console.log('• Run: ' + chalk.green('sshbridge register --email your@email.com')); console.log('• Get 50 free commands per month'); console.log('• Start automating with AI!\n'); console.log(chalk.gray('šŸ’” Still having issues? Create an issue:')); console.log(chalk.blue('https://github.com/A12-AA/sshbridge/issues')); }); // Setup wizard command program .command('setup') .description('Interactive setup wizard for new users') .action(async () => { await startSetupWizard(); }); // Interactive mode command program .command('interactive') .alias('i') .description('Enter interactive mode for guided SSH operations') .action(async () => { console.log(chalk.cyan('\nšŸŽÆ SSHBridge Interactive Mode\n')); console.log(chalk.blue('Welcome to guided SSH operations!\n')); const { action } = await inquirer.prompt([ { type: 'list', name: 'action', message: 'What would you like to do?', choices: [ { name: 'šŸ”‘ Manage SSH Keys', value: 'keys', description: 'Generate, copy, and manage SSH keys' }, { name: 'šŸ–„ļø Connect to Server', value: 'connect', description: 'Connect to a server with guided setup' }, { name: 'šŸ“ Manage Configurations', value: 'config', description: 'Create and edit server configurations' }, { name: 'šŸ” Account Management', value: 'account', description: 'Register, verify, and manage your account' }, { name: 'āŒ Exit Interactive Mode', value: 'exit', description: 'Return to command line' } ] } ]); switch (action) { case 'keys': await interactiveKeyManagement(); break; case 'connect': await interactiveConnection(); break; case 'config': await interactiveConfigManagement(); break; case 'account': await interactiveAccountManagement(); break; case 'exit': console.log(chalk.blue('\nšŸ‘‹ Exiting interactive mode. Use "sshbridge interactive" to return.\n')); break; } }); // Change mode command program .command('change-mode') .description('Change your preferred SSHBridge experience mode') .action(async () => { console.log(chalk.cyan('\nšŸ”„ Change SSHBridge Experience Mode\n')); const userConfig = getConfig(); const currentMode = userConfig.getPreferredMode() || 'interactive'; console.log(chalk.blue(`Current mode: ${currentMode === 'interactive' ? 'šŸŽÆ Interactive' : '⚔ Direct Commands'}\n`)); const { mode } = await inquirer.prompt([ { type: 'list', name: 'mode', message: 'How would you like to use SSHBridge?', choices: [ { name: 'šŸŽÆ Interactive Mode (Beginner Friendly)', value: 'interactive', description: 'Step-by-step guidance, menus, and smart defaults' }, { name: '⚔ Direct Commands (Power User)', value: 'direct', description: 'Traditional CLI commands with enhanced security' } ], default: currentMode } ]); userConfig.setPreferredMode(mode); if (mode === 'interactive') { console.log(chalk.green('\nāœ… Interactive mode enabled!')); console.log(chalk.blue('šŸ’” Use "sshbridge interactive" to enter guided mode')); console.log(chalk.blue('šŸ’” Use "sshbridge setup" for initial setup')); } else { console.log(chalk.green('\nāœ… Direct command mode enabled!')); console.log(chalk.blue('šŸ’” Use commands like: sshbridge exec user@server "ls -la"')); console.log(chalk.blue('šŸ’” Use "sshbridge --help" to see all commands')); } console.log(chalk.blue('\nšŸ’” Your preference has been saved and will be used automatically')); }); // Quick start command program .command('quick-start') .alias('qs') .description('Quick start guide for new users') .action(() => { console.log(chalk.cyan('\nšŸš€ SSHBridge Quick Start Guide\n')); console.log(chalk.blue('šŸ’” For interactive setup, use: sshbridge setup\n')); console.log(chalk.yellow('1ļøāƒ£ SSH Key Setup (Recommended):')); console.log(chalk.white(' sshbridge keygen --type ed25519 --email "your@email.com"')); console.log(chalk.gray(' šŸ’” Will prompt for secure passphrase with verification')); console.log(chalk.white(' sshbridge copy-key user@server')); console.log(chalk.white(' sshbridge keys list')); console.log(chalk.gray(' šŸ’” Keys provide secure, passwordless access\n')); console.log(chalk.yellow('2ļøāƒ£ Direct SSH (No Registration Required):')); console.log(chalk.white(' sshbridge exec user@hostname "ls -la" --direct')); console.log(chalk.white(' sshbridge exec user@hostname "whoami" --ask-pass')); console.log(chalk.gray(' šŸ’” Use --direct for immediate SSH access\n')); console.log(chalk.yellow('3ļøāƒ£ Create Configuration File:')); console.log(chalk.white(' sshbridge config --create json')); console.log(chalk.white(' # Edit sshbridge.json with your servers\n')); console.log(chalk.yellow('4ļøāƒ£ Use Configuration:')); console.log(chalk.white(' sshbridge run server-name "command"')); console.log(chalk.white(' sshbridge run server-name "command" --direct\n')); console.log(chalk.yellow('5ļøāƒ£ Register for AI Features (Optional):')); console.log(chalk.white(' sshbridge register --email your@email.com')); console.log(chalk.gray(' šŸ’” Get 50 free AI-powered commands per month\n')); console.log(chalk.blue('šŸ“š More help: sshbridge --help')); console.log(chalk.blue('šŸ”§ Config help: sshbridge config --help')); console.log(chalk.blue('šŸ”‘ Key help: sshbridge keygen --help')); }); // Examples command program .command('examples') .alias('ex') .description('Show usage examples') .action(() => { console.log(chalk.cyan('\nšŸ“š Usage Examples (Simple & Professional)\n')); console.log(chalk.yellow('šŸ”‘ SSH Key Management:')); console.log(chalk.white(' # Generate new key (interactive passphrase)')); console.log(chalk.gray(' sshbridge keygen --type ed25519 --email "your@email.com"')); console.log(chalk.white(' # Generate RSA key with custom bits')); console.log(chalk.gray(' sshbridge keygen --type rsa --bits 4096 --force')); console.log(chalk.white(' # Deploy key to server')); console.log(chalk.gray(' sshbridge copy-key user@server')); console.log(chalk.gray(' sshbridge copy-key server-name --key ~/.ssh/id_ed25519')); console.log(chalk.white(' # List and manage keys')); console.log(chalk.gray(' sshbridge keys list')); console.log(chalk.gray(' sshbridge keys fingerprint ~/.ssh/id_ed25519\n')); console.log(chalk.yellow('šŸ” Direct SSH Connections:')); console.log(chalk.white(' # Basic command execution')); console.log(chalk.gray(' sshbridge exec user@server "ls -la" --direct')); console.log(chalk.gray(' sshbridge exec admin@prod "uptime" --key ~/.ssh/id_rsa')); console.log(chalk.gray(' sshbridge exec user@host "df -h" --ask-pass')); console.log(chalk.gray(' sshbridge exec user@host "ls -la" --key ~/.ssh/id_ed25519 --ask-key-pass\n')); console.log(chalk.yellow('šŸ“ Configuration-Based Usage:')); console.log(chalk.white(' # Create config file')); console.log(chalk.gray(' sshbridge config --create json')); console.log(chalk.white(' # Use with config')); console.log(chalk.gray(' sshbridge run prod-server "docker ps"')); console.log(chalk.gray(' sshbridge run staging "git pull" --direct\n')); console.log(chalk.yellow('šŸ”§ Configuration Management:')); console.log(chalk.white(' # List configured hosts')); console.log(chalk.gray(' sshbridge config --list sshbridge.json')); console.log(chalk.white(' # Test config file')); console.log(chalk.gray(' sshbridge config --test myconfig.yaml')); console.log(chalk.white(' # Show config locations')); console.log(chalk.gray(' sshbridge config --show-path\n')); console.log(chalk.yellow('šŸ“Š Account Management:')); console.log(chalk.white(' # Check usage')); console.log(chalk.gray(' sshbridge usage')); console.log(chalk.white(' # List servers')); console.log(chalk.gray(' sshbridge servers list')); console.log(chalk.white(' # Update tool')); console.log(chalk.gray(' sshbridge update\n')); console.log(chalk.blue('šŸ’” For more help: sshbridge <command> --help')); }); // Sandbox status command program .command('sandbox') .description('Show sandbox status and statistics') .option('--stats', 'Show detailed statistics') .option('--clear', 'Clear sandbox execution history') .action(async (options) => { try { if (options.clear) { // This would clear sandbox history if we had direct access console.log(chalk.blue('šŸ—‘ļø Sandbox history cleared')); return; } console.log(chalk.cyan('\nšŸ”’ SSHBridge Sandbox Status\n')); if (options.stats) { console.log(chalk.yellow('šŸ“Š Sandbox Statistics:')); console.log(chalk.white(' Status: Enabled (default)')); console.log(chalk.white(' Mode: Docker containers (with local fallback)')); console.log(chalk.white(' Image: ubuntu:22.04')); console.log(chalk.white(' Timeout: 30 seconds')); console.log(chalk.white(' Memory limit: 512MB per container')); console.log(chalk.white(' Disk limit: 100MB per container\n')); console.log(chalk.yellow('šŸ›”ļø Safety Features:')); console.log(chalk.white(' • All commands tested in sandbox first')); console.log(chalk.white(' • Dangerous patterns automatically blocked')); console.log(chalk.white(' • Command output size limits')); console.log(chalk.white(' • Automatic cleanup after execution\n')); console.log(chalk.yellow('šŸ”§ Usage Examples:')); console.log(chalk.white(' # Test command in sandbox only')); console.log(chalk.gray(' sshbridge exec user@host "ls -la" --dry-run')); console.log(chalk.white(' # Always require confirmation (default)')); console.log(chalk.gray(' sshbridge exec user@host "command" --confirm')); console.log(chalk.white(' # Skip confirmation (dangerous!)')); console.log(chalk.gray(' sshbridge exec user@host "command" --auto-approve')); console.log(chalk.white(' # Disable sandbox (not recommended)')); console.log(chalk.gray(' sshbridge exec user@host "command" --no-sandbox')); console.log(chalk.white(' # Use custom sandbox image')); console.log(chalk.gray(' sshbridge exec user@host "command" --sandbox-image centos:8\n')); } else { console.log(chalk.green('āœ… Sandbox mode is enabled by default')); console.log(chalk.white('All commands are tested in isolated containers before execution')); console.log(chalk.blue('šŸ’” Use --stats for detailed information')); console.log(chalk.blue('šŸ’” Use --dry-run to test commands safely')); } } catch (error) { console.error(chalk.red(`āŒ Error: ${error.message}`)); process.exit(1); } }); // Troubleshoot command program .command('troubleshoot') .alias('ts') .description('Troubleshooting guide for common issues') .action(() => { console.log(chalk.cyan('\nšŸ”§ SSHBridge Troubleshooting Guide\n')); console.log(chalk.yellow('āŒ "Not authenticated" Error:')); console.log(chalk.white(' Solution: Use --direct flag for direct SSH')); console.log(chalk.gray(' sshbridge exec user@host "command" --direct')); console.log(chalk.gray(' Or register: sshbridge register --email your@email.com\n')); console.log(chalk.yellow('āŒ "Host not found in config" Error:')); console.log(chalk.white(' Solution: Create or check your config file')); console.log(chalk.gray(' sshbridge config --create json')); console.log(chalk.gray(' sshbridge config --list sshbridge.json\n')); console.log(chalk.yellow('āŒ "Authentication failed" Error:')); console.log(chalk.white(' Solution: Check credentials or use --ask-pass')); console.log(chalk.gray(' sshbridge exec user@host "command" --ask-pass')); console.log(chalk.gray(' Or specify key: --key ~/.ssh/id_rsa\n')); console.log(chalk.yellow('āŒ "Config file not found" Error:')); console.log(chalk.white(' Solution: Check file location or create new one')); console.log(chalk.gray(' sshbridge config --show-path')); console.log(chalk.gray(' sshbridge config --create json\n')); console.log(chalk.yellow('āŒ "Permission denied" Error:')); console.log(chalk.white(' Solution: Check SSH key permissions')); console.log(chalk.gray(' chmod 600 ~/.ssh/id_rsa')); console.log(chalk.gray(' Or use password: --ask-pass\n')); console.log(chalk.yellow('āŒ "SSH key not found" Error:')); console.log(chalk.white(' Solution: Generate new SSH key')); console.log(chalk.gray(' sshbridge keygen --type ed25519')); console.log(chalk.gray(' sshbridge copy-key user@server\n')); console.log(chalk.yellow('āŒ "Key copy failed" Error:')); console.log(chalk.white(' Solution: Check server connectivity and permissions')); console.log(chalk.gray(' sshbridge copy-key user@server --key ~/.ssh/id_ed25519')); console.log(chalk.gray(' Or manually: ssh-copy-id -i ~/.ssh/id_ed25519 user@server\n')); console.log(chalk.blue('šŸ“š More help: sshbridge quick-start')); console.log(chalk.blue('šŸ”§ Config help: sshbridge config --help')); }); // Register command program .command('register') .description('Register for a free account') .option('-e, --email <email>', 'Your email address') .action(async (options) => { try { const spinner = ora('Creating account...').start(); let email = options.email; if (!email) { const answers = await inquirer.prompt([ { type: 'input', name: 'email', message: 'Enter your email:', validate: (input) => input.includes('@') || 'Please enter a valid email' } ]); email = answers.email; } const result = await getAPI().register(email); spinner.stop(); if (result.needsVerification) { console.log(chalk.yellow('šŸ“§ Account created! Email verification required.')); if (result.note) console.log(chalk.gray('Note:'), result.note); // Store the API key from registration (before verification) if (result.api_key) { getConfig().setApiKey(result.api_key); getConfig().setEmail(email); } // For testing - show the code if (result.verification_code) { console.log(chalk.cyan('šŸ”‘ Verification code:'), result.verification_code); } // Prompt for verification code const verifyAnswers = await inquirer.prompt([ { type: 'input', name: 'code', message: 'Enter your 6-digit verification code:', validate: (input) => { return input.length === 6 && /^\d+$/.test(input) || 'Please enter a 6-digit code'; } } ]); const verifySpinner = ora('Verifying email...').start(); try { const verifyResult = await getAPI().verifyEmail(email, verifyAnswers.code); verifySpinner.stop(); console.log(chalk.green('āœ” Email verified successfully!')); console.log(chalk.blue(`✨ Welcome to SSHBridge v1.1.0!`)); console.log(chalk.gray(`šŸ“§ Email: ${email}`)); console.log(chalk.gray(`šŸŽÆ Free tier: 50 commands/month`)); console.log(chalk.gray(`šŸ”— Homepage: https://dulcet-gecko-595d55.netlify.app`)); console.log(chalk.yellow(`\nšŸ’” Try: sshbridge exec user@server "ls -la"`)); } catch (verifyError) { verifySpinner.stop(); console.error(chalk.red('āœ— Verification failed:'),