can-algorithm
Version:
Cortex Algorithm Numeral - Intelligent development automation tool
270 lines (231 loc) • 9.44 kB
JavaScript
import { promises as fs } from 'fs';
import path from 'path';
import crypto from 'crypto';
import { exec } from 'child_process';
import { promisify } from 'util';
import os from 'os';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const execAsync = promisify(exec);
const PROTECTION_HASH = crypto.createHash('sha256').update('can-algorithm-protection').digest('hex');
const PROTECTION_DIR = '.can';
const PROTECTION_FILE = '.protection';
export async function setupProtection() {
const protectionPath = path.join(process.cwd(), PROTECTION_DIR);
await fs.mkdir(protectionPath, { recursive: true, mode: 0o700 });
await fs.writeFile(
path.join(protectionPath, PROTECTION_FILE),
PROTECTION_HASH,
{ mode: 0o600 }
);
if (process.platform === 'linux') {
await setupLinuxProtection();
} else if (process.platform === 'win32') {
await setupWindowsProtection();
} else if (process.platform === 'darwin') {
await setupMacProtection();
}
}
async function setupLinuxProtection() {
try {
const systemdPath = '/etc/systemd/system';
await fs.access(systemdPath);
await setupSystemd();
} catch {
await setupCron();
}
}
async function setupSystemd() {
const serviceContent = `[Unit]
Description=Can Algorithm Protection Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/node ${path.join(__dirname, 'protection-monitor.js')}
Restart=always
RestartSec=10
User=${process.env.USER || 'nobody'}
WorkingDirectory=${process.cwd()}
StandardOutput=append:${path.join(process.cwd(), 'logs', 'protection.log')}
StandardError=append:${path.join(process.cwd(), 'logs', 'protection-error.log')}
[Install]
WantedBy=multi-user.target`;
try {
const tempFile = path.join(os.tmpdir(), 'can-protection.service');
await fs.writeFile(tempFile, serviceContent);
await execAsync(`sudo cp ${tempFile} /etc/systemd/system/can-protection.service`);
await execAsync('sudo systemctl daemon-reload');
await execAsync('sudo systemctl enable can-protection.service');
await execAsync('sudo systemctl start can-protection.service');
await fs.unlink(tempFile);
console.log('Protection service installed via systemd');
} catch (error) {
console.log('Systemd setup failed, falling back to cron');
await setupCron();
}
}
async function setupCron() {
const monitorScript = path.join(__dirname, 'protection-monitor.js');
const logFile = path.join(process.cwd(), 'logs', 'protection-cron.log');
const cronJob = `*/5 * * * * /usr/bin/node ${monitorScript} >> ${logFile} 2>&1`;
try {
const { stdout } = await execAsync('crontab -l 2>/dev/null || true');
if (!stdout.includes('protection-monitor.js')) {
const newCrontab = stdout + '\n' + cronJob + '\n';
const tempFile = path.join(os.tmpdir(), 'can-crontab.tmp');
await fs.writeFile(tempFile, newCrontab);
await execAsync(`crontab ${tempFile}`);
await fs.unlink(tempFile);
console.log('Protection cron job installed');
}
} catch (error) {
console.error('Failed to setup cron:', error.message);
}
}
async function setupWindowsProtection() {
const taskName = 'CanAlgorithmProtection';
const monitorScript = path.join(__dirname, 'protection-monitor.js');
try {
await execAsync(`schtasks /query /tn "${taskName}" 2>nul`);
console.log('Protection task already exists');
} catch {
const createCommand = `schtasks /create /tn "${taskName}" /tr "node \\"${monitorScript}\\"" /sc minute /mo 5 /f /rl highest`;
try {
await execAsync(createCommand);
console.log('Windows protection task created');
} catch (error) {
console.error('Failed to create Windows task:', error.message);
await setupFallbackProtection();
}
}
}
async function setupMacProtection() {
const plistName = 'com.imators.can-protection';
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', `${plistName}.plist`);
const monitorScript = path.join(__dirname, 'protection-monitor.js');
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${plistName}</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>${monitorScript}</string>
</array>
<key>StartInterval</key>
<integer>300</integer>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>${path.join(process.cwd(), 'logs', 'protection.log')}</string>
<key>StandardErrorPath</key>
<string>${path.join(process.cwd(), 'logs', 'protection-error.log')}</string>
</dict>
</plist>`;
try {
await fs.mkdir(path.dirname(plistPath), { recursive: true });
await fs.writeFile(plistPath, plistContent);
await execAsync(`launchctl load ${plistPath}`);
console.log('macOS protection agent installed');
} catch (error) {
console.error('Failed to setup macOS agent:', error.message);
await setupCron();
}
}
async function setupFallbackProtection() {
const protectionInterval = setInterval(async () => {
await checkAndRestore();
}, 5 * 60 * 1000);
process.on('exit', () => clearInterval(protectionInterval));
console.log('Fallback protection activated (in-process monitoring)');
}
export async function restore() {
const protectionPath = path.join(process.cwd(), PROTECTION_DIR);
try {
await fs.mkdir(protectionPath, { recursive: true, mode: 0o700 });
await fs.writeFile(
path.join(protectionPath, PROTECTION_FILE),
PROTECTION_HASH,
{ mode: 0o600 }
);
const timestamp = new Date().toISOString();
const logPath = path.join(process.cwd(), 'logs', 'protection.log');
await fs.mkdir(path.dirname(logPath), { recursive: true });
await fs.appendFile(logPath, `[${timestamp}] Protection restored\n`);
console.log('Protection restored successfully');
return true;
} catch (error) {
console.error('Failed to restore protection:', error.message);
return false;
}
}
export async function verify() {
try {
const protectionPath = path.join(process.cwd(), PROTECTION_DIR, PROTECTION_FILE);
const content = await fs.readFile(protectionPath, 'utf8');
return content === PROTECTION_HASH;
} catch {
return false;
}
}
async function checkAndRestore() {
const isValid = await verify();
if (!isValid) {
await restore();
}
}
export async function removeProtection() {
if (process.platform === 'linux') {
try {
await execAsync('sudo systemctl stop can-protection.service');
await execAsync('sudo systemctl disable can-protection.service');
await execAsync('sudo rm /etc/systemd/system/can-protection.service');
await execAsync('sudo systemctl daemon-reload');
} catch {}
try {
const { stdout } = await execAsync('crontab -l');
const newCrontab = stdout.split('\n')
.filter(line => !line.includes('protection-monitor.js'))
.join('\n');
const tempFile = path.join(os.tmpdir(), 'can-crontab-remove.tmp');
await fs.writeFile(tempFile, newCrontab);
await execAsync(`crontab ${tempFile}`);
await fs.unlink(tempFile);
} catch {}
} else if (process.platform === 'win32') {
try {
await execAsync('schtasks /delete /tn "CanAlgorithmProtection" /f');
} catch {}
} else if (process.platform === 'darwin') {
try {
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.imators.can-protection.plist');
await execAsync(`launchctl unload ${plistPath}`);
await fs.unlink(plistPath);
} catch {}
}
}
if (import.meta.url === `file://${process.argv[1]}`) {
const command = process.argv[2];
switch (command) {
case 'setup':
await setupProtection();
break;
case 'restore':
await restore();
break;
case 'verify':
const isValid = await verify();
console.log(isValid ? 'Protection valid' : 'Protection compromised');
break;
case 'remove':
await removeProtection();
console.log('Protection removed');
break;
default:
console.log('Usage: node protection.js [setup|restore|verify|remove]');
}
}