UNPKG

@aerocorp/cli

Version:

AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps

320 lines (265 loc) • 10.9 kB
/** * AeroCorp CLI 4.0.0 - Security Management Service * SSL certificates, API tokens, and security monitoring */ import axios from 'axios'; import chalk from 'chalk'; import inquirer from 'inquirer'; import { ConfigService } from './config'; import { AuthService } from './auth'; export interface Certificate { id: string; domain: string; issuer: string; issuedAt: string; expiresAt: string; status: 'valid' | 'expiring' | 'expired'; daysUntilExpiry: number; autoRenew: boolean; } export interface ApiToken { id: string; name: string; permissions: string[]; createdAt: string; lastUsed: string; expiresAt: string; status: 'active' | 'expired' | 'revoked'; masked: string; } export interface SecurityEvent { id: string; type: 'login' | 'deployment' | 'access' | 'error'; user: string; action: string; timestamp: string; ip: string; status: 'success' | 'failed'; location: string; } export class SecurityService { private configService: ConfigService; private authService: AuthService; constructor() { this.configService = new ConfigService(); this.authService = new AuthService(); } async listCertificates(options: { status?: string } = {}): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); const params = new URLSearchParams(); if (options.status) params.append('status', options.status); const response = await axios.get(`${config.apiUrl}/api/security/certificates?${params}`, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); const data = response.data; console.log(chalk.cyan.bold('\nšŸ”’ SSL Certificates')); console.log(chalk.gray(`Total: ${data.total} certificates`)); console.log(chalk.gray(`Valid: ${data.summary.valid} | Expiring: ${data.summary.expiring} | Expired: ${data.summary.expired}`)); if (data.certificates.length === 0) { console.log(chalk.yellow('No certificates found')); return; } console.log('\n' + chalk.white('Domain'.padEnd(35) + 'Status'.padEnd(12) + 'Expires'.padEnd(15) + 'Days Left'.padEnd(12) + 'Auto-Renew')); console.log(chalk.gray('─'.repeat(85))); data.certificates.forEach((cert: Certificate) => { const statusIcon = cert.status === 'valid' ? 'āœ…' : cert.status === 'expiring' ? 'āš ļø' : 'āŒ'; const statusColor = cert.status === 'valid' ? chalk.green : cert.status === 'expiring' ? chalk.yellow : chalk.red; console.log( `${statusIcon} ${chalk.white(cert.domain.padEnd(32))} ` + `${statusColor(cert.status.padEnd(11))} ` + `${chalk.white(cert.expiresAt.padEnd(14))} ` + `${chalk.white(cert.daysUntilExpiry.toString().padEnd(11))} ` + `${cert.autoRenew ? chalk.green('Yes') : chalk.red('No')}` ); }); } catch (error) { throw new Error(`Failed to list certificates: ${error.message}`); } } async renewCertificate(certificateId: string): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Renewing SSL certificate...')); const response = await axios.post(`${config.apiUrl}/api/security/certificates/${certificateId}/renew`, {}, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 30000 }); const cert = response.data.certificate; console.log(chalk.green('āœ… Certificate renewed successfully!')); console.log(chalk.white(`Domain: ${cert.domain}`)); console.log(chalk.white(`New expiry: ${cert.expiresAt}`)); console.log(chalk.white(`Valid for: ${cert.daysUntilExpiry} days`)); } catch (error) { throw new Error(`Failed to renew certificate: ${error.message}`); } } async listTokens(): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); const response = await axios.get(`${config.apiUrl}/api/security/tokens`, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); const data = response.data; console.log(chalk.cyan.bold('\nšŸ”‘ API Tokens')); console.log(chalk.gray(`Total: ${data.total} tokens`)); console.log(chalk.gray(`Active: ${data.summary.active} | Expired: ${data.summary.expired}`)); if (data.tokens.length === 0) { console.log(chalk.yellow('No tokens found')); return; } console.log('\n' + chalk.white('Name'.padEnd(25) + 'Permissions'.padEnd(20) + 'Last Used'.padEnd(15) + 'Expires'.padEnd(12) + 'Status')); console.log(chalk.gray('─'.repeat(85))); data.tokens.forEach((token: ApiToken) => { const statusIcon = token.status === 'active' ? 'āœ…' : token.status === 'expired' ? 'āš ļø' : 'āŒ'; const statusColor = token.status === 'active' ? chalk.green : token.status === 'expired' ? chalk.yellow : chalk.red; console.log( `${statusIcon} ${chalk.white(token.name.padEnd(22))} ` + `${chalk.blue(token.permissions.join(',').padEnd(19))} ` + `${chalk.white((token.lastUsed || 'Never').padEnd(14))} ` + `${chalk.white(token.expiresAt.padEnd(11))} ` + `${statusColor(token.status)}` ); }); } catch (error) { throw new Error(`Failed to list tokens: ${error.message}`); } } async createToken(options: any = {}): Promise<void> { try { let tokenConfig; if (options.interactive !== false) { tokenConfig = await inquirer.prompt([ { type: 'input', name: 'name', message: 'Token name:', default: options.name, validate: (input) => input.length > 0 || 'Name is required' }, { type: 'checkbox', name: 'permissions', message: 'Select permissions:', choices: [ { name: 'Read', value: 'read', checked: true }, { name: 'Write', value: 'write' }, { name: 'Deploy', value: 'deploy' }, { name: 'Admin', value: 'admin' }, { name: 'Monitoring', value: 'monitoring' } ], default: options.permissions || ['read'] }, { type: 'list', name: 'expiresIn', message: 'Token expiry:', choices: [ { name: '30 days', value: '30d' }, { name: '90 days', value: '90d' }, { name: '1 year', value: '365d' }, { name: 'Never', value: 'never' } ], default: options.expiresIn || '90d' } ]); } else { tokenConfig = options; } const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Creating API token...')); const response = await axios.post(`${config.apiUrl}/api/security/tokens`, tokenConfig, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); const token = response.data.token; console.log(chalk.green('āœ… Token created successfully!')); console.log(chalk.white(`Name: ${token.name}`)); console.log(chalk.white(`Permissions: ${token.permissions.join(', ')}`)); console.log(chalk.white(`Expires: ${token.expiresAt}`)); console.log(chalk.yellow.bold(`\nšŸ”‘ Token: ${token.full}`)); console.log(chalk.red('āš ļø Store this token securely. It will not be shown again.')); } catch (error) { throw new Error(`Failed to create token: ${error.message}`); } } async revokeToken(tokenId: string): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); console.log(chalk.blue('šŸ”„ Revoking API token...')); await axios.delete(`${config.apiUrl}/api/security/tokens/${tokenId}`, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); console.log(chalk.green('āœ… Token revoked successfully!')); } catch (error) { throw new Error(`Failed to revoke token: ${error.message}`); } } async listSecurityEvents(options: { type?: string; status?: string; limit?: number } = {}): Promise<void> { try { const config = await this.configService.getConfig(); const auth = await this.authService.getAuth(); const params = new URLSearchParams(); if (options.type) params.append('type', options.type); if (options.status) params.append('status', options.status); if (options.limit) params.append('limit', options.limit.toString()); const response = await axios.get(`${config.apiUrl}/api/security/events?${params}`, { headers: { 'Authorization': `Bearer ${auth.token}`, 'Content-Type': 'application/json' }, timeout: 10000 }); const data = response.data; console.log(chalk.cyan.bold('\nšŸ›”ļø Security Events')); console.log(chalk.gray(`Showing ${data.events.length} of ${data.total} events`)); console.log(chalk.gray(`Last 24h: ${data.summary.last24h} events`)); if (data.events.length === 0) { console.log(chalk.yellow('No security events found')); return; } console.log('\n' + chalk.white('Type'.padEnd(12) + 'User'.padEnd(20) + 'Action'.padEnd(25) + 'Status'.padEnd(10) + 'Time')); console.log(chalk.gray('─'.repeat(80))); data.events.forEach((event: SecurityEvent) => { const statusIcon = event.status === 'success' ? 'āœ…' : 'āŒ'; const statusColor = event.status === 'success' ? chalk.green : chalk.red; console.log( `${statusIcon} ${chalk.blue(event.type.padEnd(10))} ` + `${chalk.white(event.user.padEnd(19))} ` + `${chalk.white(event.action.padEnd(24))} ` + `${statusColor(event.status.padEnd(9))} ` + `${chalk.gray(new Date(event.timestamp).toLocaleString())}` ); }); } catch (error) { throw new Error(`Failed to list security events: ${error.message}`); } } }