UNPKG

n8n-nodes-netdevices

Version:
356 lines 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LinuxConnection = void 0; const base_connection_1 = require("../base-connection"); class LinuxConnection extends base_connection_1.BaseConnection { constructor(credentials) { super(credentials); this.shellPrompt = ''; this.rootUser = false; this.initialPromptDetected = false; } async sessionPreparation() { await this.createLinuxShellChannel(); await this.waitForInitialPrompt(); if (this.fastMode) { await this.setBasePrompt(); } else { await this.setBasePrompt(); await this.checkRootUser(); await this.setShellOptions(); } } async createLinuxShellChannel() { return new Promise((resolve, reject) => { this.client.shell((err, channel) => { if (err) { reject(err); return; } this.currentChannel = channel; this.currentChannel.setEncoding(this.encoding); let initialBuffer = ''; const initialPromptTimeout = this.fastMode ? 5000 : 10000; const initialPromptTimer = setTimeout(() => { if (!this.initialPromptDetected) { this.initialPromptDetected = true; resolve(); } }, initialPromptTimeout); const onInitialData = (data) => { initialBuffer += data; if (this.detectLinuxPrompt(initialBuffer)) { this.initialPromptDetected = true; clearTimeout(initialPromptTimer); this.currentChannel.removeListener('data', onInitialData); resolve(); } }; this.currentChannel.on('data', onInitialData); const minWaitTime = this.fastMode ? 150 : 400; setTimeout(() => { if (!this.initialPromptDetected) { if (initialBuffer.length > 0) { this.initialPromptDetected = true; clearTimeout(initialPromptTimer); this.currentChannel.removeListener('data', onInitialData); resolve(); } } }, minWaitTime); }); }); } async waitForInitialPrompt() { if (this.initialPromptDetected) { return; } return new Promise((resolve) => { const timeout = this.fastMode ? 2000 : 4000; setTimeout(() => { this.initialPromptDetected = true; resolve(); }, timeout); }); } detectLinuxPrompt(buffer) { const promptPatterns = [ /\$\s*$/m, /#\s*$/m, />\s*$/m, /\]\s*\$\s*$/m, /\]\s*#\s*$/m, /~\s*\$\s*$/m, /~\s*#\s*$/m, /@.*:\s*\$\s*$/m, /@.*:\s*#\s*$/m, /@.*:\s*~\s*\$\s*$/m, /@.*:\s*~\s*#\s*$/m, ]; return promptPatterns.some(pattern => pattern.test(buffer)); } async setBasePrompt() { try { await this.writeChannel(this.returnChar); const output = await this.readChannel(4000); if (!output.trim()) { await this.writeChannel(this.newline); const newOutput = await this.readChannel(3000); if (newOutput.trim()) { this.extractPromptFromOutput(newOutput); } else { this.setFallbackPrompt(); } } else { this.extractPromptFromOutput(output); } } catch (error) { this.setFallbackPrompt(); } } extractPromptFromOutput(output) { const lines = output.trim().split('\n'); const lastLine = lines[lines.length - 1]; this.basePrompt = lastLine.replace(/[>#$%]\s*$/, '').trim(); this.shellPrompt = lastLine.trim(); this.enabledPrompt = this.basePrompt + '#'; this.configPrompt = this.basePrompt + '#'; } setFallbackPrompt() { this.basePrompt = 'linux'; this.shellPrompt = 'linux$'; this.enabledPrompt = 'linux#'; this.configPrompt = 'linux#'; } async checkRootUser() { try { const result = await this.sendCommand('whoami'); if (result.success && result.output.includes('root')) { this.rootUser = true; } } catch (error) { this.rootUser = false; } } async setShellOptions() { try { await this.writeChannel('set +e' + this.newline); await this.readChannel(1000); await this.writeChannel('export PS1="\\u@\\h:\\w\\$ "' + this.newline); await this.readChannel(1000); } catch (error) { } } async sendCommand(command) { try { if (!this.isConnected || !this.currentChannel) { throw new Error('Not connected to device'); } await this.writeChannel(command + this.newline); const timeout = this.fastMode ? 4000 : 8000; const output = await this.readUntilPromptEnhanced(timeout); const cleanOutput = this.sanitizeOutput(output, command); return { command, output: cleanOutput, success: true }; } catch (error) { return { command, output: '', success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } } async readUntilPromptEnhanced(timeout = 8000) { return new Promise((resolve, reject) => { let buffer = ''; let timeoutId; const linuxPromptPatterns = [ this.basePrompt, this.shellPrompt, /\$\s*$/, /#\s*$/, />\s*$/, /\]\s*\$\s*$/, /\]\s*#\s*$/, /@.*:\s*\$\s*$/, /@.*:\s*#\s*$/, /@.*:\s*~\s*\$\s*$/, /@.*:\s*~\s*#\s*$/, ]; const onData = (data) => { buffer += data; const hasPrompt = linuxPromptPatterns.some(pattern => { if (typeof pattern === 'string') { return buffer.includes(pattern); } else { return pattern.test(buffer); } }); if (hasPrompt) { cleanup(); resolve(buffer); return; } const lines = buffer.split('\n'); const lastLine = lines[lines.length - 1]; if (lastLine.length > 0 && this.detectLinuxPrompt(lastLine)) { cleanup(); resolve(buffer); return; } }; const onError = (error) => { cleanup(); reject(error); }; const cleanup = () => { if (this.currentChannel) { this.currentChannel.removeListener('data', onData); this.currentChannel.removeListener('error', onError); } if (timeoutId) { clearTimeout(timeoutId); } }; timeoutId = setTimeout(() => { cleanup(); reject(new Error(`Timeout waiting for prompt after ${timeout}ms. Buffer: ${buffer.slice(-200)}`)); }, timeout); if (this.currentChannel) { this.currentChannel.on('data', onData); this.currentChannel.on('error', onError); } else { cleanup(); reject(new Error('No active channel available')); } }); } async sendConfig(configCommands) { try { if (!this.isConnected || !this.currentChannel) { throw new Error('Not connected to device'); } let allOutput = ''; for (const command of configCommands) { await this.writeChannel(command + this.newline); const output = await this.readChannel(3000); allOutput += output; if (output.includes('Permission denied') || output.includes('command not found') || output.includes('No such file or directory')) { throw new Error(`Configuration error on command "${command}": ${output}`); } } const cleanOutput = this.sanitizeOutput(allOutput, configCommands.join('; ')); return { command: configCommands.join('; '), output: cleanOutput, success: true }; } catch (error) { return { command: configCommands.join('; '), output: '', success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } } async getCurrentConfig() { return await this.sendCommand('cat /etc/os-release && echo "---" && uname -a'); } async saveConfig() { return await this.sendCommand('sync && echo "Configuration synchronized"'); } async rebootDevice() { try { let command = 'reboot'; if (!this.rootUser) { command = 'sudo reboot'; } await this.writeChannel(command + this.newline); const output = await this.readChannel(5000); return { command: command, output: output, success: true }; } catch (error) { return { command: 'reboot', output: '', success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } } sanitizeOutput(output, command) { const escapedCommand = command.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); let cleanOutput = output.replace(new RegExp(escapedCommand, 'g'), ''); const escapedShellPrompt = this.shellPrompt.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); cleanOutput = cleanOutput.replace(new RegExp(escapedShellPrompt, 'g'), ''); cleanOutput = cleanOutput.replace(/\[.*?\]/g, ''); cleanOutput = cleanOutput.replace(/\$\s*$/gm, ''); cleanOutput = cleanOutput.replace(/#\s*$/gm, ''); cleanOutput = cleanOutput.replace(/^\s+|\s+$/g, ''); cleanOutput = cleanOutput.replace(/\r\n/g, '\n'); cleanOutput = cleanOutput.replace(/\r/g, '\n'); cleanOutput = cleanOutput.replace(/\n\s*\n/g, '\n'); return cleanOutput; } isRootUser() { return this.rootUser; } async executeAsRoot(command) { if (this.rootUser) { return await this.sendCommand(command); } else { return await this.sendCommand('sudo ' + command); } } async getSystemInfo() { return await this.sendCommand('uname -a && cat /etc/os-release'); } async getProcessList() { return await this.sendCommand('ps aux'); } async getDiskUsage() { return await this.sendCommand('df -h'); } async getMemoryInfo() { return await this.sendCommand('free -h'); } async getNetworkInterfaces() { return await this.sendCommand('ip addr show'); } async getServiceStatus(serviceName) { return await this.sendCommand(`systemctl status ${serviceName}`); } async startService(serviceName) { return await this.executeAsRoot(`systemctl start ${serviceName}`); } async stopService(serviceName) { return await this.executeAsRoot(`systemctl stop ${serviceName}`); } async restartService(serviceName) { return await this.executeAsRoot(`systemctl restart ${serviceName}`); } } exports.LinuxConnection = LinuxConnection; //# sourceMappingURL=linux-connection.js.map