66 lines
2.0 KiB
JavaScript
66 lines
2.0 KiB
JavaScript
const { Client } = require('ssh2');
|
|
const fs = require('fs');
|
|
require('dotenv').config();
|
|
|
|
const getSSHConfig = () => {
|
|
const config = {
|
|
host: process.env.SSH_HOST,
|
|
username: process.env.SSH_USER,
|
|
port: 22,
|
|
};
|
|
|
|
let privateKeyPath = process.env.SSH_KEY_PATH;
|
|
if (privateKeyPath && privateKeyPath.endsWith('.pub')) {
|
|
privateKeyPath = privateKeyPath.replace('.pub', '');
|
|
}
|
|
|
|
if (privateKeyPath) {
|
|
config.privateKey = fs.readFileSync(privateKeyPath);
|
|
} else if (process.env.SSH_PASSWORD) {
|
|
config.password = process.env.SSH_PASSWORD;
|
|
}
|
|
|
|
return config;
|
|
};
|
|
|
|
const execCommand = (command) => {
|
|
return new Promise((resolve, reject) => {
|
|
const conn = new Client();
|
|
conn.on('ready', () => {
|
|
conn.exec(command, (err, stream) => {
|
|
if (err) {
|
|
conn.end();
|
|
return reject(err);
|
|
}
|
|
let output = '';
|
|
let errorOutput = '';
|
|
stream.on('close', (code, signal) => {
|
|
conn.end();
|
|
if (code !== 0) return reject(new Error(`Command failed with code ${code}: ${errorOutput}`));
|
|
resolve(output.trim());
|
|
}).on('data', (data) => {
|
|
output += data;
|
|
}).stderr.on('data', (data) => {
|
|
errorOutput += data;
|
|
});
|
|
});
|
|
}).on('error', (err) => {
|
|
reject(err);
|
|
}).connect(getSSHConfig());
|
|
});
|
|
};
|
|
|
|
const readFile = (filePath) => {
|
|
return execCommand(`cat "${filePath}"`);
|
|
};
|
|
|
|
const writeFile = (filePath, content) => {
|
|
// Basic implementation: echo content to file.
|
|
// WARNING: Not safe for large files or complex headers, but start simple.
|
|
// Ideally use SFTP for robustness later.
|
|
const escapedContent = content.replace(/"/g, '\\"');
|
|
return execCommand(`echo "${escapedContent}" > "${filePath}"`);
|
|
};
|
|
|
|
module.exports = { execCommand, readFile, writeFile };
|