n8n-nodes-netdevices
Version:
n8n node to interact with network devices (Cisco, MikroTik, Arista, Extreme Networks, Dell, Juniper, HP, Aruba, Ubiquiti, Palo Alto, Fortinet - ISP, data center, campus, and edge)
383 lines • 13.5 kB
JavaScript
"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.vdoms = false;
this.osVersion = '';
this.originalOutputMode = '';
this.outputMode = '';
this.inConfigGlobal = false;
this.setupFortiGateAlgorithms();
}
setupFortiGateAlgorithms() {
const originalGetOptimizedAlgorithms = this.getOptimizedAlgorithms.bind(this);
this.getOptimizedAlgorithms = () => {
const fortiGateAlgorithms = {
serverHostKey: ['ssh-rsa', 'ecdsa-sha2-nistp256'],
cipher: ['aes128-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc'],
hmac: ['hmac-sha1', 'hmac-sha2-256'],
kex: [
'diffie-hellman-group14-sha1',
'diffie-hellman-group-exchange-sha1',
'diffie-hellman-group-exchange-sha256',
'diffie-hellman-group1-sha1'
]
};
return [fortiGateAlgorithms, ...originalGetOptimizedAlgorithms()];
};
}
async sessionPreparation() {
try {
await this.createFortinetShellChannel();
await this.handleBanner();
await this.setBasePrompt();
await this.detectVDOMs();
await this.determineOSVersion();
await this.detectOutputMode();
await this.disablePaging();
}
catch (error) {
throw new Error(`FortiGate session preparation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
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 ? 500 : 1000);
});
});
}
async handleBanner() {
try {
const data = await this.readChannel(5000);
if (data.includes('to accept')) {
await this.writeChannel('a' + this.returnChar);
await this.readChannel(3000);
}
if (data.includes('Press any key to continue') || data.includes('Press Enter to continue')) {
await this.writeChannel(this.returnChar);
await this.readChannel(3000);
}
if (data.includes('Welcome') || data.includes('FortiGate') || data.includes('FortiOS')) {
await this.writeChannel(this.returnChar);
await this.readChannel(3000);
}
}
catch (error) {
console.warn('Banner handling failed, continuing:', error);
}
}
async setBasePrompt() {
try {
await this.writeChannel(this.returnChar);
const output = await this.readChannel(3000);
const lines = output.trim().split('\n');
let prompt = '';
for (let i = lines.length - 1; i >= 0; i--) {
const line = lines[i].trim();
if (line.match(/[#$]\s*$/)) {
prompt = line.replace(/[#$]\s*$/, '').trim();
break;
}
}
if (!prompt) {
const hostnameMatch = output.match(/FortiGate-(\S+)/i) ||
output.match(/(\S+)\s*[#$]/);
if (hostnameMatch) {
prompt = hostnameMatch[1];
}
else {
prompt = 'FortiGate';
}
}
this.basePrompt = prompt;
this.enabledPrompt = this.basePrompt + '#';
this.configPrompt = this.basePrompt + '#';
}
catch (error) {
throw new Error(`Failed to set base prompt: ${error instanceof Error ? error.message : String(error)}`);
}
}
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) {
console.warn('Failed to disable paging, continuing:', 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 ? 10000 : 20000;
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) {
const lines = output.split('\n');
if (lines.length > 0 && lines[0].includes(command)) {
lines.shift();
}
if (lines.length > 0) {
const lastLine = lines[lines.length - 1];
const promptRegex = new RegExp(`^${this.escapeRegex(this.basePrompt)}[>#$]`);
if (promptRegex.test(lastLine)) {
lines.pop();
}
}
return lines.join('\n').trim();
}
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