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
JavaScript
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 };