const { spawn } = require('child_process');
const express = require('express');
const app = express();
app.use(express.json());
// SECURE: Using spawn with argument array
app.post('/ping', async (req, res) => {
try {
const hostname = req.body.hostname;
// Validate hostname format
const hostnamePattern = /^[a-zA-Z0-9][a-zA-Z0-9\-\.]{0,252}$/;
if (!hostname || !hostnamePattern.test(hostname)) {
return res.status(400).json({ error: 'Invalid hostname' });
}
// Use spawn with argument array (no shell)
const output = await executeSafely('ping', ['-c', '1', hostname]);
res.json({ output });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// SECURE: Allowlist validation for compress
app.post('/compress', async (req, res) => {
try {
const filename = req.body.filename;
const format = req.body.format;
// Validate format against allowlist
const allowedFormats = ['gz', 'bz2', 'xz'];
if (!allowedFormats.includes(format)) {
return res.status(400).json({ error: 'Invalid format' });
}
// Validate filename
const filenamePattern = /^[a-zA-Z0-9_\-\.]+$/;
if (!filename || !filenamePattern.test(filename)) {
return res.status(400).json({ error: 'Invalid filename' });
}
// Use spawn with argument array
const args = [`-c${format}f`, `${filename}.tar.${format}`, filename];
await executeSafely('tar', args);
res.json({ message: 'Compressed successfully' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Safe command execution helper
function executeSafely(command, args, timeout = 10000) {
return new Promise((resolve, reject) => {
const child = spawn(command, args);
let stdout = '';
child.stdout.on('data', (data) => stdout += data);
child.on('close', (code) => {
code === 0 ? resolve(stdout) : reject(new Error('Command failed'));
});
setTimeout(() => {
child.kill();
reject(new Error('Timeout'));
}, timeout);
});
}