@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
text/typescript
/**
* 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}`);
}
}
}