UNPKG

ssh-bridge-ai

Version:

One Command Magic SSH with Invisible Analytics - Connect to any server instantly with 'sshbridge user@server'. Zero setup, zero friction, pure magic. Industry-standard security with behind-the-scenes business intelligence.

296 lines (259 loc) • 8.29 kB
const chalk = require('chalk'); const inquirer = require('inquirer'); const { ValidationUtils } = require('./validation'); const { ErrorHandler } = require('./errors'); const logger = require('./logger'); /** * CLI helper utilities for common operations */ class CLIHelpers { /** * Display installation help information */ static showInstallationHelp() { 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')); } /** * Prompt for email with validation * @param {string} defaultEmail - Default email if provided * @returns {Promise<string>} - Validated email */ static async promptForEmail(defaultEmail = null) { if (defaultEmail && ValidationUtils.validateEmail(defaultEmail)) { return defaultEmail; } const answers = await inquirer.prompt([ { type: 'input', name: 'email', message: 'Enter your email:', validate: (input) => { if (!input || !ValidationUtils.validateEmail(input)) { return 'Please enter a valid email address'; } return true; } } ]); return answers.email; } /** * Prompt for verification code * @returns {Promise<string>} - Verification code */ static async promptForVerificationCode() { const answers = await inquirer.prompt([ { type: 'input', name: 'code', message: 'Enter your 6-digit verification code:', validate: (input) => { if (!input || !/^\d{6}$/.test(input)) { return 'Please enter a valid 6-digit verification code'; } return true; } } ]); return answers.code; } /** * Prompt for connection string * @returns {Promise<string>} - Connection string */ static async promptForConnectionString() { const answers = await inquirer.prompt([ { type: 'input', name: 'connection', message: 'Enter SSH connection (user@host:port or user@host):', validate: (input) => { if (!input || !input.includes('@')) { return 'Please enter a valid connection string (user@host)'; } return true; } } ]); return answers.connection; } /** * Prompt for SSH key path * @returns {Promise<string>} - SSH key path */ static async promptForSSHKey() { const answers = await inquirer.prompt([ { type: 'input', name: 'keyPath', message: 'Enter path to your SSH private key (or press Enter for default):', default: '~/.ssh/id_rsa', validate: async (input) => { if (!input) return true; try { const isValid = await ValidationUtils.validateSSHKeyFile(input); if (!isValid) { return 'SSH key file is not secure or accessible. Please check permissions and ownership.'; } return true; } catch (error) { return 'Invalid SSH key path'; } } } ]); return answers.keyPath; } /** * Prompt for password (hidden input) * @returns {Promise<string>} - Password */ static async promptForPassword() { const answers = await inquirer.prompt([ { type: 'password', name: 'password', message: 'Enter your password:', mask: '*' } ]); return answers.password; } /** * Prompt for SSH key passphrase with verification challenge * @returns {Promise<string>} - Verified passphrase */ static async promptForSSHPassphrase() { let passphrase, verifyPassphrase; do { const answers = await inquirer.prompt([ { type: 'password', name: 'passphrase', message: 'šŸ” Enter your SSH key passphrase:', mask: '*', validate: (input) => { if (!input || input.trim().length === 0) { return 'Passphrase cannot be empty'; } if (input.length < 8) { return 'Passphrase must be at least 8 characters long'; } return true; } } ]); passphrase = answers.passphrase; const verifyAnswers = await inquirer.prompt([ { type: 'password', name: 'verifyPassphrase', message: 'šŸ” Verify your SSH key passphrase:', mask: '*' } ]); verifyPassphrase = verifyAnswers.verifyPassphrase; if (passphrase !== verifyPassphrase) { console.log(chalk.red('āŒ Passphrases do not match. Please try again.')); } } while (passphrase !== verifyPassphrase); console.log(chalk.green('āœ… Passphrase verified successfully!')); return passphrase; } /** * Display success message * @param {string} message - Success message * @param {Object} data - Optional data to display */ static showSuccess(message, data = null) { console.log(chalk.green(`āœ… ${message}`)); if (data) { console.log(chalk.gray(JSON.stringify(data, null, 2))); } } /** * Display error message * @param {string} message - Error message * @param {Error} error - Error object */ static showError(message, error = null) { console.log(chalk.red(`āŒ ${message}`)); if (error) { const sanitizedError = ErrorHandler.sanitizeError(error); console.log(chalk.gray(sanitizedError.message)); if (process.env.NODE_ENV === 'development') { console.log(chalk.gray('Stack trace:')); console.log(chalk.gray(sanitizedError.stack)); } } } /** * Display warning message * @param {string} message - Warning message */ static showWarning(message) { console.log(chalk.yellow(`āš ļø ${message}`)); } /** * Display info message * @param {string} message - Info message */ static showInfo(message) { console.log(chalk.blue(`ā„¹ļø ${message}`)); } /** * Confirm action with user * @param {string} message - Confirmation message * @param {boolean} defaultValue - Default value * @returns {Promise<boolean>} - User confirmation */ static async confirm(message, defaultValue = false) { const answers = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message, default: defaultValue } ]); return answers.confirmed; } /** * Select from options * @param {string} message - Selection message * @param {Array} choices - Available choices * @returns {Promise<string>} - Selected choice */ static async select(message, choices) { const answers = await inquirer.prompt([ { type: 'list', name: 'selected', message, choices } ]); return answers.selected; } } module.exports = { CLIHelpers };