UNPKG

n8n-nodes-netdevices

Version:

n8n node to interact with network devices (Cisco, Juniper, Palo Alto PAN-OS, Ciena SAOS, Linux, etc.)

322 lines 11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FortinetConnection = void 0; const base_connection_1 = require("../base-connection"); class FortinetConnection extends base_connection_1.BaseConnection { constructor(credentials) { super(credentials); this.promptPattern = /[#$]/; this.vdoms = false; this.osVersion = ''; this.originalOutputMode = ''; this.outputMode = ''; this.inConfigGlobal = false; } async sessionPreparation() { await this.createFortinetShellChannel(); await this.handleBanner(); await this.setBasePrompt(); await this.detectVDOMs(); await this.determineOSVersion(); await this.detectOutputMode(); await this.disablePaging(); } async createFortinetShellChannel() { return new Promise((resolve, reject) => { this.client.shell((err, channel) => { if (err) { reject(err); return; } this.currentChannel = channel; this.currentChannel.setEncoding(this.encoding); setTimeout(() => resolve(), this.fastMode ? 200 : 600); }); }); } async handleBanner() { try { const data = await this.readChannel(3000); if (data.includes('to accept')) { await this.writeChannel('a' + this.returnChar); await this.readChannel(2000); } } catch (error) { } } async setBasePrompt() { await this.writeChannel(this.returnChar); const output = await this.readChannel(3000); const lines = output.trim().split('\n'); const lastLine = lines[lines.length - 1]; this.basePrompt = lastLine.replace(/[#$]\s*$/, '').trim(); this.enabledPrompt = this.basePrompt + '#'; this.configPrompt = this.basePrompt + '#'; } async detectVDOMs() { try { const result = await this.sendCommand('get system status | grep Virtual'); const output = result.output.toLowerCase(); this.vdoms = output.includes('virtual domain configuration: multiple') || output.includes('virtual domain configuration: enable') || output.includes('virtual domain configuration: split-task'); } catch (error) { this.vdoms = false; } } async determineOSVersion() { try { const result = await this.sendCommand('get system status | grep Version'); const output = result.output; if (output.match(/Version: .* (v[78]\.)/)) { this.osVersion = 'v7_or_later'; } else if (output.match(/Version: .* (v[654]\.)/)) { this.osVersion = 'v6_or_earlier'; } else { this.osVersion = 'unknown'; } } catch (error) { this.osVersion = 'unknown'; } } async detectOutputMode() { try { if (this.osVersion === 'v6_or_earlier') { this.originalOutputMode = await this.getOutputModeV6(); } else { this.originalOutputMode = await this.getOutputModeV7(); } this.outputMode = this.originalOutputMode; } catch (error) { this.originalOutputMode = 'more'; this.outputMode = 'more'; } } async getOutputModeV6() { if (this.vdoms) { await this.enterConfigGlobal(); } const result = await this.sendCommand('show full-configuration system console'); const output = result.output; if (this.vdoms) { await this.exitConfigGlobal(); } const match = output.match(/^\s+set output (\S+)\s*$/m); if (match && ['more', 'standard'].includes(match[1])) { return match[1]; } return 'more'; } async getOutputModeV7() { if (this.vdoms) { await this.enterConfigGlobal(); } const result = await this.sendCommand('get system console'); const output = result.output; if (this.vdoms) { await this.exitConfigGlobal(); } const match = output.match(/output\s+:\s+(\S+)\s*$/m); if (match && ['more', 'standard'].includes(match[1])) { return match[1]; } return 'more'; } async enterConfigGlobal() { try { await this.writeChannel('config global' + this.newline); const output = await this.readChannel(3000); if (output.includes('#')) { this.inConfigGlobal = true; } else { throw new Error('Failed to enter config global mode'); } } catch (error) { throw new Error('Netmiko may require config global access to properly disable output paging. Alternatively you can try configuring configure system console -> set output standard.'); } } async exitConfigGlobal() { if (!this.inConfigGlobal) { return; } try { await this.writeChannel('end' + this.newline); const output = await this.readChannel(3000); if (!output.includes('config global')) { this.inConfigGlobal = false; } else { throw new Error('Failed to exit config global mode'); } } catch (error) { throw new Error('Unable to properly exit config global mode.'); } } async disablePaging() { if (this.outputMode === 'standard') { return; } try { if (this.vdoms) { await this.enterConfigGlobal(); } const commands = [ 'config system console', 'set output standard', 'end' ]; for (const command of commands) { await this.writeChannel(command + this.newline); await this.readChannel(2000); } this.outputMode = 'standard'; if (this.vdoms) { await this.exitConfigGlobal(); } } 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 ? 8000 : 15000; const output = await this.readUntilPrompt(undefined, 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 : String(error) }; } } async sendConfig(configCommands) { try { if (!this.isConnected || !this.currentChannel) { throw new Error('Not connected to device'); } let fullOutput = ''; for (const command of configCommands) { await this.writeChannel(command + this.newline); const output = await this.readChannel(3000); fullOutput += output; } const cleanOutput = this.sanitizeOutput(fullOutput, configCommands.join('\n')); return { command: configCommands.join('\n'), output: cleanOutput, success: true }; } catch (error) { return { command: configCommands.join('\n'), output: '', success: false, error: error instanceof Error ? error.message : String(error) }; } } async getCurrentConfig() { return this.sendCommand('show full-configuration'); } async saveConfig() { return { command: 'save config', output: 'Fortinet configuration is typically saved automatically', success: true }; } async rebootDevice() { try { if (!this.isConnected || !this.currentChannel) { throw new Error('Not connected to device'); } await this.writeChannel('execute reboot' + this.newline); const output = await this.readChannel(5000); if (output.toLowerCase().includes('yes/no') || output.toLowerCase().includes('y/n')) { await this.writeChannel('yes' + this.newline); await this.readChannel(3000); } return { command: 'execute reboot', output: this.sanitizeOutput(output, 'execute reboot'), success: true }; } catch (error) { return { command: 'execute reboot', output: '', success: false, error: error instanceof Error ? error.message : String(error) }; } } sanitizeOutput(output, command) { let cleanOutput = output.replace(command, '').trim(); cleanOutput = cleanOutput.replace(new RegExp(this.promptPattern.source + '\\s*$', 'g'), ''); cleanOutput = cleanOutput.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, ''); cleanOutput = cleanOutput.replace(/\n\s*\n/g, '\n').trim(); return cleanOutput; } async enterConfigMode() { return; } async exitConfigMode() { return; } isInConfigMode() { return false; } async cleanup() { try { if (this.originalOutputMode === 'more') { if (this.vdoms) { await this.enterConfigGlobal(); } const commands = [ 'config system console', 'set output more', 'end' ]; for (const command of commands) { await this.writeChannel(command + this.newline); await this.readChannel(2000); } if (this.vdoms) { await this.exitConfigGlobal(); } } } catch (error) { } await this.disconnect(); } hasVDOMs() { return this.vdoms; } getOSVersion() { return this.osVersion; } getOutputMode() { return this.outputMode; } } exports.FortinetConnection = FortinetConnection; //# sourceMappingURL=fortinet-connection.js.map