Last active
August 2, 2025 07:06
-
-
Save akansha-oi/4c5b0db28b0028711c26dc005e9c58af to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const express = require('express'); | |
| const cors = require('cors'); | |
| let systemConfig = { | |
| description: "Managed Switch 7.4.8", | |
| objectId: "1.3.6.1.4.1.12284.1", | |
| version: "Managed Switch 7.4.8", | |
| interfaces: 10, | |
| serialNumber: "20200600001", | |
| macAddress: "00:28:24:13:D0:9D", | |
| ipAddress: "192.168.0.1", | |
| startTime: "0-Days 0-Hours 7-Minutes 5-Seconds", | |
| dateTime: "2020/01/01 00:04:57", | |
| systemName: "", | |
| systemLocation: "", | |
| systemContact: "" | |
| }; | |
| let industrialStatusData = { | |
| status: "Online", | |
| uptime: "2-Days 5-Hours 32-Minutes 15-Seconds", | |
| cpuUsage: 45, // Percentage | |
| memoryUsage: 60, // Percentage | |
| temperature: 35, // Degrees Celsius | |
| powerStatus: "Normal", | |
| ports: Array.from({ length: 10 }, (_, i) => ({ | |
| port: `${i + 1}`, | |
| linkStatus: Math.random() > 0.2 ? "Up" : "Down", | |
| speed: Math.random() > 0.5 ? "1000Mbps" : "100Mbps", | |
| activity: Math.random() > 0.3 ? "Active" : "Idle" | |
| })) | |
| }; | |
| let aclGroupNum = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] | |
| let protocolType = ["tcp", "ip", "udp"] | |
| let sourcePort = ["ftp(tcp)", "ftp-data(tcp)", "po3(tcp)", "smtp(tcp)", "telnet(tcp)", "www(tcp)", "rip(udp)", "snmp(udp)", "snmp-trap(udp)", "tftp(udp)"] | |
| let destinationPort = ["ftp(tcp)", "ftp-data(tcp)", "po3(tcp)", "smtp(tcp)", "telnet(tcp)", "www(tcp)", "rip(udp)", "snmp(udp)", "snmp-trap(udp)", "tftp(udp)"] | |
| const aclStandardIpEntries = []; | |
| let extendedAclEntries = []; | |
| let aclMacIpEntries = []; | |
| let macArpAclEntries = []; | |
| let serialConfig = { | |
| baudRate: "38400", | |
| charSize: "8", | |
| parity: "None", | |
| stopBits: "1", | |
| flowControl: "None" | |
| }; | |
| let availablePorts = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; | |
| let flowControlData = [ | |
| { port: "1", state: "Off" }, | |
| { port: "2", state: "Off" }, | |
| { port: "3", state: "Off" }, | |
| { port: "4", state: "Off" }, | |
| { port: "5", state: "Off" }, | |
| { port: "6", state: "Off" }, | |
| { port: "7", state: "Off" }, | |
| { port: "8", state: "Off" }, | |
| { port: "9", state: "Off" }, | |
| { port: "10", state: "Off" }, | |
| ]; | |
| let stormData = Array.from({ length: 10 }, (_, i) => ({ | |
| port: `${i + 1}`, | |
| broadcastSuppression: "Off", | |
| broadcastRate: 64, | |
| multicastSuppression: "Off", | |
| multicastRate: 64, | |
| dlfSuppression: "Off", | |
| dlfRate: 64 | |
| })); | |
| let protectedPortData = Array.from({ length: 10 }, (_, i) => ({ | |
| port: i + 1, | |
| protected: false | |
| })); | |
| let jumboFrameSize = 6000; | |
| let portRateLimits = [ | |
| { port: '1', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '2', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '3', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '4', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '5', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '6', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '7', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '8', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '9', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| { port: '10', egressRate: 0, ingressRate: 0, status: 'Off' }, | |
| ]; | |
| let userSafetyConfig = [ | |
| { serviceType: 'HTTP', managementState: 'Enable', aclGroup: 0 }, | |
| { serviceType: 'SNMP', managementState: 'Enable', aclGroup: 0 }, | |
| { serviceType: 'TELNET', managementState: 'Enable', aclGroup: 0 }, | |
| { serviceType: 'SSH', managementState: 'Enable', aclGroup: 0 }, | |
| ]; | |
| let sntpConfig = { | |
| ipAddress1: '', | |
| ipAddress2: '', | |
| ipAddress3: '', | |
| timeInterval: 0, | |
| timeZone: '', | |
| dstStatus: 'Disable', | |
| dstStartTime: '', | |
| dstEndTime: '', | |
| dstBias: 0, | |
| enableStatus: 'Disable', | |
| systemDateTime: '' | |
| }; | |
| let learnLimitData = Array.from({ length: 10 }, (_, i) => ({ | |
| port: `${i + 1}`, | |
| macLimit: 8191 | |
| })); | |
| let snmpCommunityData = [ | |
| { communityName: "public", accessType: "Read Only", state: "Active" } | |
| ]; | |
| let snmpVersionData = [ | |
| { versionType: "v2c", state: "Active" } | |
| ]; | |
| let trapTargetData = [ | |
| { trapIp: "192.168.1.100", trapCommunity: "public", trapVersion: "v2c", state: "Active" } | |
| ]; | |
| let qosData = Array.from({ length: 10 }, (_, i) => ({ | |
| port: i + 1, | |
| qosType: "NO QOS", | |
| priority: 0 | |
| })); | |
| let qosScheduleData = Array.from({ length: 10 }, (_, i) => ({ | |
| port: `${i + 1}`, | |
| mode: "WRR", // default mode | |
| weights: [1, 2, 4, 8, 16, 32, 64, 127] // queues 0 to 7 | |
| })); | |
| // AAA Configuration Data Structures | |
| let aaaAuthConfig = { | |
| authType: "local" | |
| }; | |
| let tacacsConfig = { | |
| serverIP: "0.0.0.0", | |
| optionServerIP: "0.0.0.0", | |
| authType: "pap", | |
| sharedSecret: "", | |
| authorization: "disable", | |
| accounting: "disable" | |
| }; | |
| let radiusConfig = { | |
| primaryServer: "0.0.0.0", | |
| optionServer: "0.0.0.0", | |
| udpPort: "1812", | |
| accounting: "enable", | |
| accountingUDPPort: "1813", | |
| sharedKey: "", | |
| vendor: "", | |
| nasPort: "50003", | |
| nasPortType: "15", | |
| nasServiceType: "2", | |
| roaming: "disable" | |
| }; | |
| let dot1xConfig = { | |
| enable: "disable", | |
| reauth: "disable", | |
| reauthPeriod: "3600", | |
| quietPeriod: "60", | |
| txPeriod: "30", | |
| serverTimeout: "10", | |
| supplicantTimeout: "30", | |
| maxRequest: "3", | |
| reauthMax: "3" | |
| }; | |
| let dot1xPortConfig = Array.from({ length: 10 }, (_, i) => ({ | |
| port: `${i + 1}`, | |
| portMode: "N/A", | |
| supportHostNum: 256 | |
| })); | |
| let dot1xUserAuthData = []; | |
| for (let i = 1; i <= 10; i++) { | |
| const portEntry = { | |
| port: i, | |
| port_mode: i === 1 ? "auto" : (i === 2 ? "force-authorized" : "auto"), | |
| accepted_host_num: i === 1 ? 1 : 0, | |
| users: [] | |
| }; | |
| if (i === i) { | |
| portEntry.users = [ | |
| { | |
| username: "user1", | |
| mac: "AA:BB:CC:DD:EE:01", | |
| request_state: "Success", | |
| applicant_state: "Authorized", | |
| applicant_retry: 0, | |
| backend_state: "Active", | |
| backend_request_num: 1, | |
| retry_request_state: "None" | |
| }, | |
| { | |
| username: "user2", | |
| mac: "AA:BB:CC:DD:EE:02", | |
| request_state: "Pending", | |
| applicant_state: "Initializing", | |
| applicant_retry: 2, | |
| backend_state: "Waiting", | |
| backend_request_num: 3, | |
| retry_request_state: "Retrying" | |
| } | |
| ]; | |
| } | |
| dot1xUserAuthData.push(portEntry); | |
| } | |
| // IGMP SNOOPING Configuration Data Structures | |
| let igmpSnoopingConfig = { | |
| globalIgmpSnooping: "disable", | |
| vlanId: "vlan1", | |
| vlanIgmpSnooping: "disable", | |
| fastLeave: "disable", | |
| fastLeaveTimeout: "300000", | |
| queryMembershipTimeout: "300000", | |
| groupMembershipTimeout: "400000" | |
| }; | |
| let multicastGroupInfo = { | |
| groups: [] | |
| }; | |
| // GMRP Configuration Data Structures | |
| let gmrpGlobalConfig = { | |
| globalGmrp: "disable" | |
| }; | |
| let gmrpPortsConfig = Array.from({ length: 10 }, (_, i) => ({ | |
| portName: `${i + 1}`, | |
| gmrpStatus: "Disable", | |
| joinTimer: "---", | |
| leaveTimer: "---", | |
| leaveAllTimer: "---" | |
| })); | |
| let gmrpStateMachine = { | |
| entries: [] | |
| }; | |
| // GVRP Configuration Data Structures | |
| let gvrpGlobalConfig = { | |
| globalGvrp: "disable" | |
| }; | |
| let gvrpPortsConfig = Array.from({ length: 10 }, (_, i) => ({ | |
| portName: `${i + 1}`, | |
| gvrpStatus: "Disable", | |
| joinTimer: "---", | |
| leaveTimer: "---", | |
| leaveAllTimer: "---" | |
| })); | |
| let gvrpStateMachine = { | |
| entries: [] | |
| }; | |
| // EAPS Configuration Data Structures | |
| let eapsConfigs = [ | |
| { | |
| eapsRingId: "3", | |
| eapsRingIdInput: "", | |
| createStatus: "Created", | |
| eapsMode: "Transit", | |
| primaryPort: "4", | |
| secondaryPort: "5", | |
| controlVlan: "0", | |
| protectedVlans: "", | |
| helloTimeInterval: "1", | |
| failTime: "3", | |
| dataSpan: "Disable", | |
| extremeInteroperability: "Enable", | |
| enableStatus: "Disable" | |
| }, | |
| { | |
| eapsRingId: "1", | |
| eapsRingIdInput: "", | |
| createStatus: "Created", | |
| eapsMode: "Master", | |
| primaryPort: "1", | |
| secondaryPort: "2", | |
| controlVlan: "100", | |
| protectedVlans: "10,20", | |
| helloTimeInterval: "2", | |
| failTime: "5", | |
| dataSpan: "Enable", | |
| extremeInteroperability: "Disable", | |
| enableStatus: "Enable" | |
| }, | |
| { | |
| eapsRingId: "2", | |
| eapsRingIdInput: "", | |
| createStatus: "Created", | |
| eapsMode: "Transit", | |
| primaryPort: "6", | |
| secondaryPort: "7", | |
| controlVlan: "200", | |
| protectedVlans: "30,40,50", | |
| helloTimeInterval: "1", | |
| failTime: "4", | |
| dataSpan: "Disable", | |
| extremeInteroperability: "Enable", | |
| enableStatus: "Enable" | |
| } | |
| ]; | |
| //lldp | |
| let lldpGlobalConfig = {} | |
| let lldpPortTableData = [ | |
| { | |
| "port": "ge1/1", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/2", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/3", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/4", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/5", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/6", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/7", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/8", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/9", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| }, | |
| { | |
| "port": "ge1/10", | |
| "status": "Enable", | |
| "adminStatus": "TxRx", | |
| "manageIp": "0.0.0.0", | |
| "interval": "0", | |
| "dot1tlv": "Enable", | |
| "dot3tlv": "Enable", | |
| "medtlv": "Enable" | |
| } | |
| ] | |
| // RMON Configuration Data Structures | |
| const rmonStatisticsData = [ | |
| { | |
| port: "1", | |
| index: "1", | |
| owner: "Admin1", | |
| stats: { | |
| etherStatsDropEvents: "10", | |
| etherStatsPkts: "1000", | |
| etherStatsMulticastPkts: "200", | |
| etherStatsUndersizePkts: "5", | |
| etherStatsFragments: "3", | |
| etherStatsCollisions: "0", | |
| etherStatsPkts65to127Octets: "400", | |
| etherStatsPkts256to511Octets: "100", | |
| etherStatsPkts1024to1518Octets: "50", | |
| etherStatsOctets: "150000", | |
| etherStatsBroadcastPkts: "300", | |
| etherStatsCRCAlignErrors: "2", | |
| etherStatsOversizePkts: "1", | |
| etherStatsJabbers: "0", | |
| etherStatsPkts64Octets: "500", | |
| etherStatsPkts128to255Octets: "200", | |
| etherStatsPkts512to1023Octets: "80" | |
| } | |
| }, | |
| { | |
| port: "2", | |
| index: "2", | |
| owner: "Admin2", | |
| stats: { | |
| etherStatsDropEvents: "15", | |
| etherStatsPkts: "1200", | |
| etherStatsMulticastPkts: "250", | |
| etherStatsUndersizePkts: "7", | |
| etherStatsFragments: "4", | |
| etherStatsCollisions: "1", | |
| etherStatsPkts65to127Octets: "450", | |
| etherStatsPkts256to511Octets: "120", | |
| etherStatsPkts1024to1518Octets: "60", | |
| etherStatsOctets: "180000", | |
| etherStatsBroadcastPkts: "350", | |
| etherStatsCRCAlignErrors: "3", | |
| etherStatsOversizePkts: "2", | |
| etherStatsJabbers: "1", | |
| etherStatsPkts64Octets: "550", | |
| etherStatsPkts128to255Octets: "220", | |
| etherStatsPkts512to1023Octets: "90" | |
| } | |
| } | |
| ]; | |
| const rmonHistoryData = [ | |
| { | |
| port: "1", | |
| index: "1", | |
| interval: "30", | |
| buckets: "50", | |
| owner: "Admin1", | |
| historyData: [ | |
| { index: "1", timeIntervalStart: "2025-08-01 10:00:00", dropEvents: "5", octets: "10000", pkts: "100", broadcastPkts: "20", multicastPkts: "10", crcAlignErrors: "1", undersizePkts: "2", oversizePkts: "0", fragments: "1", jabbers: "0", collisions: "0", utilization: "10" }, | |
| { index: "2", timeIntervalStart: "2025-08-01 10:30:00", dropEvents: "6", octets: "12000", pkts: "120", broadcastPkts: "25", multicastPkts: "12", crcAlignErrors: "2", undersizePkts: "3", oversizePkts: "1", fragments: "2", jabbers: "0", collisions: "1", utilization: "12" }, | |
| { index: "3", timeIntervalStart: "2025-08-01 11:00:00", dropEvents: "7", octets: "14000", pkts: "140", broadcastPkts: "30", multicastPkts: "15", crcAlignErrors: "3", undersizePkts: "4", oversizePkts: "2", fragments: "3", jabbers: "1", collisions: "2", utilization: "15" }, | |
| { index: "4", timeIntervalStart: "2025-08-01 11:30:00", dropEvents: "8", octets: "16000", pkts: "160", broadcastPkts: "35", multicastPkts: "18", crcAlignErrors: "4", undersizePkts: "5", oversizePkts: "3", fragments: "4", jabbers: "2", collisions: "3", utilization: "18" }, | |
| { index: "5", timeIntervalStart: "2025-08-01 12:00:00", dropEvents: "9", octets: "18000", pkts: "180", broadcastPkts: "40", multicastPkts: "20", crcAlignErrors: "5", undersizePkts: "6", oversizePkts: "4", fragments: "5", jabbers: "3", collisions: "4", utilization: "20" }, | |
| { index: "6", timeIntervalStart: "2025-08-01 12:30:00", dropEvents: "10", octets: "20000", pkts: "200", broadcastPkts: "45", multicastPkts: "22", crcAlignErrors: "6", undersizePkts: "7", oversizePkts: "5", fragments: "6", jabbers: "4", collisions: "5", utilization: "22" } | |
| ] | |
| }, | |
| { | |
| port: "2", | |
| index: "2", | |
| interval: "60", | |
| buckets: "100", | |
| owner: "Admin2", | |
| historyData: [ | |
| { index: "1", timeIntervalStart: "2025-08-01 10:00:00", dropEvents: "10", octets: "20000", pkts: "200", broadcastPkts: "40", multicastPkts: "20", crcAlignErrors: "2", undersizePkts: "4", oversizePkts: "1", fragments: "2", jabbers: "1", collisions: "1", utilization: "20" }, | |
| { index: "2", timeIntervalStart: "2025-08-01 11:00:00", dropEvents: "12", octets: "24000", pkts: "240", broadcastPkts: "48", multicastPkts: "24", crcAlignErrors: "3", undersizePkts: "5", oversizePkts: "2", fragments: "3", jabbers: "2", collisions: "2", utilization: "24" } | |
| ] | |
| } | |
| ]; | |
| const rmonAlarmData = [ | |
| { | |
| sequenceIndex: "1", | |
| interval: "30", | |
| variable: "etherStatsPkts", | |
| sampleType: "absolute", | |
| alarmValue: "1000", | |
| risingThreshold: "1500", | |
| fallingThreshold: "500", | |
| risingEventIndex: "1", | |
| fallingEventIndex: "2", | |
| owner: "Admin1" | |
| }, | |
| { | |
| sequenceIndex: "2", | |
| interval: "60", | |
| variable: "etherStatsOctets", | |
| sampleType: "delta", | |
| alarmValue: "200000", | |
| risingThreshold: "300000", | |
| fallingThreshold: "100000", | |
| risingEventIndex: "3", | |
| fallingEventIndex: "4", | |
| owner: "Admin2" | |
| } | |
| ]; | |
| const rmonEventData = [ | |
| { | |
| sequenceIndex: "1", | |
| index: "1", | |
| description: "High packet rate", | |
| type: "snmptrap", | |
| community: "public", | |
| lastTimeSent: "2025-08-01 10:00:00", | |
| owner: "Admin1" | |
| }, | |
| { | |
| sequenceIndex: "2", | |
| index: "2", | |
| description: "Low packet rate", | |
| type: "log", | |
| community: "private", | |
| lastTimeSent: "2025-08-01 11:00:00", | |
| owner: "Admin2" | |
| } | |
| ]; | |
| function isIndexUsed(index, excludeSequenceIndex = null) { | |
| return ( | |
| rmonStatisticsData.some(stat => stat.index === index) || | |
| rmonHistoryData.some(hist => hist.index === index) || | |
| rmonAlarmData.some(alarm => alarm.sequenceIndex === index && alarm.sequenceIndex !== excludeSequenceIndex) || | |
| rmonEventData.some(event => event.sequenceIndex === index && event.sequenceIndex !== excludeSequenceIndex) | |
| ); | |
| } | |
| // ERPS Configuration Data Structures | |
| let erpsConfig = { | |
| domain: "1", | |
| domainStatus: "Not Created", | |
| domainNodeRole: "none-interconnection", | |
| ring: "1", | |
| ringStatus: "Not Created", | |
| ringMode: "", | |
| nodeMode: "", | |
| rapsVlan: "0", | |
| trafficVlan: "", | |
| rplPort: "", | |
| rlPort: "", | |
| revertiveBehaviour: "revertive", | |
| holdOffTime: "0", | |
| guardTime: "0", | |
| wtrTime: "0", | |
| wtbTime: "0", | |
| rapsSendTime: "0", | |
| ringEnable: "disable", | |
| forcedSwitchRpl: "", | |
| forcedSwitchRl: "", | |
| manualSwitchPort: "" | |
| }; | |
| let erpsInfo = { | |
| domains: [ | |
| { | |
| domain: 1, | |
| instance: 1, | |
| nodeRole: "interconnection", | |
| rings: [ | |
| { | |
| ring: 1, | |
| ringMode: "none", | |
| rplPort: 0, | |
| rlPort: 0, | |
| revertiveBehaviour: "revertive", | |
| holdOffTime: "0ms", | |
| guardTime: "500ms", | |
| wtrTime: "5min", | |
| wtbTime: "5s", | |
| rapsSendTime: "5s", | |
| rapsVlan: 0, | |
| trafficVlanList: "none", | |
| enableState: "disable", | |
| nodeState: "init", | |
| portList: "none" | |
| } | |
| ] | |
| }, | |
| { | |
| domain: 2, | |
| instance: 2, | |
| nodeRole: "none-interconnection", | |
| rings: [ | |
| { | |
| ring: 1, | |
| ringMode: "none", | |
| rplPort: 0, | |
| rlPort: 0, | |
| revertiveBehaviour: "revertive", | |
| holdOffTime: "0ms", | |
| guardTime: "500ms", | |
| wtrTime: "5min", | |
| wtbTime: "5s", | |
| rapsSendTime: "5s", | |
| rapsVlan: 0, | |
| trafficVlanList: "none", | |
| enableState: "disable", | |
| nodeState: "init", | |
| portList: "none" | |
| } | |
| ] | |
| } | |
| ] | |
| }; | |
| // Dummy data for the MAC table | |
| const macAddressTable = [ | |
| { macAddress: '00:11:22:33:44:55', vlanId: 10, port: '1', static: true }, | |
| { macAddress: '66:77:88:99:AA:BB', vlanId: 20, port: '2', static: false }, | |
| { macAddress: 'CC:DD:EE:FF:00:11', vlanId: 30, port: '3', static: 1 }, | |
| { macAddress: '22:33:44:55:66:77', vlanId: 40, port: '1', static: 0 }, | |
| { macAddress: '88:99:AA:BB:CC:DD', vlanId: 4, port: '2', static: false }, | |
| { macAddress: 'FF:EE:DD:CC:BB:AA', vlanId: 50, port: '3', static: true }, | |
| // add more sample entries if needed | |
| ]; | |
| let macFilteredData = {}; | |
| // Mock MSTP port configurations | |
| let mstpGlobalConfig = { | |
| mstp: "enabled", | |
| priority: 32768, | |
| portfastBpduFilter: "disabled", | |
| portfastBpduGuard: "disabled", | |
| forwardTime: 15, | |
| helloTime: 2, | |
| errdisabledTimeout: 30, | |
| maxAge: 20, | |
| maxHops: 20, | |
| ciscoInteroperability: "disabled" | |
| }; | |
| let mstpPortConfigs = [ | |
| { | |
| port: "1", | |
| portFast: "Enabled", | |
| portfastBpduFilter: "Disabled", | |
| portfastBpduGuard: "Disabled", | |
| rootGuard: "Disabled", | |
| linkType: "Shared", | |
| priority: 128, | |
| pathCost: 20000, | |
| forceVersion: "MSTP" | |
| }, | |
| { | |
| port: "2", | |
| portFast: "Disabled", | |
| portfastBpduFilter: "Disabled", | |
| portfastBpduGuard: "Disabled", | |
| rootGuard: "Enabled", | |
| linkType: "point-to-point", | |
| priority: 64, | |
| pathCost: 10000, | |
| forceVersion: "RSTP" | |
| } | |
| ]; | |
| let staticRoutes = [ | |
| { | |
| "targetAddress": "192.168.1.0/24", | |
| "nextHop": "192.168.1.1", | |
| "distance": 1, | |
| "state": "Active" | |
| }, | |
| { | |
| "targetAddress": "10.0.0.0/16", | |
| "nextHop": "10.0.0.1", | |
| "distance": 5, | |
| "state": "Active" | |
| }, | |
| { | |
| "targetAddress": "172.16.0.0/12", | |
| "nextHop": "172.16.0.1", | |
| "distance": 10, | |
| "state": "Inactive" | |
| } | |
| ]; | |
| const trunkConfig = { | |
| trunkGroups: [ | |
| { id: '0001', created: false, memberPorts: [] }, | |
| { id: '0002', created: false, memberPorts: [] }, | |
| { id: '0003', created: false, memberPorts: [] }, | |
| { id: '0004', created: false, memberPorts: [] }, | |
| { id: '0005', created: false, memberPorts: [] }, | |
| { id: '0006', created: false, memberPorts: [] }, | |
| { id: '0007', created: false, memberPorts: [] }, | |
| { id: '0008', created: false, memberPorts: [] }, | |
| ], | |
| trunkMethod: ['src-mac', 'dst-mac', 'src-dst-mac', 'src-ip', 'src-dst-ip'], | |
| ablePorts: ['ge1/1', 'ge1/2', 'ge1/3', 'ge1/4', 'ge1/5', 'ge1/6', 'ge1/7', 'ge1/8', 'ge1/9', 'ge1/10'], | |
| }; | |
| // mirror port | |
| const mirrorPorts = [ | |
| "ge1/1", "ge1/2", "ge1/3", "ge1/4", "ge1/5", "ge1/6", | |
| "ge1/7", "ge1/8", "ge1/9", "ge1/10" | |
| ]; | |
| let savedMirrorConfig = [] | |
| let cableDiagnosis = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] | |
| let cableDiagnosisResult = []; | |
| let ntdpConfig = { | |
| port: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], // example ports | |
| selectedPort: "1", | |
| portEnable: 'Enabled', | |
| globalEnable: 'Enabled', | |
| interval: 30, | |
| hopsDelay: 5, | |
| portDelay: 5 | |
| }; | |
| let ndpConfig = { | |
| port: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], // example ports | |
| selectedPort: "1", | |
| portEnable: 'Enabled', | |
| globalEnable: 'Enabled', | |
| helloTime: 30, | |
| agingTime: 60 | |
| }; | |
| // --- Dummy storage (in-memory) --- | |
| let clusterConfig = { | |
| enable: "disable", | |
| mgmtVlan: 1, | |
| ipPool: "0.0.0.0/0", | |
| handshakeTime: 10, | |
| holdTime: 60 | |
| }; | |
| let clusterName = { | |
| name: "", | |
| type: "static" | |
| }; | |
| let clusterMembers = [ | |
| { serial: "001", mac: "AA:BB:CC:DD:EE:01", ip: "192.168.1.2", status: "Active", name: "Node1", role: "Leader" }, | |
| { serial: "002", mac: "AA:BB:CC:DD:EE:02", ip: "192.168.1.3", status: "Standby", name: "Node2", role: "Member" } | |
| ]; | |
| let poequeryConfigs = [ | |
| { | |
| port: '1', | |
| pdIpAddress: '192.168.1.10', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '2', | |
| pdIpAddress: '192.168.1.11', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '3', | |
| pdIpAddress: '192.168.1.12', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '4', | |
| pdIpAddress: '192.168.1.13', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '5', | |
| pdIpAddress: '192.168.1.14', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '6', | |
| pdIpAddress: '192.168.1.15', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '7', | |
| pdIpAddress: '192.168.1.16', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| { | |
| port: '8', | |
| pdIpAddress: '192.168.1.17', | |
| queryInterval: 5, | |
| timeoutNumber: 3, | |
| bootTime: 120, | |
| rebootTimes: 0, | |
| }, | |
| ]; | |
| let logs = [ | |
| { timestamp: '2025-07-26 10:00:00', priority: 'critical', message: 'System rebooted unexpectedly.' }, | |
| { timestamp: '2025-07-26 10:10:00', priority: 'info', message: 'Service started successfully.' }, | |
| { timestamp: '2025-07-26 10:20:00', priority: 'debug', message: 'Debug log message.' }, | |
| { timestamp: '2025-07-26 10:30:00', priority: 'warning', message: 'High memory usage detected.' } | |
| ]; | |
| let logInfo = { | |
| criticalCount: 100, criticalUsed: 35, | |
| warningCount: 150, warningUsed: 45, | |
| infoCount: 300, infoUsed: 120, | |
| debugCount: 200, debugUsed: 60 | |
| }; | |
| let logConfig = { | |
| syslog: 'enable', | |
| firstServerIp: '192.168.1.10', | |
| secondServerIp: '192.168.1.11', | |
| udp: 514, | |
| logLevel: 'info' | |
| }; | |
| let vlans = { | |
| 10: 'Marketing', | |
| 20: 'Sales', | |
| 30: 'Engineering' | |
| }; | |
| let poePolicyCongifs = { | |
| "1": { | |
| status: "disable", | |
| schedule: {} | |
| }, | |
| "2": { | |
| status: "enable", | |
| schedule: { | |
| "08-Monday": true, | |
| "09-Monday": true, | |
| "10-Monday": true, | |
| "14-Wednesday": true | |
| } | |
| }, | |
| "3": { | |
| status: "disable", | |
| schedule: {} | |
| }, | |
| "4": { | |
| status: "enable", | |
| schedule: { | |
| "08-Monday": true, | |
| "09-Monday": true, | |
| "10-Monday": true, | |
| "14-Wednesday": true | |
| } | |
| }, | |
| "5": { | |
| status: "disable", | |
| schedule: {} | |
| }, | |
| "6": { | |
| status: "enable", | |
| schedule: { | |
| "08-Monday": true, | |
| "09-Monday": true, | |
| "10-Monday": true, | |
| "14-Wednesday": true | |
| } | |
| }, | |
| "7": { | |
| status: "disable", | |
| schedule: {} | |
| }, | |
| "8": { | |
| status: "enable", | |
| schedule: { | |
| "08-Monday": true, | |
| "09-Monday": true, | |
| "10-Monday": true, | |
| "14-Wednesday": true | |
| } | |
| } | |
| }; | |
| let macBindings = []; | |
| let macAutoData = [ | |
| { macAddress: 'AA:BB:CC:DD:EE:01', vlanId: 10, port: '1' }, | |
| { macAddress: 'AA:BB:CC:DD:EE:02', vlanId: 20, port: '2' }, | |
| { macAddress: 'AA:BB:CC:DD:EE:03', vlanId: 30, port: '3' }, | |
| { macAddress: 'AA:BB:CC:DD:EE:04', vlanId: 10, port: '1' }, | |
| { macAddress: 'AA:BB:CC:DD:EE:05', vlanId: 20, port: '2' }, | |
| { macAddress: 'AA:BB:CC:DD:EE:06', vlanId: 30, port: '3' }, | |
| // Add more as needed | |
| ]; | |
| const ports = [ | |
| { | |
| id: "1", description: "Port 1", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 300, voltage: 48, power: 15, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 15, powerConsumption: 10, powerUsage: 12, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "2", description: "Port 2", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 250, voltage: 48, power: 12, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 12, powerConsumption: 9, powerUsage: 10, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "3", description: "Port 3", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 280, voltage: 48, power: 14, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 14, powerConsumption: 9, powerUsage: 11, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "4", description: "Port 4", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 260, voltage: 48, power: 13, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 13, powerConsumption: 8, powerUsage: 10, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "5", description: "Port 5", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 310, voltage: 48, power: 16, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 16, powerConsumption: 11, powerUsage: 13, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "6", description: "Port 6", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 270, voltage: 48, power: 14, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 14, powerConsumption: 9, powerUsage: 11, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "7", description: "Port 7", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 290, voltage: 48, power: 15, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 15, powerConsumption: 10, powerUsage: 12, pseHardwareVersion: "v1.0" | |
| }, | |
| { | |
| id: "8", description: "Port 8", type: "RJ45", mode: "automatic", adminStatus: "enabled", operation: "on", | |
| activePSEType: "af", passivePSEType: "af", current: 300, voltage: 48, power: 15, | |
| activeVoltage: 48, passiveVoltage: 48, totalPower: 15, powerConsumption: 10, powerUsage: 12, pseHardwareVersion: "v1.0" | |
| } | |
| ]; | |
| function isValidIp(ip) { | |
| const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/; | |
| if (!ipRegex.test(ip)) return false; | |
| return ip.split('.').every(octet => parseInt(octet) >= 0 && parseInt(octet) <= 255); | |
| } | |
| function isValidMac(mac) { | |
| const macRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/; | |
| return macRegex.test(mac); | |
| } | |
| // In-memory ARP table | |
| let arpTable = [ | |
| { ipAddress: '192.168.20.3', macAddress: 'a7e:e38:68e4', type: 'dynamic' }, | |
| { ipAddress: '192.168.20.34', macAddress: 'bc9:2f2:b14c', type: 'dynamic' }, | |
| { ipAddress: '192.168.20.125', macAddress: '3024:a42:1bb3', type: 'static' }, | |
| { ipAddress: '192.168.20.222', macAddress: 'b05c:dae7:af02', type: 'dynamic' } | |
| ]; | |
| function isValidMstpConfig(config) { | |
| const validBooleans = ["enabled", "disabled"]; | |
| const validLinkTypes = ["Shared", "point-to-point"]; | |
| const validForceVersions = ["STP", "nonSupported", "MSTP", "RSTP"]; | |
| return ( | |
| validBooleans.includes(config.mstp) && | |
| Number.isInteger(config.priority) && config.priority >= 0 && config.priority <= 61440 && | |
| validBooleans.includes(config.portfastBpduFilter) && | |
| validBooleans.includes(config.portfastBpduGuard) && | |
| Number.isInteger(config.forwardTime) && config.forwardTime >= 1 && | |
| Number.isInteger(config.helloTime) && config.helloTime >= 1 && config.helloTime <= 10 && | |
| Number.isInteger(config.errdisabledTimeout) && config.errdisabledTimeout >= 6 && config.errdisabledTimeout <= 40 && | |
| Number.isInteger(config.maxAge) && config.maxAge >= 4 && config.maxAge <= 30 && | |
| Number.isInteger(config.maxHops) && config.maxHops >= 4 && config.maxHops <= 30 && | |
| validBooleans.includes(config.ciscoInteroperability) | |
| ); | |
| } | |
| function isValidPortConfig(config) { | |
| const validBooleans = ["Enabled", "Disabled"]; | |
| const validLinkTypes = ["Shared", "point-to-point"]; | |
| const validForceVersions = ["STP", "nonSupported", "MSTP", "RSTP"]; | |
| return ( | |
| typeof config.port === "string" && config.port.trim() !== "" && | |
| validBooleans.includes(config.portFast) && | |
| validBooleans.includes(config.portfastBpduFilter) && | |
| validBooleans.includes(config.portfastBpduGuard) && | |
| validBooleans.includes(config.rootGuard) && | |
| validLinkTypes.includes(config.linkType) && | |
| Number.isInteger(config.priority) && config.priority >= 0 && config.priority <= 240 && | |
| Number.isInteger(config.pathCost) && config.pathCost >= 0 && | |
| validForceVersions.includes(config.forceVersion) | |
| ); | |
| } | |
| function isValidVid(vid) { | |
| return Number.isInteger(vid) && vid >= 1 && vid <= 4094; | |
| }; | |
| // Validate IP address with CIDR notation | |
| function isValidIpWithCidr(ip) { | |
| return /^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\/([1-9]|[1-2]\d|3[0-2])$/.test(ip); | |
| }; | |
| const vlanInterfaces = {}; | |
| // Middleware to check if VLAN exists | |
| function checkVlanExists(req, res, next) { | |
| const vlanId = req.body.vlanId || parseInt(req.params.vlanId); | |
| if (!vlanId || !vlans[vlanId]) { | |
| return res.status(400).json({ message: `VLAN ${vlanId} does not exist.` }); | |
| } | |
| next(); | |
| } | |
| function isIpAddressUnique(vlanId, ipAddress) { | |
| return !Object.entries(vlanInterfaces).some(([id, vlan]) => { | |
| return vlan.ipAddress === ipAddress && parseInt(id) !== vlanId; | |
| }); | |
| } | |
| const vports = Array.from({ length: 10 }, (_, i) => `${i + 1}`); | |
| const portMemberships = {}; | |
| // Initialize all ports with VLAN 10 as default ('p') | |
| vports.forEach(port => { | |
| portMemberships[port] = { '10': ['p', 'u'] }; | |
| }); | |
| function getLogStats() { | |
| const count = (priority) => logs.filter(l => l.priority === priority).length; | |
| return { | |
| criticalCount: 50, | |
| criticalUsed: count('critical'), | |
| warningCount: 50, | |
| warningUsed: count('warning'), | |
| infoCount: 100, | |
| infoUsed: count('info'), | |
| debugCount: 100, | |
| debugUsed: count('debug'), | |
| logs: logs | |
| }; | |
| } | |
| function isValidIPv4(ip) { | |
| const regex = /^(\d{1,3}\.){3}\d{1,3}$/; | |
| if (!regex.test(ip)) return false; | |
| return ip.split('.').every(octet => { | |
| const val = parseInt(octet, 10); | |
| return val >= 0 && val <= 255; | |
| }); | |
| } | |
| function isValidCIDR(cidr) { | |
| const regex = /^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/; | |
| if (!regex.test(cidr)) return false; | |
| const [ip, prefix] = cidr.split('/'); | |
| const prefixNum = parseInt(prefix, 10); | |
| return isValidIPv4(ip) && prefixNum >= 0 && prefixNum <= 32; | |
| } | |
| // Helper validation functions | |
| function validateIPAddress(ip) { | |
| // Regular expression for IPv4 validation | |
| const ipRegex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; | |
| return ipRegex.test(ip); | |
| } | |
| function validatePort(port) { | |
| // Port must be a number between 1-65535 | |
| const portNum = parseInt(port, 10); | |
| return !isNaN(portNum) && portNum >= 1 && portNum <= 65535; | |
| } | |
| function validatePositiveInteger(value) { | |
| const num = parseInt(value, 10); | |
| return !isNaN(num) && num >= 0 && Number.isInteger(num); | |
| } | |
| class MainServer { | |
| app = express(); | |
| port = 8443; | |
| init() { | |
| this.app.use(cors()); | |
| this.app.use(express.json()); | |
| this.app.use(express.urlencoded({ extended: true })); | |
| this.app.use(express.static('public')); | |
| this.setupRoutes(); | |
| } | |
| //////////////// GET ROUTES /////////////////// GET ROUTES //////////////////////////// GET ROUTES //////////////////////////////// | |
| setupRoutes() { | |
| this.app.get('/', (req, res) => { | |
| res.sendFile(__dirname + '/public/index.html'); | |
| }); | |
| this.app.get('/api/serial-config', (req, res) => { | |
| res.json(serialConfig); | |
| }); | |
| this.app.get('/api/system-config', (req, res) => { | |
| res.json(systemConfig); | |
| }); | |
| this.app.get('/api/industrial-status', (req, res) => { | |
| // Simulate dynamic updates to the data | |
| industrialStatusData.status = Math.random() > 0.1 ? "Online" : "Offline"; | |
| industrialStatusData.cpuUsage = Math.floor(Math.random() * 100); // 0-100% | |
| industrialStatusData.memoryUsage = Math.floor(Math.random() * 100); // 0-100% | |
| industrialStatusData.temperature = Math.floor(Math.random() * 50 + 20); // 20-70°C | |
| industrialStatusData.powerStatus = Math.random() > 0.2 ? "Normal" : "Warning"; | |
| industrialStatusData.ports = industrialStatusData.ports.map(port => ({ | |
| ...port, | |
| linkStatus: Math.random() > 0.2 ? "Up" : "Down", | |
| speed: Math.random() > 0.5 ? "1000Mbps" : "100Mbps", | |
| activity: Math.random() > 0.3 ? "Active" : "Idle" | |
| })); | |
| res.json(industrialStatusData); | |
| }); | |
| this.app.get('/api/port_stats', (req, res) => { | |
| res.json({ ports: availablePorts }); | |
| }); | |
| this.app.get('/api/storm-control', (req, res) => { | |
| res.json(stormData); | |
| }); | |
| this.app.get('/api/flow-control', (req, res) => { | |
| res.json(flowControlData); | |
| }); | |
| this.app.get('/api/protected-port', (req, res) => { | |
| res.json(protectedPortData); | |
| }); | |
| this.app.get('/api/jumbo-frame', (req, res) => { | |
| res.json({ frameSize: jumboFrameSize }); | |
| }); | |
| this.app.get('/api/port-rate-limit', (req, res) => { | |
| res.json(portRateLimits); | |
| }); | |
| this.app.get('/api/user-safety', (req, res) => { | |
| res.json(userSafetyConfig); | |
| }); | |
| this.app.get('/api/sntp-config', (req, res) => { | |
| res.json(sntpConfig); | |
| }); | |
| this.app.get('/api/learn-limit', (req, res) => { | |
| res.json(learnLimitData); | |
| }); | |
| this.app.get('/api/snmp-community', (req, res) => { | |
| res.json(snmpCommunityData); | |
| }); | |
| this.app.get('/api/snmp-versions', (req, res) => { | |
| res.json(snmpVersionData); | |
| }); | |
| this.app.get('/api/trap-targets', (req, res) => { | |
| res.json(trapTargetData); | |
| }); | |
| this.app.get('/api/qos-config', (req, res) => { | |
| res.json(qosData); | |
| }); | |
| this.app.get('/api/get_qos_schedule', (req, res) => { | |
| res.json(qosScheduleData); | |
| }); | |
| this.app.get('/api/aaa-authentication', (req, res) => { | |
| res.json(aaaAuthConfig); | |
| }); | |
| this.app.get('/api/tacacs-config', (req, res) => { | |
| res.json(tacacsConfig); | |
| }); | |
| this.app.get('/api/radius-config', (req, res) => { | |
| res.json(radiusConfig); | |
| }); | |
| this.app.get('/api/dot1x-config', (req, res) => { | |
| res.json(dot1xConfig); | |
| }); | |
| this.app.get('/api/dot1x-port-config', (req, res) => { | |
| res.json(dot1xPortConfig); | |
| }); | |
| this.app.get('/api/igmp-snooping-config', (req, res) => { | |
| res.json(igmpSnoopingConfig); | |
| }); | |
| this.app.get('/api/dot1x-user-auth', (req, res) => { | |
| const { port } = req.query; | |
| if (port) { | |
| const portNum = parseInt(port, 10); | |
| const portData = dot1xUserAuthData.find(p => p.port === portNum); | |
| if (!portData) { | |
| return res.status(404).json({ message: `Port ${port} not found` }); | |
| } | |
| return res.json(portData); | |
| } else { | |
| return res.json(dot1xUserAuthData); | |
| } | |
| }); | |
| this.app.get('/api/multicast-group-info', (req, res) => { | |
| res.json(multicastGroupInfo); | |
| }); | |
| this.app.get('/api/gmrp-global-config', (req, res) => { | |
| res.json(gmrpGlobalConfig); | |
| }); | |
| this.app.get('/api/gmrp-ports-config', (req, res) => { | |
| res.json({ ports: gmrpPortsConfig }); | |
| }); | |
| this.app.get('/api/gmrp-state-machine', (req, res) => { | |
| res.json(gmrpStateMachine); | |
| }); | |
| this.app.get('/api/gvrp-ports-config', (req, res) => { | |
| res.json({ ports: gvrpPortsConfig }); | |
| }); | |
| this.app.get('/api/gvrp-state-machine', (req, res) => { | |
| res.json(gvrpStateMachine); | |
| }); | |
| this.app.get('/api/eaps-config', (req, res) => { | |
| const { ringId } = req.query; | |
| if (ringId) { | |
| const config = eapsConfigs.find(r => r.eapsRingId === ringId); | |
| if (config) { | |
| return res.json(config); | |
| } | |
| return res.status(404).json({ message: 'EAPS Ring ID not found.' }); | |
| } | |
| res.json(eapsConfigs); | |
| }); | |
| this.app.get('/api/eaps-info', (req, res) => { | |
| res.json(eapsConfigs); | |
| }); | |
| this.app.get('/api/rmon-statistics', (req, res) => { | |
| const { port } = req.query; | |
| if (port) { | |
| const stats = rmonStatisticsData.find(item => item.port === port) || {}; | |
| res.json(stats); | |
| } else { | |
| res.json(rmonStatisticsData); | |
| } | |
| }); | |
| this.app.get('/api/rmon-history', (req, res) => { | |
| const { port, page = 1, limit = 5 } = req.query; | |
| const history = rmonHistoryData.find(item => item.port === port) || { historyData: [], totalPages: 0, currentPage: 1 }; | |
| const startIndex = (page - 1) * limit; | |
| const endIndex = startIndex + parseInt(limit); | |
| const paginatedData = history.historyData.slice(startIndex, endIndex); | |
| res.json({ | |
| ...history, | |
| historyData: paginatedData, | |
| totalPages: Math.ceil(history.historyData.length / limit), | |
| currentPage: parseInt(page) | |
| }); | |
| }); | |
| this.app.get('/api/rmon-alarm', (req, res) => { | |
| const { page = 1, limit = 5 } = req.query; | |
| const startIndex = (page - 1) * limit; | |
| const endIndex = startIndex + parseInt(limit); | |
| const paginatedData = rmonAlarmData.slice(startIndex, endIndex); | |
| res.json({ | |
| alarms: paginatedData, | |
| totalPages: Math.ceil(rmonAlarmData.length / limit), | |
| currentPage: parseInt(page) | |
| }); | |
| }); | |
| this.app.get('/api/rmon-event', (req, res) => { | |
| const { page = 1, limit = 5 } = req.query; | |
| const startIndex = (page - 1) * limit; | |
| const endIndex = startIndex + parseInt(limit); | |
| const paginatedData = rmonEventData.slice(startIndex, endIndex); | |
| res.json({ | |
| events: paginatedData, | |
| totalPages: Math.ceil(rmonEventData.length / limit), | |
| currentPage: parseInt(page) | |
| }); | |
| }); | |
| this.app.get('/api/erps-config', (req, res) => { | |
| res.json(erpsConfig); | |
| }); | |
| this.app.get('/api/erps-info', (req, res) => { | |
| res.json(erpsInfo); | |
| }); | |
| this.app.get('/api/acl-group', (req, res) => { | |
| res.json({ aclGroupNum }); | |
| }); | |
| this.app.get('/api/extended-port-options', (req, res) => { | |
| res.json({ | |
| protocolType, | |
| sourcePort, | |
| destinationPort | |
| }); | |
| }); | |
| this.app.get('/api/get-acl-standard-ip', (req, res) => { | |
| res.status(200).json(aclStandardIpEntries); | |
| }); | |
| this.app.get('/api/get-extended-ip', (req, res) => { | |
| return res.status(200).json(extendedAclEntries); | |
| }); | |
| this.app.get('/api/get-acl-mac-ip', (req, res) => { | |
| return res.status(200).json(aclMacIpEntries); | |
| }); | |
| this.app.get('/api/get-acl-mac-arp', (req, res) => { | |
| return res.status(200).json(macArpAclEntries); | |
| }); | |
| this.app.get('/api/port-trunking', (req, res) => { | |
| res.json(trunkConfig); | |
| }); | |
| this.app.get('/api/get-mirror-ports', (req, res) => { | |
| res.json(mirrorPorts); | |
| }); | |
| this.app.get('/api/get-mirror-config', (req, res) => { | |
| if (!savedMirrorConfig) { | |
| return res.status(404).json({ message: "No config applied yet" }); | |
| } | |
| res.json(savedMirrorConfig); | |
| }); | |
| this.app.get('/api/get-ddm-status', (req, res) => { | |
| const data = { | |
| interfaces: [ | |
| { | |
| name: "interface ge1/9:", | |
| status: "The interface ge1/9 hasn't optical module." | |
| }, | |
| { | |
| name: " interface ge1/10:", | |
| status: "The interface ge1/10 hasn't optical module." | |
| } | |
| ] | |
| }; | |
| res.json(data); | |
| }); | |
| this.app.get('/api/poe-config', (req, res) => { | |
| res.json(poequeryConfigs); | |
| }); | |
| this.app.get('/api/mac-address-table', (req, res) => { | |
| res.json(macAddressTable); | |
| }); | |
| this.app.get('/api/snmp-config', (req, res) => { | |
| res.json(macBindings); | |
| }); | |
| this.app.get('/api/mac-bind-table', (req, res) => { | |
| res.json(macBindings); | |
| }); | |
| this.app.get("/api/host-static-route", (req, res) => { | |
| res.json(staticRoutes); | |
| }); | |
| this.app.get('/api/cluster-config', (req, res) => { | |
| res.json(clusterConfig); | |
| }); | |
| this.app.get('/api/cluster-members', (req, res) => { | |
| res.json(clusterMembers); | |
| }); | |
| this.app.get('/api/vlans', (req, res) => { | |
| // Convert object to array of { vid, vlan_name } | |
| const vlanArray = Object.entries(vlans).map(([vid, vlan_name]) => ({ | |
| vid: parseInt(vid, 10), | |
| vlan_name | |
| })); | |
| res.json(vlanArray); | |
| }); | |
| this.app.get('/api/get-vlan-info', (req, res) => { | |
| const vlanArray = Object.entries(vlans).map(([vid, name]) => ({ | |
| vid: Number(vid), | |
| vlan_name: name, | |
| State: 'Active', | |
| Port_member: Object.entries(portMemberships) | |
| .filter(([port, memberships]) => memberships[vid]) | |
| .map(([port, memberships]) => `${port}[${memberships[vid].join('')}]`) | |
| .join(' ') | |
| })); | |
| res.json({ vlans: vlanArray }); | |
| }); | |
| // GET VLAN information (dummy) | |
| this.app.get('/api/get-vlan-information', (req, res) => { | |
| const { vid } = req.query; | |
| // Return empty response if no vid is selected | |
| if (!vid) { | |
| return res.json({ vlans: [] }); | |
| } | |
| const vlanEntries = Object.entries(vlans).filter(([v]) => v === vid); | |
| const vlanArray = vlanEntries.map(([v, name]) => ({ | |
| vid: Number(v), | |
| vlan_name: name, | |
| State: 'Active', | |
| Port_member: Object.entries(portMemberships) | |
| .filter(([port, memberships]) => memberships[v]) | |
| .map(([port, memberships]) => `${port}[${memberships[v].join('')}]`) | |
| .join(' ') | |
| })); | |
| res.json({ vlans: vlanArray }); | |
| }); | |
| this.app.get('/api/mac-auto-filter', (req, res) => { | |
| res.json(macAutoData); | |
| }); | |
| this.app.get('/api/get_vlan_ports/:port', (req, res) => { | |
| const port = req.params.port; | |
| const memberships = portMemberships[port]; | |
| if (!memberships) return res.status(404).json({ error: 'Port not found' }); | |
| res.json(memberships); | |
| }); | |
| this.app.get('/api/get_vlan_interfaces', (req, res) => { | |
| const vlanArray = Object.entries(vlanInterfaces).map(([vlanId, info]) => ({ | |
| vlanId: parseInt(vlanId, 10), | |
| ipAddress: info.ipAddress, | |
| dhcpEnabled: info.dhcpEnabled, | |
| macAddress: info.macAddress, | |
| })); | |
| res.json(vlanArray); | |
| }); | |
| this.app.get("/api/mstp-global-config", (req, res) => { | |
| try { | |
| res.json(mstpGlobalConfig); | |
| } catch (error) { | |
| console.error("Error fetching MSTP global config:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| this.app.get('/api/get-lldp-global', (req, res) => { | |
| return res.status(200).json(lldpGlobalConfig || {}); | |
| }); | |
| this.app.get('/api/get-lldp-port-table-data', (req, res) => { | |
| return res.status(200).json(lldpPortTableData); | |
| }); | |
| this.app.get('/api/get-lldp-port-config', (req, res) => { | |
| const port = req.query.port; | |
| console.log("port", port) | |
| if (!port) { | |
| return res.status(400).json({ message: "Port is required" }); | |
| } | |
| const entry = lldpPortTableData.find(item => item.port === port); | |
| if (!entry) { | |
| return res.status(404).json({ message: `Port ${port} not found` }); | |
| } | |
| return res.json(entry); | |
| }); | |
| this.app.get("/api/mstp-port-config", (req, res) => { | |
| try { | |
| res.json(mstpPortConfigs); | |
| } catch (error) { | |
| console.error("Error fetching MSTP port config:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| this.app.get("/api/mstp-port-information", (req, res) => { | |
| try { | |
| res.json(mstpPortConfigs); | |
| } catch (error) { | |
| console.error("Error fetching MSTP port information:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| this.app.get("/api/gvrp-port-config", (req, res) => { | |
| res.json(gvrpPorts); | |
| }); | |
| this.app.get('/api/gvrp-global-config', (req, res) => { | |
| res.json(gvrpGlobalConfig); | |
| }); | |
| this.app.get('/api/gvrp-state-machine', (req, res) => { | |
| res.json(gvrpStateMachine); | |
| }); | |
| this.app.get('/api/ntdp-config', (req, res) => { | |
| res.json(ntdpConfig); | |
| }); | |
| this.app.get('/api/ndp-config', (req, res) => { | |
| res.json(ndpConfig); | |
| }); | |
| this.app.get("/api/poe-port-config", (req, res) => { | |
| res.json({ ports }); | |
| }); | |
| this.app.get('/api/poe-policy-config', (req, res) => { | |
| const ports = Object.keys(poePolicyCongifs).map(port => ({ port })); | |
| res.json(ports); | |
| }); | |
| this.app.get('/api/poe-policy-config/:port', (req, res) => { | |
| const port = req.params.port; | |
| const config = poePolicyCongifs[port]; | |
| if (!config) { | |
| return res.status(404).json({ error: `Port '${port}' not found.` }); | |
| } | |
| res.json(config); | |
| }); | |
| this.app.get('/api/log-info', (req, res) => { | |
| res.json(getLogStats()); | |
| }); | |
| this.app.get('/api/log-config', (req, res) => { | |
| res.json(logConfig); | |
| }); | |
| this.app.get('/api/mac-auto-bind', (req, res) => { | |
| res.json(macAutoData); | |
| }); | |
| this.app.get('/api/get-cable-diagnosis', (req, res) => { | |
| res.json(cableDiagnosis); | |
| }); | |
| this.app.get("/api/get-cable-diagnosis-data", (req, res) => { | |
| if (!cableDiagnosisResult) { | |
| return res.status(404).json({ message: "No cable diagnosis result found" }); | |
| } | |
| res.json(cableDiagnosisResult); | |
| }); | |
| this.app.get('/api/mac-filter', (req, res) => { | |
| const { port } = req.query; | |
| if (port && port !== '0') { | |
| const entries = macFilteredData[port] || []; | |
| return res.json(entries); | |
| } | |
| // Combine all port data into a flat array with port info | |
| const allEntries = Object.entries(macFilteredData).flatMap(([port, entries]) => | |
| entries.map(entry => ({ ...entry, port })) | |
| ); | |
| res.json(allEntries); | |
| }); | |
| this.app.get('/api/arp-config-display', (req, res) => { | |
| res.json(arpTable); | |
| }); | |
| /////////// POST ROUTES //////////////////// POST ROUTES ////////////////////////// POST ROUTES //////////////////////////////////////// | |
| this.app.post('/api/add-acl-standard-ip', (req, res) => { | |
| const { groupNum, sourceIp, sourceWildcard, action } = req.body; | |
| console.log(req.body); | |
| if (!groupNum || !sourceIp || !sourceWildcard || !action) { | |
| return res.status(400).json({ message: 'Missing required fields' }); | |
| } | |
| const newEntry = { groupNum, sourceIp, sourceWildcard, action }; | |
| aclStandardIpEntries.push(newEntry); | |
| return res.status(200).json({ | |
| message: 'ACL group added successfully', | |
| data: newEntry | |
| }); | |
| }); | |
| this.app.post('/api/add-acl-extended-ip', (req, res) => { | |
| const { | |
| groupNum, | |
| protocolType, | |
| sourcePort, | |
| destinationPort, | |
| tcpFlags, | |
| sourceIp, | |
| sourceWildcard, | |
| destinationIp, | |
| destinationWildcard, | |
| action | |
| } = req.body; | |
| if (!groupNum || !protocolType || !sourceIp || !sourceWildcard || !destinationIp || !destinationWildcard || !action) { | |
| return res.status(400).json({ message: 'Missing required fields' }); | |
| } | |
| const newEntry = { | |
| groupNum, | |
| protocolType, | |
| sourcePort, | |
| destinationPort, | |
| tcpFlags, | |
| sourceIp, | |
| sourceWildcard, | |
| destinationIp, | |
| destinationWildcard, | |
| action | |
| }; | |
| extendedAclEntries.push(newEntry); | |
| return res.status(200).json({ | |
| message: 'Extended ACL added successfully', | |
| data: newEntry | |
| }); | |
| }) | |
| this.app.post('/api/add-acl-mac-ip', (req, res) => { | |
| const config = req.body; | |
| const { | |
| groupNumber, | |
| sourceMac, | |
| destinationIp, | |
| rule | |
| } = config; | |
| // Basic validation | |
| if (!groupNumber || !sourceMac || !destinationIp || !rule) { | |
| return res.status(400).json({ message: 'Missing required fields' }); | |
| } | |
| aclMacIpEntries.push(config); | |
| console.log("RaclMacIpEntries", aclMacIpEntries); | |
| res.json({ | |
| message: "ACL MAC IP configuration saved successfully.", | |
| data: config | |
| }); | |
| }); | |
| this.app.post('/api/add-acl-mac-arp', (req, res) => { | |
| const { | |
| groupNum, | |
| srcMac, | |
| srcMacWildcard, | |
| srcIp, | |
| srcIpWildcard, | |
| rule | |
| } = req.body; | |
| // Validate input | |
| if (!groupNum || !srcMac || !srcMacWildcard || !srcIp || !srcIpWildcard || !rule) { | |
| return res.status(400).json({ message: 'Missing required fields' }); | |
| } | |
| const newEntry = { | |
| groupNum, | |
| srcMac, | |
| srcMacWildcard, | |
| srcIp, | |
| srcIpWildcard, | |
| rule | |
| }; | |
| macArpAclEntries.push(newEntry); | |
| return res.status(200).json({ | |
| message: 'MAC ARP ACL entry added successfully', | |
| data: newEntry | |
| }); | |
| }); | |
| this.app.post('/api/qos-config', (req, res) => { | |
| const { port, qosType, priority } = req.body; | |
| const portNum = parseInt(port); | |
| const priorityVal = parseInt(priority); | |
| if (isNaN(portNum) || portNum < 1 || portNum > 10) { | |
| return res.status(400).json({ message: "Invalid port number." }); | |
| } | |
| if (isNaN(priorityVal) || priorityVal < 0 || priorityVal > 7) { | |
| return res.status(400).json({ message: "Priority must be between 0 and 7." }); | |
| } | |
| const validQoSTypes = [ | |
| "NO QOS", "COS based", "DSCP based", "DSCP/COS based" | |
| ]; | |
| if (!validQoSTypes.includes(qosType)) { | |
| return res.status(400).json({ message: "Invalid QoS type." }); | |
| } | |
| const index = qosData.findIndex(item => item.port === portNum); | |
| if (index !== -1) { | |
| qosData[index] = { port: portNum, qosType, priority: priorityVal }; | |
| console.log(`QoS updated on port ${portNum}:`, qosData[index]); | |
| return res.json({ message: `QoS updated for port ${portNum}.` }); | |
| } else { | |
| return res.status(404).json({ message: `Port ${portNum} not found.` }); | |
| } | |
| }); | |
| this.app.post("/api/set-trunk-method", (req, res) => { | |
| const { method } = req.body; | |
| if (!method) return res.status(400).json({ message: "Trunk method is required" }); | |
| return res.json({ message: "Trunk method set successfully" }); | |
| }); | |
| this.app.post("/api/create-trunk-group", (req, res) => { | |
| const { id } = req.body; | |
| const group = trunkConfig.trunkGroups.find(g => g.id === id); | |
| if (!id || !group) return res.status(404).json({ message: "Invalid trunk group ID" }); | |
| group.created = true; | |
| res.json({ message: `Trunk group ${id} created.` }); | |
| }); | |
| this.app.post("/api/add-member-port", (req, res) => { | |
| const { groupId, ports } = req.body; | |
| const group = trunkConfig.trunkGroups.find(g => g.id === groupId && g.created); | |
| if (!group || !Array.isArray(ports)) return res.status(400).json({ message: "Invalid group or ports" }); | |
| ports.forEach(p => { | |
| if (!group.memberPorts.includes(p)) group.memberPorts.push(p); | |
| }); | |
| trunkConfig.ablePorts = trunkConfig.ablePorts.filter(p => !ports.includes(p)); | |
| res.json({ message: "Ports added to trunk group." }); | |
| }); | |
| this.app.post("/api/remove-member-port", (req, res) => { | |
| const { groupId, ports } = req.body; | |
| const group = trunkConfig.trunkGroups.find(g => g.id === groupId && g.created); | |
| if (!group || !Array.isArray(ports)) return res.status(400).json({ message: "Invalid group or ports" }); | |
| group.memberPorts = group.memberPorts.filter(p => !ports.includes(p)); | |
| ports.forEach(p => { if (!trunkConfig.ablePorts.includes(p)) trunkConfig.ablePorts.push(p); }); | |
| res.json({ message: "Ports removed from trunk group." }); | |
| }); | |
| this.app.post("/api/delete-trunk-group", (req, res) => { | |
| const { id } = req.body; | |
| const group = trunkConfig.trunkGroups.find(g => g.id === id && g.created); | |
| if (!group) return res.status(404).json({ message: "Trunk group not found or not created." }); | |
| trunkConfig.ablePorts.push(...group.memberPorts.filter(p => !trunkConfig.ablePorts.includes(p))); | |
| group.created = false; | |
| group.memberPorts = []; | |
| res.json({ message: `Trunk group ${id} deleted.` }); | |
| }); | |
| this.app.post('/api/apply-mirror-config', (req, res) => { | |
| const { mirrorPort, mirroredPorts, mirrorDirection } = req.body; | |
| if (!mirrorPort || !mirroredPorts || !mirrorDirection) { | |
| return res.status(400).json({ message: "Missing required fields" }); | |
| } | |
| savedMirrorConfig = { | |
| mirrorPort, | |
| mirroredPorts, | |
| mirrorDirection, | |
| }; | |
| res.json({ message: "Mirror configuration applied", config: savedMirrorConfig }); | |
| }); | |
| this.app.post('/api/log-config', (req, res) => { | |
| const { syslog, firstServerIp, secondServerIp, udp, logLevel } = req.body; | |
| if (!syslog || !firstServerIp || !udp || !logLevel) { | |
| return res.status(400).json({ error: 'Missing required fields.' }); | |
| } | |
| logConfig = { | |
| syslog, | |
| firstServerIp, | |
| secondServerIp: secondServerIp || '', | |
| udp, | |
| logLevel | |
| }; | |
| res.json({ message: 'Log configuration updated.' }); | |
| }); | |
| this.app.post('/api/log-info/clear', (req, res) => { | |
| logs = []; | |
| res.json({ message: 'Logs cleared' }); | |
| }); | |
| this.app.post('/api/ndp-config', (req, res) => { | |
| const { port, portEnable, globalEnable, helloTime, agingTime } = req.body; | |
| if (!port || !portEnable || !globalEnable || !helloTime || !agingTime) { | |
| return res.status(400).json({ error: 'Missing required fields' }); | |
| } | |
| if (!ndpConfig.port.includes(port)) { | |
| return res.status(400).json({ error: 'Invalid port selected' }); | |
| } | |
| // Update config | |
| ndpConfig.portEnable = portEnable; | |
| ndpConfig.selectedPort = port; // ✅ ← Fix: use selected port from frontend | |
| ndpConfig.globalEnable = globalEnable; | |
| ndpConfig.helloTime = Number(helloTime); | |
| ndpConfig.agingTime = Number(agingTime); | |
| res.json({ message: 'NDP configuration updated successfully' }); | |
| }); | |
| this.app.post('/api/ntdp-config', (req, res) => { | |
| const { port, portEnable, globalEnable, interval, hopsDelay, portDelay } = req.body; | |
| // Validate required fields | |
| if (!port || !portEnable || !globalEnable || !interval || !hopsDelay || !portDelay) { | |
| return res.status(400).json({ error: 'Missing required fields' }); | |
| } | |
| if (!ntdpConfig.port.includes(port)) { | |
| return res.status(400).json({ error: 'Invalid port selected' }); | |
| } | |
| // Apply config | |
| ntdpConfig.portEnable = portEnable; | |
| ntdpConfig.selectedPort = port; // ✅ Set selectedPort from submitted port | |
| ntdpConfig.globalEnable = globalEnable; | |
| ntdpConfig.interval = Number(interval); | |
| ntdpConfig.hopsDelay = Number(hopsDelay); | |
| ntdpConfig.portDelay = Number(portDelay); | |
| res.json({ message: 'NTDPS configuration updated successfully' }); | |
| }); | |
| this.app.post("/api/gvrp-port-config", (req, res) => { | |
| const { port, gvrpStatus } = req.body; | |
| if (!port || !gvrpStatus) { | |
| return res.status(400).json({ error: "Missing port or gvrpStatus" }); | |
| } | |
| // Update if exists, else add new | |
| const existing = gvrpPorts.find(p => p.port === port); | |
| if (existing) { | |
| existing.gvrpStatus = gvrpStatus; | |
| } else { | |
| gvrpPorts.push({ | |
| port, | |
| gvrpStatus, | |
| jointime: 30, | |
| leavetime: 60, | |
| leavealltimer: 90 | |
| }); | |
| } | |
| res.json({ message: `GVRP config applied for ${port}`, config: req.body }); | |
| }); | |
| this.app.post('/api/poe-config', (req, res) => { | |
| const { port, pdIpAddress, queryInterval, timeoutNumber, bootTime } = req.body; | |
| if (!port) { | |
| return res.status(400).json({ error: 'PoE port is required' }); | |
| } | |
| // Find existing config by port | |
| const existingIndex = poequeryConfigs.findIndex((c) => c.port === port); | |
| if (existingIndex !== -1) { | |
| // Update existing config | |
| poequeryConfigs[existingIndex] = { | |
| ...poequeryConfigs[existingIndex], | |
| pdIpAddress, | |
| queryInterval, | |
| timeoutNumber, | |
| bootTime, | |
| // rebootTimes is kept as-is or reset? Here keep as-is | |
| }; | |
| } else { | |
| // Add new config with rebootTimes = 0 | |
| poequeryConfigs.push({ | |
| port, | |
| pdIpAddress, | |
| queryInterval, | |
| timeoutNumber, | |
| bootTime, | |
| rebootTimes: 0, | |
| }); | |
| } | |
| return res.status(200).json({ message: 'Configuration saved successfully' }); | |
| }); | |
| this.app.post("/api/poe-port-config/apply-settings", (req, res) => { | |
| const { ports: selectedPorts, config } = req.body; | |
| if (!selectedPorts || !Array.isArray(selectedPorts) || selectedPorts.length === 0) { | |
| return res.status(400).json({ error: "No ports selected" }); | |
| } | |
| if (!config) { | |
| return res.status(400).json({ error: "No config provided" }); | |
| } | |
| selectedPorts.forEach(portId => { | |
| const port = ports.find(p => p.id === portId); | |
| if (port) { | |
| // Update only the keys that exist in config | |
| if (config.mode !== undefined) port.mode = config.mode; | |
| if (config.adminStatus !== undefined) port.adminStatus = config.adminStatus; | |
| if (config.activePSEType !== undefined) port.activePSEType = config.activePSEType; | |
| if (config.passivePSEType !== undefined) port.passivePSEType = config.passivePSEType; | |
| if (config.activeVoltage !== undefined) port.activeVoltage = config.activeVoltage; | |
| if (config.passiveVoltage !== undefined) port.passiveVoltage = config.passiveVoltage; | |
| if (config.totalPower !== undefined) port.totalPower = config.totalPower; | |
| // Simulate related fields recalculation | |
| port.powerConsumption = Math.round(port.totalPower * 0.6); | |
| port.powerUsage = Math.round(port.totalPower * 0.8); | |
| } | |
| }); | |
| // Return the updated ports so frontend can refresh display | |
| res.json({ message: "Configuration applied", ports }); | |
| }); | |
| this.app.post("/api/poe-port-config/restore-defaults", (req, res) => { | |
| const { ports: selectedPorts } = req.body; | |
| if (!selectedPorts || !Array.isArray(selectedPorts) || selectedPorts.length === 0) { | |
| return res.status(400).json({ error: "No ports selected" }); | |
| } | |
| selectedPorts.forEach(portId => { | |
| const port = ports.find(p => p.id === portId); | |
| if (port) { | |
| // Restore to default values (example defaults) | |
| port.mode = "automatic"; | |
| port.adminStatus = "enabled"; | |
| port.activePSEType = "af"; | |
| port.passivePSEType = "af"; | |
| port.activeVoltage = 48; | |
| port.passiveVoltage = 48; | |
| port.totalPower = 15; | |
| port.powerConsumption = 10; | |
| port.powerUsage = 12; | |
| port.operation = "on"; | |
| } | |
| }); | |
| res.json({ message: "Defaults restored", restoredPorts: selectedPorts }); | |
| }); | |
| this.app.post("/api/poe-port-restart", (req, res) => { | |
| const { ports: selectedPorts } = req.body; | |
| if (!selectedPorts || !Array.isArray(selectedPorts) || selectedPorts.length === 0) { | |
| return res.status(400).json({ error: "No ports selected" }); | |
| } | |
| // Simulate restart operation - here just respond after a delay (could add async tasks) | |
| setTimeout(() => { | |
| res.json({ message: "Ports restarted", restartedPorts: selectedPorts }); | |
| }, 2000); // simulate 2 seconds restart delay | |
| }); | |
| this.app.post('/api/cluster-config', (req, res) => { | |
| const { enable, mgmtVlan, ipPool, handshakeTime, holdTime } = req.body; | |
| clusterConfig = { | |
| enable, | |
| mgmtVlan, | |
| ipPool, | |
| handshakeTime, | |
| holdTime | |
| }; | |
| console.log("Updated cluster config:", clusterConfig); | |
| res.json({ status: 'success', updated: clusterConfig }); | |
| }); | |
| this.app.post('/api/cluster-name', (req, res) => { | |
| const { name, type } = req.body; | |
| clusterName = { name, type }; | |
| console.log("Updated cluster name:", clusterName); | |
| res.json({ status: 'success', clusterName }); | |
| }); | |
| this.app.post('/api/flow-control', (req, res) => { | |
| const { port, state } = req.body; | |
| const entry = flowControlData.find(e => e.port === port); | |
| if (!entry) return res.status(404).json({ message: `Port ${port} not found` }); | |
| if (!['On', 'Off'].includes(state)) return res.status(400).json({ message: `Invalid state: ${state}` }); | |
| entry.state = state; | |
| console.log(`Flow control for ${port} set to ${state}`); | |
| res.json({ message: `Flow control for ${port} updated to ${state}` }); | |
| }); | |
| this.app.post('/api/storm-control', (req, res) => { | |
| const { port, broadcastSuppression, broadcastRate, multicastSuppression, multicastRate, dlfSuppression, dlfRate } = req.body; | |
| const entry = stormData.find(p => p.port === port); | |
| if (!entry) return res.status(404).json({ message: `Port ${port} not found` }); | |
| entry.broadcastSuppression = broadcastSuppression; | |
| entry.broadcastRate = broadcastRate; | |
| entry.multicastSuppression = multicastSuppression; | |
| entry.multicastRate = multicastRate; | |
| entry.dlfSuppression = dlfSuppression; | |
| entry.dlfRate = dlfRate; | |
| console.log(`Updated storm control for ${port}`); | |
| res.json({ message: `Storm control updated for ${port}` }); | |
| }); | |
| this.app.post('/api/system-config', (req, res) => { | |
| const { systemName, systemLocation, systemContact } = req.body; | |
| systemConfig.systemName = systemName; | |
| systemConfig.systemLocation = systemLocation; | |
| systemConfig.systemContact = systemContact; | |
| res.json({ message: 'Config saved successfully' }); | |
| }); | |
| this.app.post('/api/reboot', (req, res) => { | |
| console.log('Reboot request received.'); | |
| res.json({ message: 'Simulated: Switch is rebooting...' }); | |
| }); | |
| this.app.post('/api/factory-reset', (req, res) => { | |
| console.log('Factory reset request received.'); | |
| res.json({ message: 'Simulated: Factory reset in progress...' }); | |
| }); | |
| this.app.post('/api/protected-port', (req, res) => { | |
| const { protectedPorts } = req.body; | |
| protectedPortData.forEach(port => { | |
| port.protected = protectedPorts.includes(port.port); | |
| }); | |
| console.log(`Protected ports updated: ${protectedPorts.join(', ')}`); | |
| res.json({ message: 'Protected port settings applied successfully' }); | |
| }); | |
| this.app.post('/api/jumbo-frame', (req, res) => { | |
| const { frameSize } = req.body; | |
| if (typeof frameSize !== 'number' || frameSize < 1522 || frameSize > 16283) { | |
| return res.status(400).json({ message: 'Invalid frame size. Must be between 1522 and 16283.' }); | |
| } | |
| jumboFrameSize = frameSize; | |
| res.json({ message: 'Jumbo Frame size updated successfully.' }); | |
| }); | |
| this.app.post('/api/port-rate-limit', (req, res) => { | |
| const { port, egressRate, ingressRate } = req.body; | |
| const index = portRateLimits.findIndex(p => p.port === port); | |
| if (index !== -1) { | |
| portRateLimits[index] = { port, egressRate, ingressRate }; | |
| res.json({ message: 'Port rate limit updated successfully.' }); | |
| } else { | |
| res.status(400).json({ error: 'Invalid port' }); | |
| } | |
| }); | |
| this.app.post('/api/user-safety', (req, res) => { | |
| const { serviceType, managementState, aclGroup } = req.body; | |
| const index = userSafetyConfig.findIndex(item => item.serviceType === serviceType); | |
| if (index === -1) return res.status(400).json({ error: 'Invalid service type' }); | |
| userSafetyConfig[index] = { serviceType, managementState, aclGroup }; | |
| console.log(`Updated ${serviceType} config:`, userSafetyConfig[index]); | |
| res.json({ message: `Updated ${serviceType} configuration.` }); | |
| }); | |
| this.app.post('/api/add-lldp-global', (req, res) => { | |
| const { lldpGlobal, holdMultiplier, reinitDelay, txDelay, txInterval } = req.body; | |
| // Basic validation | |
| if ( | |
| lldpGlobal === undefined || | |
| !holdMultiplier || | |
| !reinitDelay || | |
| !txDelay || | |
| !txInterval | |
| ) { | |
| return res.status(400).json({ error: 'All fields are required' }); | |
| } | |
| lldpGlobalConfig = { | |
| lldpGlobal, | |
| holdMultiplier, | |
| reinitDelay, | |
| txDelay, | |
| txInterval | |
| }; | |
| return res.status(200).json({ message: 'LLDP Global settings saved successfully!' }); | |
| }); | |
| this.app.post("/api/apply-lldp-port-config", (req, res) => { | |
| const { port, ...newData } = req.body; | |
| const portEntry = lldpPortTableData.find(item => item.port === port); | |
| if (!portEntry) { | |
| return res.status(404).json({ message: "Port not found" }); | |
| } | |
| // Update existing port data | |
| Object.assign(portEntry, newData); | |
| res.json({ message: "Port updated successfully", data: portEntry }); | |
| }); | |
| this.app.post('/api/sntp-config', (req, res) => { | |
| const { ipAddress1, ipAddress2, ipAddress3, timeInterval, timeZone, dstStatus, dstStartTime, dstEndTime, dstBias, enableStatus, systemDateTime } = req.body; | |
| if (isNaN(timeInterval) || timeInterval < 1) return res.status(400).json({ message: 'Invalid Time Interval.' }); | |
| if (isNaN(dstBias) || dstBias < 0 || dstBias > 99) return res.status(400).json({ message: 'DST Bias must be between 0 and 99.' }); | |
| sntpConfig = { ipAddress1, ipAddress2, ipAddress3, timeInterval, timeZone, dstStatus, dstStartTime, dstEndTime, dstBias, enableStatus, systemDateTime }; | |
| res.json({ message: 'SNTP configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/snmp-community', (req, res) => { | |
| const { communityName, accessType } = req.body; | |
| if (!communityName || !accessType) return res.status(400).json({ message: 'Community name and access type are required.' }); | |
| if (!['Read/Write', 'Read Only'].includes(accessType)) return res.status(400).json({ message: 'Invalid access type. Must be Read/Write or Read Only.' }); | |
| if (snmpCommunityData.some(item => item.communityName === communityName)) return res.status(400).json({ message: 'Community name already exists.' }); | |
| const state = new Date().getHours() >= 8 && new Date().getHours() < 18 ? "Active" : "Inactive"; | |
| snmpCommunityData.push({ communityName, accessType, state }); | |
| console.log(`Added SNMP community: ${communityName} with state ${state}`); | |
| res.json({ message: 'SNMP community name added successfully.' }); | |
| }); | |
| this.app.post('/api/trap-targets', (req, res) => { | |
| const { trapIp, trapCommunity, trapVersion } = req.body; | |
| if (!trapIp || !trapCommunity || !trapVersion) return res.status(400).json({ message: 'IP address, community, and version are required.' }); | |
| if (!/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(trapIp)) { | |
| return res.status(400).json({ message: 'Invalid IP address format.' }); | |
| } | |
| if (!['v1', 'v2c', 'v3'].includes(trapVersion)) return res.status(400).json({ message: 'Invalid version. Must be v1, v2c, or v3.' }); | |
| if (trapTargetData.some(item => item.trapIp === trapIp)) return res.status(400).json({ message: 'IP address already exists.' }); | |
| const state = new Date().getHours() >= 8 && new Date().getHours() < 18 ? "Active" : "Inactive"; | |
| trapTargetData.push({ trapIp, trapCommunity, trapVersion, state }); | |
| console.log(`Added trap target: ${trapIp} with community ${trapCommunity}, version ${trapVersion}, and state ${state}`); | |
| res.json({ message: 'Trap target added successfully.' }); | |
| }); | |
| this.app.post('/api/learn-limit', (req, res) => { | |
| const { port, macLimit, cancel } = req.body; | |
| const entry = learnLimitData.find(p => parseInt(p.port) === parseInt(port)); | |
| if (!entry) return res.status(404).json({ message: `Port ${port} not found` }); | |
| if (cancel) { | |
| entry.macLimit = 8191; | |
| console.log(`Reverted MAC limit for port ${port} to 8191`); | |
| return res.json({ message: `Learn limit for port ${port} reverted to default (8191).` }); | |
| } | |
| if (isNaN(macLimit) || macLimit < 0 || macLimit > 8191) { | |
| return res.status(400).json({ message: 'MAC Limit must be between 0 and 8191.' }); | |
| } | |
| entry.macLimit = macLimit; | |
| console.log(`Updated MAC limit for port ${port} to ${macLimit}`); | |
| res.json({ message: `Learn limit for port ${port} updated to ${macLimit}.` }); | |
| }); | |
| this.app.post("/api/mstp-global-config", (req, res) => { | |
| try { | |
| const config = req.body; | |
| if (!isValidMstpConfig(config)) { | |
| return res.status(400).json({ error: "Invalid MSTP global configuration parameters" }); | |
| } | |
| mstpGlobalConfig = { ...config }; | |
| console.log("MSTP global configuration updated:", mstpGlobalConfig); | |
| res.json({ message: "MSTP global configuration updated successfully", config: mstpGlobalConfig }); | |
| } catch (error) { | |
| console.error("Error updating MSTP global config:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| this.app.post("/api/mstp-port-config", (req, res) => { | |
| try { | |
| const config = req.body; | |
| if (!isValidPortConfig(config)) { | |
| return res.status(400).json({ error: "Invalid MSTP port configuration parameters" }); | |
| } | |
| const index = mstpPortConfigs.findIndex(p => p.port === config.port); | |
| if (index === -1) { | |
| mstpPortConfigs.push(config); | |
| } else { | |
| mstpPortConfigs[index] = { ...config }; | |
| } | |
| console.log(`MSTP Port ${config.port} configuration updated:, ${config}`); | |
| res.json({ message: "MSTP port configuration updated successfully" }); | |
| } catch (error) { | |
| console.error("Error updating MSTP port config:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| this.app.post('/api/set_qos_schedule', (req, res) => { | |
| const { port, mode, weights } = req.body; | |
| if (!port || !mode || !Array.isArray(weights) || weights.length !== 8) { | |
| return res.status(400).json({ message: "Invalid request body" }); | |
| } | |
| const index = qosScheduleData.findIndex(p => p.port === port); | |
| if (index === -1) { | |
| return res.status(404).json({ message: "Port not found" }); | |
| } | |
| qosScheduleData[index] = { port, mode, weights }; | |
| res.json({ message: "QoS schedule updated successfully" }); | |
| }); | |
| this.app.post('/api/aaa-authentication', (req, res) => { | |
| const { authType } = req.body; | |
| if (!authType || !['local', 'tacacs', 'radius', 'none'].includes(authType)) { | |
| return res.status(400).json({ message: 'Invalid authentication type. Must be local, tacacs, radius, or none.' }); | |
| } | |
| aaaAuthConfig.authType = authType; | |
| console.log(`AAA Authentication type updated to: ${authType}`); | |
| res.json({ message: 'AAA Authentication configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/tacacs-config', (req, res) => { | |
| const { serverIP, optionServerIP, authType, sharedSecret, authorization, accounting } = req.body; | |
| if (!serverIP || !optionServerIP || !authType || !authorization || !accounting) { | |
| return res.status(400).json({ message: 'All fields are required except shared secret.' }); | |
| } | |
| // Validate IP addresses | |
| if (!validateIPAddress(serverIP)) { | |
| return res.status(400).json({ message: 'Invalid Server IP address format. Please use format: xxx.xxx.xxx.xxx' }); | |
| } | |
| if (!validateIPAddress(optionServerIP)) { | |
| return res.status(400).json({ message: 'Invalid Option Server IP address format. Please use format: xxx.xxx.xxx.xxx' }); | |
| } | |
| if (!['pap', 'ascii', 'chap'].includes(authType)) { | |
| return res.status(400).json({ message: 'Invalid authentication type. Must be pap, ascii, or chap.' }); | |
| } | |
| if (!['enable', 'disable'].includes(authorization) || !['enable', 'disable'].includes(accounting)) { | |
| return res.status(400).json({ message: 'Authorization and accounting must be enable or disable.' }); | |
| } | |
| tacacsConfig.serverIP = serverIP; | |
| tacacsConfig.optionServerIP = optionServerIP; | |
| tacacsConfig.authType = authType; | |
| tacacsConfig.sharedSecret = sharedSecret || ""; | |
| tacacsConfig.authorization = authorization; | |
| tacacsConfig.accounting = accounting; | |
| console.log(`TACACS+ configuration updated: Server IP: ${serverIP}, Auth Type: ${authType}`); | |
| res.json({ message: 'TACACS+ configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/radius-config', (req, res) => { | |
| const { primaryServer, optionServer, udpPort, accounting, accountingUDPPort, sharedKey, vendor, nasPort, nasPortType, nasServiceType, roaming } = req.body; | |
| if (!primaryServer || !optionServer || !udpPort || !accounting || !accountingUDPPort || !nasPort || !nasPortType || !nasServiceType || !roaming) { | |
| return res.status(400).json({ message: 'All fields are required except shared key and vendor.' }); | |
| } | |
| // Validate IP addresses | |
| if (!validateIPAddress(primaryServer)) { | |
| return res.status(400).json({ message: 'Invalid Primary Server IP address format. Please use format: xxx.xxx.xxx.xxx' }); | |
| } | |
| if (!validateIPAddress(optionServer)) { | |
| return res.status(400).json({ message: 'Invalid Option Server IP address format. Please use format: xxx.xxx.xxx.xxx' }); | |
| } | |
| // Validate ports | |
| if (!validatePort(udpPort)) { | |
| return res.status(400).json({ message: 'Invalid UDP Port. Port must be a number between 1-65535.' }); | |
| } | |
| if (!validatePort(accountingUDPPort)) { | |
| return res.status(400).json({ message: 'Invalid Accounting UDP Port. Port must be a number between 1-65535.' }); | |
| } | |
| // Validate NAS port and types | |
| if (!validatePositiveInteger(nasPort)) { | |
| return res.status(400).json({ message: 'Invalid NAS Port. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(nasPortType)) { | |
| return res.status(400).json({ message: 'Invalid NAS Port Type. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(nasServiceType)) { | |
| return res.status(400).json({ message: 'Invalid NAS Service Type. Must be a positive integer.' }); | |
| } | |
| if (!['enable', 'disable'].includes(accounting) || !['enable', 'disable'].includes(roaming)) { | |
| return res.status(400).json({ message: 'Accounting and roaming must be enable or disable.' }); | |
| } | |
| radiusConfig.primaryServer = primaryServer; | |
| radiusConfig.optionServer = optionServer; | |
| radiusConfig.udpPort = udpPort; | |
| radiusConfig.accounting = accounting; | |
| radiusConfig.accountingUDPPort = accountingUDPPort; | |
| radiusConfig.sharedKey = sharedKey || ""; | |
| radiusConfig.vendor = vendor || ""; | |
| radiusConfig.nasPort = nasPort; | |
| radiusConfig.nasPortType = nasPortType; | |
| radiusConfig.nasServiceType = nasServiceType; | |
| radiusConfig.roaming = roaming; | |
| console.log(`RADIUS configuration updated: Primary Server: ${primaryServer}, Accounting: ${accounting}`); | |
| res.json({ message: 'RADIUS configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/dot1x-config', (req, res) => { | |
| const { enable, reauth, reauthPeriod, quietPeriod, txPeriod, serverTimeout, supplicantTimeout, maxRequest, reauthMax } = req.body; | |
| if (!enable || !reauth || !reauthPeriod || !quietPeriod || !txPeriod || !serverTimeout || !supplicantTimeout || !maxRequest || !reauthMax) { | |
| return res.status(400).json({ message: 'All fields are required.' }); | |
| } | |
| if (!['enable', 'disable'].includes(enable) || !['enable', 'disable'].includes(reauth)) { | |
| return res.status(400).json({ message: 'Enable and reauthentication must be enable or disable.' }); | |
| } | |
| // Validate time periods and counts | |
| if (!validatePositiveInteger(reauthPeriod)) { | |
| return res.status(400).json({ message: 'Invalid Reauthentication Period. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(quietPeriod)) { | |
| return res.status(400).json({ message: 'Invalid Quiet Period. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(txPeriod)) { | |
| return res.status(400).json({ message: 'Invalid Tx Period. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(serverTimeout)) { | |
| return res.status(400).json({ message: 'Invalid Server Timeout. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(supplicantTimeout)) { | |
| return res.status(400).json({ message: 'Invalid Supplicant Timeout. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(maxRequest)) { | |
| return res.status(400).json({ message: 'Invalid Max Request. Must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(reauthMax)) { | |
| return res.status(400).json({ message: 'Invalid Reauth Max. Must be a positive integer.' }); | |
| } | |
| dot1xConfig.enable = enable; | |
| dot1xConfig.reauth = reauth; | |
| dot1xConfig.reauthPeriod = reauthPeriod; | |
| dot1xConfig.quietPeriod = quietPeriod; | |
| dot1xConfig.txPeriod = txPeriod; | |
| dot1xConfig.serverTimeout = serverTimeout; | |
| dot1xConfig.supplicantTimeout = supplicantTimeout; | |
| dot1xConfig.maxRequest = maxRequest; | |
| dot1xConfig.reauthMax = reauthMax; | |
| console.log(`802.1x configuration updated: Enable: ${enable}, Reauth: ${reauth}`); | |
| res.json({ message: '802.1x configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/dot1x-port-config', (req, res) => { | |
| const { port, portMode, supportHostNum } = req.body; | |
| console.log(req.body); | |
| if (!port || !portMode || supportHostNum === undefined) { | |
| return res.status(400).json({ message: 'Port, port mode, and support host number are required.' }); | |
| } | |
| if (!['auto', 'force-authorized', 'force-unauthorized'].includes(portMode)) { | |
| return res.status(400).json({ message: 'Invalid port mode. Must be auto, force-authorized, or force-unauthorized.' }); | |
| } | |
| // Validate support host number | |
| if (!validatePositiveInteger(supportHostNum)) { | |
| return res.status(400).json({ message: 'Invalid Support Host Number. Must be a positive integer.' }); | |
| } | |
| const portEntry = dot1xPortConfig.find(p => p.port === port); | |
| if (!portEntry) { | |
| return res.status(404).json({ message: 'Port not found.' }); | |
| } | |
| portEntry.portMode = portMode; | |
| portEntry.supportHostNum = parseInt(supportHostNum) || 256; | |
| console.log(`802.1x port configuration updated: Port: ${port}, Mode: ${portMode}`); | |
| res.json({ message: '802.1x port configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/igmp-snooping-config', (req, res) => { | |
| const { globalIgmpSnooping, vlanId, vlanIgmpSnooping, fastLeave, fastLeaveTimeout, queryMembershipTimeout, groupMembershipTimeout } = req.body; | |
| if (!globalIgmpSnooping || !vlanId || !vlanIgmpSnooping || !fastLeave || !fastLeaveTimeout || !queryMembershipTimeout || !groupMembershipTimeout) { | |
| return res.status(400).json({ message: 'All fields are required.' }); | |
| } | |
| if (!['enable', 'disable'].includes(globalIgmpSnooping) || !['enable', 'disable'].includes(vlanIgmpSnooping) || !['enable', 'disable'].includes(fastLeave)) { | |
| return res.status(400).json({ message: 'Global IGMP SNOOPING, VLAN IGMP SNOOPING, and Fast Leave must be enable or disable.' }); | |
| } | |
| // Add type checking for timeout values | |
| if (!validatePositiveInteger(fastLeaveTimeout)) { | |
| return res.status(400).json({ message: 'Fast Leave Timeout must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(queryMembershipTimeout)) { | |
| return res.status(400).json({ message: 'Query Membership Timeout must be a positive integer.' }); | |
| } | |
| if (!validatePositiveInteger(groupMembershipTimeout)) { | |
| return res.status(400).json({ message: 'Group Membership Timeout must be a positive integer.' }); | |
| } | |
| igmpSnoopingConfig.globalIgmpSnooping = globalIgmpSnooping; | |
| igmpSnoopingConfig.vlanId = vlanId; | |
| igmpSnoopingConfig.vlanIgmpSnooping = vlanIgmpSnooping; | |
| igmpSnoopingConfig.fastLeave = fastLeave; | |
| igmpSnoopingConfig.fastLeaveTimeout = fastLeaveTimeout; | |
| igmpSnoopingConfig.queryMembershipTimeout = queryMembershipTimeout; | |
| igmpSnoopingConfig.groupMembershipTimeout = groupMembershipTimeout; | |
| console.log(`IGMP SNOOPING configuration updated: Global: ${globalIgmpSnooping}, VLAN: ${vlanId}, Fast Leave: ${fastLeave}`); | |
| res.json({ message: 'IGMP SNOOPING configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/gmrp-global-config', (req, res) => { | |
| const { globalGmrp } = req.body; | |
| if (!globalGmrp) { | |
| return res.status(400).json({ message: 'Global GMRP status is required.' }); | |
| } | |
| if (!['enable', 'disable'].includes(globalGmrp)) { | |
| return res.status(400).json({ message: 'Global GMRP must be enable or disable.' }); | |
| } | |
| gmrpGlobalConfig.globalGmrp = globalGmrp; | |
| console.log(`GMRP global configuration updated: Global GMRP: ${globalGmrp}`); | |
| res.json({ message: 'GMRP global configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/gmrp-ports-config', (req, res) => { | |
| const { port, gmrpStatus } = req.body; | |
| if (!port || !gmrpStatus) { | |
| return res.status(400).json({ message: 'Port and GMRP status are required.' }); | |
| } | |
| if (!['enable', 'disable'].includes(gmrpStatus)) { | |
| return res.status(400).json({ message: 'GMRP status must be enable or disable.' }); | |
| } | |
| const portEntry = gmrpPortsConfig.find(p => p.portName === port); | |
| if (!portEntry) { | |
| return res.status(404).json({ message: 'Port not found.' }); | |
| } | |
| portEntry.gmrpStatus = gmrpStatus === 'enable' ? 'Enable' : 'Disable'; | |
| console.log(`GMRP ports configuration updated: Port: ${port}, Status: ${gmrpStatus}`); | |
| res.json({ message: 'GMRP ports configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/gvrp-global-config', (req, res) => { | |
| const { globalGvrp } = req.body; | |
| if (!globalGvrp) { | |
| return res.status(400).json({ message: 'Global GVRP status is required.' }); | |
| } | |
| if (!['enable', 'disable'].includes(globalGvrp)) { | |
| return res.status(400).json({ message: 'Global GVRP must be enable or disable.' }); | |
| } | |
| gvrpGlobalConfig.globalGvrp = globalGvrp; | |
| console.log(`GVRP global configuration updated: Global GVRP: ${globalGvrp}`); | |
| res.json({ message: 'GVRP global configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/gvrp-ports-config', (req, res) => { | |
| const { port, gvrpStatus } = req.body; | |
| if (!port || !gvrpStatus) { | |
| return res.status(400).json({ message: 'Port and GVRP status are required.' }); | |
| } | |
| if (!['enable', 'disable'].includes(gvrpStatus)) { | |
| return res.status(400).json({ message: 'GVRP status must be enable or disable.' }); | |
| } | |
| const portEntry = gvrpPortsConfig.find(p => p.portName === port); | |
| if (!portEntry) { | |
| return res.status(404).json({ message: 'Port not found.' }); | |
| } | |
| portEntry.gvrpStatus = gvrpStatus === 'enable' ? 'Enable' : 'Disable'; | |
| console.log(`GVRP ports configuration updated: Port: ${port}, Status: ${gvrpStatus}`); | |
| res.json({ message: 'GVRP ports configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/eaps-config', (req, res) => { | |
| const { eapsRingId, eapsRingIdInput, eapsMode, primaryPort, secondaryPort, controlVlan, protectedVlans, helloTimeInterval, failTime, dataSpan, extremeInteroperability, enableStatus } = req.body; | |
| if (!eapsRingId) { | |
| return res.status(400).json({ message: 'EAPS Ring ID is required.' }); | |
| } | |
| if (!eapsMode) { | |
| return res.status(400).json({ message: 'EAPS mode is required.' }); | |
| } | |
| if (!['None', 'Master', 'Transit'].includes(eapsMode)) { | |
| return res.status(400).json({ message: 'EAPS mode must be None, Master, or Transit.' }); | |
| } | |
| const existingRing = eapsConfigs.find(ring => ring.eapsRingId === eapsRingId); | |
| if (!existingRing) { | |
| return res.status(400).json({ message: 'EAPS Ring ID does not exist. Please create the ring first.' }); | |
| } | |
| if (controlVlan && !validatePositiveInteger(controlVlan)) { | |
| return res.status(400).json({ message: 'Control VLAN must be a positive integer.' }); | |
| } | |
| if (helloTimeInterval && !validatePositiveInteger(helloTimeInterval)) { | |
| return res.status(400).json({ message: 'Hello Time Interval must be a positive integer.' }); | |
| } | |
| if (failTime && !validatePositiveInteger(failTime)) { | |
| return res.status(400).json({ message: 'Fail Time must be a positive integer.' }); | |
| } | |
| const ringIndex = eapsConfigs.findIndex(ring => ring.eapsRingId === eapsRingId); | |
| eapsConfigs[ringIndex] = { | |
| eapsRingId, | |
| eapsRingIdInput: eapsRingIdInput || '', | |
| createStatus: 'Created', | |
| eapsMode, | |
| primaryPort: primaryPort || '', | |
| secondaryPort: secondaryPort || '', | |
| controlVlan: controlVlan || '0', | |
| protectedVlans: protectedVlans || '', | |
| helloTimeInterval: helloTimeInterval || '1', | |
| failTime: failTime || '3', | |
| dataSpan: dataSpan || 'Disable', | |
| extremeInteroperability: extremeInteroperability || 'Enable', | |
| enableStatus: enableStatus || 'Disable' | |
| }; | |
| console.log(`EAPS configuration updated: Ring ID: ${eapsRingId}, Mode: ${eapsMode}, Primary Port: ${primaryPort}, Secondary Port: ${secondaryPort}`); | |
| res.json({ message: 'EAPS configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/eaps-config/create', (req, res) => { | |
| const { eapsRingId, eapsMode, primaryPort, secondaryPort, controlVlan, protectedVlans, helloTimeInterval, failTime, dataSpan, extremeInteroperability, enableStatus } = req.body; | |
| if (!eapsRingId) { | |
| return res.status(400).json({ message: 'EAPS Ring ID is required.' }); | |
| } | |
| if (!eapsMode) { | |
| return res.status(400).json({ message: 'EAPS mode is required.' }); | |
| } | |
| if (!['None', 'Master', 'Transit'].includes(eapsMode)) { | |
| return res.status(400).json({ message: 'EAPS mode must be None, Master, or Transit.' }); | |
| } | |
| if (eapsConfigs.find(ring => ring.eapsRingId === eapsRingId)) { | |
| return res.status(400).json({ message: 'EAPS Ring ID already exists.' }); | |
| } | |
| if (controlVlan && !validatePositiveInteger(controlVlan)) { | |
| return res.status(400).json({ message: 'Control VLAN must be a positive integer.' }); | |
| } | |
| if (helloTimeInterval && !validatePositiveInteger(helloTimeInterval)) { | |
| return res.status(400).json({ message: 'Hello Time Interval must be a positive integer.' }); | |
| } | |
| if (failTime && !validatePositiveInteger(failTime)) { | |
| return res.status(400).json({ message: 'Fail Time must be a positive integer.' }); | |
| } | |
| const newConfig = { | |
| eapsRingId, | |
| eapsRingIdInput: '', | |
| createStatus: 'Created', | |
| eapsMode, | |
| primaryPort: primaryPort || '', | |
| secondaryPort: secondaryPort || '', | |
| controlVlan: controlVlan || '0', | |
| protectedVlans: protectedVlans || '', | |
| helloTimeInterval: helloTimeInterval || '1', | |
| failTime: failTime || '3', | |
| dataSpan: dataSpan || 'Disable', | |
| extremeInteroperability: extremeInteroperability || 'Enable', | |
| enableStatus: enableStatus || 'Disable' | |
| }; | |
| eapsConfigs.push(newConfig); | |
| console.log(`EAPS configuration created: Ring ID: ${eapsRingId}, Mode: ${eapsMode}`); | |
| res.json({ message: 'EAPS configuration created successfully.' }); | |
| }); | |
| this.app.post('/api/eaps-config/remove', (req, res) => { | |
| const { eapsRingId } = req.body; | |
| if (!eapsRingId) { | |
| return res.status(400).json({ message: 'EAPS Ring ID is required.' }); | |
| } | |
| const ringIndex = eapsConfigs.findIndex(ring => ring.eapsRingId === eapsRingId); | |
| if (ringIndex === -1) { | |
| return res.status(400).json({ message: 'EAPS Ring ID does not exist.' }); | |
| } | |
| eapsConfigs.splice(ringIndex, 1); | |
| console.log(`EAPS configuration removed for Ring ID: ${eapsRingId}`); | |
| res.json({ message: 'EAPS configuration removed successfully.' }); | |
| }); | |
| this.app.post('/api/rmon-statistics', (req, res) => { | |
| const { port, index, owner } = req.body; | |
| if (!port) { | |
| return res.status(400).json({ message: 'Port is required.' }); | |
| } | |
| if (index && index !== '0') { | |
| const existingStats = rmonStatisticsData.find(item => item.port === port); | |
| if (!existingStats && isIndexUsed(index)) { | |
| return res.status(400).json({ message: 'Index is already used in another RMON configuration.' }); | |
| } | |
| } | |
| let statsEntry = rmonStatisticsData.find(item => item.port === port); | |
| if (!statsEntry) { | |
| statsEntry = { | |
| port, | |
| index: index || '0', | |
| owner: owner || '', | |
| stats: { | |
| etherStatsDropEvents: "0", | |
| etherStatsPkts: "0", | |
| etherStatsMulticastPkts: "0", | |
| etherStatsUndersizePkts: "0", | |
| etherStatsFragments: "0", | |
| etherStatsCollisions: "0", | |
| etherStatsPkts65to127Octets: "0", | |
| etherStatsPkts256to511Octets: "0", | |
| etherStatsPkts1024to1518Octets: "0", | |
| etherStatsOctets: "0", | |
| etherStatsBroadcastPkts: "0", | |
| etherStatsCRCAlignErrors: "0", | |
| etherStatsOversizePkts: "0", | |
| etherStatsJabbers: "0", | |
| etherStatsPkts64Octets: "0", | |
| etherStatsPkts128to255Octets: "0", | |
| etherStatsPkts512to1023Octets: "0" | |
| } | |
| }; | |
| rmonStatisticsData.push(statsEntry); | |
| } else { | |
| if (index && index !== '0' && index !== statsEntry.index && isIndexUsed(index)) { | |
| return res.status(400).json({ message: 'Index is already used in another RMON configuration.' }); | |
| } | |
| statsEntry.index = index || '0'; | |
| statsEntry.owner = owner || ''; | |
| } | |
| console.log(`RMON statistics configuration updated: Port: ${port}, Index: ${index}, Owner: ${owner}`); | |
| res.json({ message: 'RMON statistics configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/rmon-statistics/delete', (req, res) => { | |
| const { port } = req.body; | |
| if (!port) { | |
| return res.status(400).json({ message: 'Port is required.' }); | |
| } | |
| const index = rmonStatisticsData.findIndex(item => item.port === port); | |
| if (index !== -1) { | |
| rmonStatisticsData[index] = { | |
| ...rmonStatisticsData[index], | |
| index: '0', | |
| owner: '', | |
| stats: { | |
| etherStatsDropEvents: "0", | |
| etherStatsPkts: "0", | |
| etherStatsMulticastPkts: "0", | |
| etherStatsUndersizePkts: "0", | |
| etherStatsFragments: "0", | |
| etherStatsCollisions: "0", | |
| etherStatsPkts65to127Octets: "0", | |
| etherStatsPkts256to511Octets: "0", | |
| etherStatsPkts1024to1518Octets: "0", | |
| etherStatsOctets: "0", | |
| etherStatsBroadcastPkts: "0", | |
| etherStatsCRCAlignErrors: "0", | |
| etherStatsOversizePkts: "0", | |
| etherStatsJabbers: "0", | |
| etherStatsPkts64Octets: "0", | |
| etherStatsPkts128to255Octets: "0", | |
| etherStatsPkts512to1023Octets: "0" | |
| } | |
| }; | |
| console.log(`RMON statistics configuration deleted for Port: ${port}`); | |
| res.json({ message: 'RMON statistics configuration deleted successfully.' }); | |
| } else { | |
| res.status(404).json({ message: 'Port not found.' }); | |
| } | |
| }); | |
| this.app.post('/api/rmon-history', (req, res) => { | |
| const { port, index, interval, buckets, owner } = req.body; | |
| if (!port) { | |
| return res.status(400).json({ message: 'Port is required.' }); | |
| } | |
| if (index && index !== '0') { | |
| const existingHistory = rmonHistoryData.find(item => item.port === port); | |
| if (!existingHistory && isIndexUsed(index)) { | |
| return res.status(400).json({ message: 'Index is already used in another RMON configuration.' }); | |
| } | |
| } | |
| let historyEntry = rmonHistoryData.find(item => item.port === port); | |
| if (!historyEntry) { | |
| historyEntry = { | |
| port, | |
| index: index || '0', | |
| interval: interval || '0', | |
| buckets: buckets || '0', | |
| owner: owner || '', | |
| historyData: [] | |
| }; | |
| rmonHistoryData.push(historyEntry); | |
| } else { | |
| if (index && index !== '0' && index !== historyEntry.index && isIndexUsed(index)) { | |
| return res.status(400).json({ message: 'Index is already used in another RMON configuration.' }); | |
| } | |
| historyEntry.index = index || '0'; | |
| historyEntry.interval = interval || '0'; | |
| historyEntry.buckets = buckets || '0'; | |
| historyEntry.owner = owner || ''; | |
| } | |
| console.log(`RMON history configuration updated: Port: ${port}, Index: ${index}, Interval: ${interval}`); | |
| res.json({ message: 'RMON history configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/rmon-history/delete', (req, res) => { | |
| const { port } = req.body; | |
| if (!port) { | |
| return res.status(400).json({ message: 'Port is required.' }); | |
| } | |
| const index = rmonHistoryData.findIndex(item => item.port === port); | |
| if (index !== -1) { | |
| rmonHistoryData[index] = { | |
| ...rmonHistoryData[index], | |
| index: '0', | |
| interval: '0', | |
| buckets: '0', | |
| owner: '', | |
| historyData: [] | |
| }; | |
| console.log(`RMON history configuration deleted for Port: ${port}`); | |
| res.json({ message: 'RMON history configuration deleted successfully.' }); | |
| } else { | |
| res.status(404).json({ message: 'Port not found.' }); | |
| } | |
| }); | |
| this.app.post('/api/rmon-alarm', (req, res) => { | |
| const { sequenceType, sequenceIndex, interval, variable, sampleType, alarmValue, risingThreshold, fallingThreshold, risingEventIndex, fallingEventIndex, owner } = req.body; | |
| if (!sequenceIndex) { | |
| return res.status(400).json({ message: 'Sequence Index is required.' }); | |
| } | |
| if (isIndexUsed(sequenceIndex, sequenceIndex)) { | |
| return res.status(400).json({ message: 'Sequence Index is already used in another RMON configuration.' }); | |
| } | |
| const existingIndex = rmonAlarmData.findIndex(item => item.sequenceIndex === sequenceIndex); | |
| const newAlarm = { | |
| sequenceIndex: sequenceIndex || '0', | |
| interval: interval || '0', | |
| variable: variable || '', | |
| sampleType: sampleType || 'absolute', | |
| alarmValue: alarmValue || '0', | |
| risingThreshold: risingThreshold || '0', | |
| fallingThreshold: fallingThreshold || '0', | |
| risingEventIndex: risingEventIndex || '0', | |
| fallingEventIndex: fallingEventIndex || '0', | |
| owner: owner || '' | |
| }; | |
| if (sequenceType === 'Existing' && existingIndex !== -1) { | |
| rmonAlarmData[existingIndex] = newAlarm; | |
| } else { | |
| rmonAlarmData.push(newAlarm); | |
| } | |
| console.log(`RMON alarm configuration updated: Sequence Index: ${sequenceIndex}, Variable: ${variable}, Sample Type: ${sampleType}`); | |
| res.json({ message: 'RMON alarm configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/rmon-alarm/delete', (req, res) => { | |
| const { sequenceIndex } = req.body; | |
| if (!sequenceIndex) { | |
| return res.status(400).json({ message: 'Sequence Index is required.' }); | |
| } | |
| const index = rmonAlarmData.findIndex(item => item.sequenceIndex === sequenceIndex); | |
| if (index !== -1) { | |
| rmonAlarmData.splice(index, 1); | |
| console.log(`RMON alarm configuration deleted for Sequence Index: ${sequenceIndex}`); | |
| res.json({ message: 'RMON alarm configuration deleted successfully.' }); | |
| } else { | |
| res.status(404).json({ message: 'Alarm not found.' }); | |
| } | |
| }); | |
| this.app.post('/api/rmon-event', (req, res) => { | |
| const { sequenceType, sequenceIndex, index, description, type, community, lastTimeSent, owner } = req.body; | |
| if (!sequenceIndex) { | |
| return res.status(400).json({ message: 'Sequence Index is required.' }); | |
| } | |
| if (isIndexUsed(sequenceIndex, sequenceIndex)) { | |
| return res.status(400).json({ message: 'Sequence Index is already used in another RMON configuration.' }); | |
| } | |
| const existingIndex = rmonEventData.findIndex(item => item.sequenceIndex === sequenceIndex); | |
| const newEvent = { | |
| sequenceIndex: sequenceIndex || '0', | |
| index: index || '', | |
| description: description || '', | |
| type: type || 'none', | |
| community: community || '', | |
| lastTimeSent: lastTimeSent || '1970/01/01 00:00:00', | |
| owner: owner || '' | |
| }; | |
| if (sequenceType === 'Existing' && existingIndex !== -1) { | |
| rmonEventData[existingIndex] = newEvent; | |
| } else { | |
| rmonEventData.push(newEvent); | |
| } | |
| console.log(`RMON event configuration updated: Sequence Index: ${sequenceIndex}, Description: ${description}, Type: ${type}`); | |
| res.json({ message: 'RMON event configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/rmon-event/delete', (req, res) => { | |
| const { sequenceIndex } = req.body; | |
| if (!sequenceIndex) { | |
| return res.status(400).json({ message: 'Sequence Index is required.' }); | |
| } | |
| const index = rmonEventData.findIndex(item => item.sequenceIndex === sequenceIndex); | |
| if (index !== -1) { | |
| rmonEventData.splice(index, 1); | |
| console.log(`RMON event configuration deleted for Sequence Index: ${sequenceIndex}`); | |
| res.json({ message: 'RMON event configuration deleted successfully.' }); | |
| } else { | |
| res.status(404).json({ message: 'Event not found.' }); | |
| } | |
| }); | |
| this.app.post('/api/erps-config', (req, res) => { | |
| Object.assign(erpsConfig, req.body); | |
| res.json({ message: 'ERPS configuration updated successfully.' }); | |
| }); | |
| this.app.post('/api/erps-info', (req, res) => { | |
| if (req.body.info) erpsInfo.info = req.body.info; | |
| res.json({ message: 'ERPS info updated successfully.' }); | |
| }); | |
| this.app.post("/api/run-cable-diagnosis", (req, res) => { | |
| const { port } = req.body; | |
| if (!port) { | |
| return res.status(400).json({ message: "Port is required" }); | |
| } | |
| const result = { | |
| port: port, | |
| channelA: "open", | |
| lengthA: "1.03(m)", | |
| channelB: "open", | |
| lengthB: "1.00(m)", | |
| channelC: "open", | |
| lengthC: "1.02(m)", | |
| channelD: "open", | |
| lengthD: "1.00(m)" | |
| }; | |
| // Save result in variable | |
| cableDiagnosisResult = result; | |
| // Only return message | |
| res.json({ message: "Cable diagnosis completed successfully" }); | |
| }); | |
| this.app.post('/api/create_vlan', (req, res) => { | |
| const { vid, vlan_name } = req.body; | |
| if (!isValidVid(vid) || typeof vlan_name !== 'string' || vlan_name.trim() === '') { | |
| return res.status(400).json({ message: 'Invalid VLAN ID or name' }); | |
| } | |
| if (vlans.hasOwnProperty(vid)) { | |
| return res.status(409).json({ message: `VLAN ${vid} already exists.` }); | |
| } | |
| vlans[vid] = vlan_name.trim(); | |
| res.json({ message: `Dummy VLAN ${vid} (${vlans[vid]}) applied.` }); | |
| }); | |
| this.app.delete('/api/destroy_vlan', (req, res) => { | |
| const { vid } = req.body; | |
| if (!isValidVid(vid)) { | |
| return res.status(400).json({ message: 'Invalid VLAN ID' }); | |
| } | |
| if (vlans.hasOwnProperty(vid)) { | |
| const deletedName = vlans[vid]; | |
| delete vlans[vid]; | |
| res.json({ message: `Dummy VLAN ${vid} (${deletedName}) deleted.` }); | |
| } else { | |
| res.status(404).json({ message: `Dummy VLAN ${vid} not found.` }); | |
| } | |
| }); | |
| this.app.post('/api/set_vlan_port', (req, res) => { | |
| const { port, vlan: vlanStr, mode, action } = req.body; | |
| const vlan = parseInt(vlanStr, 10); | |
| if (!vports.includes(port)) { | |
| return res.status(400).json({ error: 'Invalid port' }); | |
| } | |
| if (!vlans.hasOwnProperty(vlan)) { | |
| return res.status(400).json({ error: 'Invalid VLAN' }); | |
| } | |
| if (mode === 'access' && action !== 'default') { | |
| return res.status(403).json({ error: 'Access mode does not allow modifying VLAN memberships.' }); | |
| } | |
| if (!portMemberships[port]) portMemberships[port] = {}; | |
| switch (action) { | |
| case 'default': | |
| portMemberships[port] = {}; | |
| portMemberships[port][vlan] = ['p', 'u']; | |
| break; | |
| case 'tag': | |
| portMemberships[port][vlan] = ['t']; | |
| break; | |
| case 'untag': | |
| portMemberships[port][vlan] = ['u']; | |
| break; | |
| case 'unmember': | |
| delete portMemberships[port][vlan]; | |
| break; | |
| default: | |
| return res.status(400).json({ error: 'Invalid action' }); | |
| } | |
| res.json({ message: 'Updated', members: portMemberships[port] }); | |
| }); | |
| this.app.post('/api/create_vlan_interface', (req, res) => { | |
| const { vlanId, ipAddress, dhcpEnabled, macAddress } = req.body; | |
| if (!vlanId) { | |
| return res.status(400).json({ error: 'vlanId is required' }); | |
| } | |
| // If VLAN already has an interface | |
| if (vlanInterfaces[vlanId]) { | |
| return res.status(409).json({ error: `VLAN interface with ID ${vlanId} already exists. interface overlap.` }); | |
| } | |
| // If DHCP disabled, IP must be provided | |
| if (!dhcpEnabled && (!ipAddress || !isValidIpWithCidr(ipAddress))) { | |
| return res.status(400).json({ error: 'Invalid IP format. Expected format: x.x.x.x/xx' }); | |
| } | |
| // Check IP uniqueness across other VLANs | |
| if (!dhcpEnabled && ipAddress && !isIpAddressUnique(vlanId, ipAddress)) { | |
| return res.status(409).json({ error: `IP address ${ipAddress} is already assigned to another VLAN` }); | |
| } | |
| const mac = macAddress || '00:11:22:33:44:55'; | |
| vlanInterfaces[vlanId] = { | |
| ipAddress: dhcpEnabled ? '' : ipAddress, | |
| dhcpEnabled, | |
| macAddress: mac | |
| }; | |
| return res.json({ success: true, vlanId, ipAddress, dhcpEnabled, macAddress: mac }); | |
| }); | |
| this.app.post('/api/destroy_vlan_interface', checkVlanExists, (req, res) => { | |
| const { vlanId } = req.body; | |
| if (!vlanInterfaces[vlanId]) { | |
| return res.status(404).json({ message: `VLAN interface ${vlanId} not found` }); | |
| } | |
| delete vlanInterfaces[vlanId]; | |
| res.json({ message: `VLAN interface ${vlanId} deleted.` }); | |
| }); | |
| this.app.post('/api/update_vlan_interface', checkVlanExists, (req, res) => { | |
| const { vlanId, ipAddress, dhcpEnabled } = req.body; | |
| if (!vlanInterfaces[vlanId]) { | |
| return res.status(404).json({ message: `VLAN interface ${vlanId} not found` }); | |
| } | |
| if (!dhcpEnabled) { | |
| if (!ipAddress || typeof ipAddress !== 'string') { | |
| return res.status(400).json({ message: 'IP Address is required if DHCP is disabled.' }); | |
| } | |
| if (!isValidIpWithCidr(ipAddress)) { | |
| return res.status(400).json({ message: 'Invalid IP format. Expected format: x.x.x.x/xx' }); | |
| } | |
| if (!isIpAddressUnique(vlanId, ipAddress)) { | |
| return res.status(409).json({ message: `IP address ${ipAddress} is already assigned to another VLAN.` }); | |
| } | |
| } | |
| vlanInterfaces[vlanId].dhcpEnabled = !!dhcpEnabled; | |
| vlanInterfaces[vlanId].ipAddress = dhcpEnabled ? '' : ipAddress; | |
| res.json({ message: `VLAN interface ${vlanId} updated.` }); | |
| }); | |
| this.app.post('/api/delete_vlanIp', checkVlanExists, (req, res) => { | |
| const { vlanId, ipAddress } = req.body; | |
| if (!vlanInterfaces[vlanId]) { | |
| return res.status(404).json({ message: `VLAN interface ${vlanId} not found` }); | |
| } | |
| if (vlanInterfaces[vlanId].ipAddress !== ipAddress) { | |
| return res.status(400).json({ message: 'IP Address does not match current VLAN IP' }); | |
| } | |
| vlanInterfaces[vlanId].ipAddress = ''; | |
| vlanInterfaces[vlanId].dhcpEnabled = false; | |
| res.json({ message: `IP address removed from VLAN ${vlanId}.` }); | |
| }); | |
| this.app.post('/api/mac-bind-table', (req, res) => { | |
| const { macAddress, vlanId, port } = req.body; | |
| if (!macAddress || vlanId === undefined || !port) { | |
| return res.status(400).send('Invalid request: macAddress, vlanId, and port are required.'); | |
| } | |
| // Check for duplicate entry | |
| const exists = macBindings.some(entry => | |
| entry.macAddress.toLowerCase() === macAddress.toLowerCase() && | |
| parseInt(entry.vlanId) === parseInt(vlanId) && | |
| entry.port === port | |
| ); | |
| if (exists) { | |
| return res.status(409).send('Binding already exists.'); | |
| } | |
| macBindings.push({ macAddress, vlanId, port }); | |
| res.status(201).send('Binding added successfully.'); | |
| }); | |
| this.app.delete('/api/mac-bind-table', (req, res) => { | |
| const { macAddress, vlanId, port } = req.body; | |
| if (!macAddress || vlanId === undefined || !port) { | |
| return res.status(400).send('Invalid request: macAddress, vlanId, and port are required.'); | |
| } | |
| const initialLength = macBindings.length; | |
| macBindings = macBindings.filter(entry => | |
| !(entry.macAddress.toLowerCase() === macAddress.toLowerCase() && | |
| parseInt(entry.vlanId) === parseInt(vlanId) && | |
| entry.port === port) | |
| ); | |
| if (macBindings.length === initialLength) { | |
| return res.status(404).send('Binding not found.'); | |
| } | |
| res.send('Binding deleted successfully.'); | |
| }); | |
| this.app.post("/api/host-static-route", (req, res) => { | |
| const { targetAddress, nextHop } = req.body; | |
| if (!targetAddress || !nextHop) { | |
| return res.status(400).json({ message: "Both targetAddress and nextHop are required." }); | |
| } | |
| if (!isValidCIDR(targetAddress)) { | |
| return res.status(400).json({ message: "Invalid CIDR format for targetAddress." }); | |
| } | |
| if (!isValidIPv4(nextHop)) { | |
| return res.status(400).json({ message: "Invalid IPv4 format for nextHop." }); | |
| } | |
| const newRoute = { | |
| targetAddress, | |
| nextHop, | |
| distance: 1, | |
| state: "Active" | |
| }; | |
| staticRoutes.push(newRoute); | |
| res.status(201).json({ message: "Static route added successfully." }); | |
| }); | |
| this.app.post('/api/poe-policy-config/:port', (req, res) => { | |
| const port = req.params.port; | |
| const { status, schedule } = req.body; | |
| if (!poePolicyCongifs[port]) { | |
| return res.status(404).json({ error: `Port '${port}' not found.` }); | |
| } | |
| if (typeof status !== 'string' || typeof schedule !== 'object') { | |
| return res.status(400).json({ error: 'Invalid status or schedule format.' }); | |
| } | |
| poePolicyCongifs[port] = { status, schedule }; | |
| console.log(`[Updated Config] Port: ${port}`); | |
| console.log(poePolicyCongifs[port]); | |
| res.json({ message: 'Configuration saved successfully' }); | |
| }); | |
| this.app.post('/api/mac-filter', (req, res) => { | |
| const { port, macEntries } = req.body; | |
| if (!port || !Array.isArray(macEntries)) { | |
| return res.status(400).json({ error: 'Invalid request body' }); | |
| } | |
| if (!macFilteredData[port]) macFilteredData[port] = []; | |
| // Avoid duplicates | |
| macEntries.forEach(entry => { | |
| const exists = macFilteredData[port].some( | |
| e => e.macAddress === entry.macAddress && e.vlanId === entry.vlanId | |
| ); | |
| if (!exists) { | |
| macFilteredData[port].push({ macAddress: entry.macAddress, vlanId: entry.vlanId }); | |
| } | |
| }); | |
| res.json(macFilteredData[port]); | |
| }); | |
| this.app.post('/api/mac-filter-apply', (req, res) => { | |
| const { bindings } = req.body; | |
| if (!Array.isArray(bindings) || bindings.length === 0) { | |
| return res.status(400).json({ error: 'No bindings provided.' }); | |
| } | |
| bindings.forEach(({ port, macAddress, vlanId }) => { | |
| if (!port || !macAddress || isNaN(vlanId)) return; | |
| if (!macFilteredData[port]) macFilteredData[port] = []; | |
| const exists = macFilteredData[port].some( | |
| e => e.macAddress === macAddress && e.vlanId === vlanId | |
| ); | |
| if (!exists) { | |
| macFilteredData[port].push({ macAddress, vlanId }); | |
| } | |
| }); | |
| console.log('Filtered MAC entries:', macFilteredData); | |
| res.status(200).json({ message: 'MAC filter applied successfully.' }); | |
| }); | |
| this.app.post('/api/arp-config-display', (req, res) => { | |
| const { ipAddress, macAddress } = req.body; | |
| if (!isValidIp(ipAddress) || !isValidMac(macAddress)) { | |
| return res.status(400).json({ message: 'Invalid IP or MAC address format' }); | |
| } | |
| const exists = arpTable.find(entry => entry.ipAddress === ipAddress); | |
| if (exists) { | |
| return res.status(400).json({ message: 'ARP entry already exists' }); | |
| } | |
| arpTable.push({ ipAddress, macAddress, type: 'static' }); | |
| res.json({ message: 'ARP entry added' }); | |
| }); | |
| /////////////////////////// DELETE ROUTES /////////////////////// DELETE ROUTES ///////////////// DELETE ROUTES ///////////////////////// | |
| this.app.delete('/api/snmp-community/:index', (req, res) => { | |
| const index = parseInt(req.params.index); | |
| if (isNaN(index) || index < 0 || index >= snmpCommunityData.length) return res.status(404).json({ message: 'Invalid index.' }); | |
| const removed = snmpCommunityData.splice(index, 1); | |
| console.log(`Deleted SNMP community: ${removed[0].communityName}`); | |
| res.json({ message: 'SNMP community name deleted successfully.' }); | |
| }); | |
| this.app.delete('/api/trap-targets/:index', (req, res) => { | |
| const index = parseInt(req.params.index); | |
| if (isNaN(index) || index < 0 || index >= trapTargetData.length) return res.status(404).json({ message: 'Invalid index.' }); | |
| const removed = trapTargetData.splice(index, 1); | |
| console.log(`Deleted trap target: ${removed[0].trapIp}`); | |
| res.json({ message: 'Trap target deleted successfully.' }); | |
| }); | |
| this.app.delete('/api/cluster-name', (req, res) => { | |
| const { name } = req.body; | |
| if (name === clusterName.name) { | |
| clusterName = { name: "", type: "static" }; | |
| console.log("Cluster name deleted."); | |
| res.json({ status: 'success', message: 'Cluster name deleted.' }); | |
| } else { | |
| res.status(404).json({ status: 'error', message: 'Cluster name not found.' }); | |
| } | |
| }); | |
| this.app.delete("/api/mstp-port-config", (req, res) => { | |
| try { | |
| const { port } = req.query; | |
| if (!port || typeof port !== "string" || port.trim() === "") { | |
| return res.status(400).json({ error: "Valid port is required" }); | |
| } | |
| const index = mstpPortConfigs.findIndex(p => p.port === port); | |
| if (index === -1) { | |
| return res.status(404).json({ error: "Port configuration not found" }); | |
| } | |
| mstpPortConfigs.splice(index, 1); | |
| console.log(`MSTP Port ${port} configuration deleted`); | |
| res.json(`{ message: MSTP port ${port} configuration deleted successfully }`); | |
| } catch (error) { | |
| console.error("Error deleting MSTP port config:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| this.app.delete("/api/host-static-route", (req, res) => { | |
| const { targetAddresses } = req.body; | |
| if (!Array.isArray(targetAddresses)) { | |
| return res.status(400).json({ message: "targetAddresses must be an array." }); | |
| } | |
| const invalidCIDRs = targetAddresses.filter(addr => !isValidCIDR(addr)); | |
| if (invalidCIDRs.length > 0) { | |
| return res.status(400).json({ message: `Invalid CIDR(s): ${invalidCIDRs.join(", ")}` }); | |
| } | |
| const before = staticRoutes.length; | |
| staticRoutes = staticRoutes.filter(route => !targetAddresses.includes(route.targetAddress)); | |
| const deleted = before - staticRoutes.length; | |
| res.json({ message: `${deleted} static route(s) deleted.` }); | |
| }); | |
| this.app.delete('/api/mac-filter', (req, res) => { | |
| const { port, entries } = req.body; | |
| if (!port || !Array.isArray(entries)) { | |
| return res.status(400).json({ error: 'Invalid request body' }); | |
| } | |
| if (!macFilteredData[port]) return res.json([]); | |
| macFilteredData[port] = macFilteredData[port].filter( | |
| e => !entries.some(entry => | |
| e.macAddress === entry.macAddress && e.vlanId === entry.vlanId | |
| ) | |
| ); | |
| res.json(macFilteredData[port]); | |
| }); | |
| this.app.delete('/api/arp-config-display', (req, res) => { | |
| const category = req.query.category; | |
| const ipSegment = req.query.segment; | |
| if (!category || (ipSegment && !isValidIp(ipSegment))) { | |
| return res.status(400).json({ message: 'Invalid category or IP segment format' }); | |
| } | |
| const initialLength = arpTable.length; | |
| arpTable = arpTable.filter(entry => { | |
| if (category === 'all') return false; | |
| if (category === 'dynamic' || category === 'static') return entry.type !== category; | |
| return true; | |
| }); | |
| if (ipSegment) { | |
| arpTable = arpTable.filter(entry => entry.ipAddress !== ipSegment); | |
| } | |
| if (arpTable.length === initialLength) { | |
| return res.status(404).json({ message: 'No ARP entries found to delete' }); | |
| } | |
| res.json({ message: `ARP entries for category ${category} deleted` }); | |
| }); | |
| this.app.patch('/api/snmp-community/:index', (req, res) => { | |
| const index = parseInt(req.params.index); | |
| if (isNaN(index) || index < 0 || index >= snmpCommunityData.length) return res.status(404).json({ message: 'Invalid index.' }); | |
| const { accessType } = req.body; | |
| if (accessType && !['Read/Write', 'Read Only'].includes(accessType)) return res.status(400).json({ message: 'Invalid access type.' }); | |
| if (accessType) snmpCommunityData[index].accessType = accessType; | |
| console.log(`Updated SNMP community at index ${index}`); | |
| res.json({ message: 'SNMP community updated successfully.' }); | |
| }); | |
| this.app.patch('/api/trap-targets/:index', (req, res) => { | |
| const index = parseInt(req.params.index); | |
| if (isNaN(index) || index < 0 || index >= trapTargetData.length) return res.status(404).json({ message: 'Invalid index.' }); | |
| const { trapIp, trapCommunity, trapVersion } = req.body; | |
| const state = new Date().getHours() >= 8 && new Date().getHours() < 18 ? "Active" : "Inactive"; | |
| if (trapVersion && !['v1', 'v2c', 'v3'].includes(trapVersion)) return res.status(400).json({ message: 'Invalid trap version.' }); | |
| // if (trapVersion) trapTargetData[index].trapVersion = trapVersion; | |
| trapTargetData[index] = { trapIp, trapCommunity, trapVersion, state }; | |
| console.log(`Updated trap target at index ${index}`); | |
| res.json({ message: 'Trap target updated successfully.' }); | |
| }); | |
| this.app.put('/api/arp-config-display/convert', (req, res) => { | |
| const category = req.query.category; | |
| const ipSegment = req.query.segment; | |
| if (!category || (ipSegment && !isValidIp(ipSegment))) { | |
| return res.status(400).json({ message: 'Invalid category or IP segment format' }); | |
| } | |
| let converted = false; | |
| arpTable = arpTable.map(entry => { | |
| if ((category === 'dynamic' || category === 'all') && entry.type === 'dynamic' && (!ipSegment || entry.ipAddress === ipSegment)) { | |
| converted = true; | |
| return { ...entry, type: 'static' }; | |
| } | |
| return entry; | |
| }); | |
| if (!converted) { | |
| return res.status(404).json({ message: 'No dynamic ARP entries found to convert' }); | |
| } | |
| res.json({ message: `ARP entries for category ${category} converted to static` }); | |
| }); | |
| this.app.put("/api/mstp-port-config", (req, res) => { | |
| try { | |
| const config = req.body; | |
| if (!isValidPortConfig(config)) { | |
| return res.status(400).json({ error: "Invalid MSTP port configuration parameters" }); | |
| } | |
| const index = mstpPortConfigs.findIndex(p => p.port === config.port); | |
| if (index === -1) { | |
| return res.status(404).json({ error: "Port configuration not found" }); | |
| } | |
| mstpPortConfigs[index] = { ...config }; | |
| console.log(`MSTP Port ${config.port} configuration updated:, ${config}`); | |
| res.json({ message: "MSTP port configuration updated successfully" }); | |
| } catch (error) { | |
| console.error("Error updating MSTP port config:", error); | |
| res.status(500).json({ error: "Internal server error" }); | |
| } | |
| }); | |
| } | |
| start() { | |
| this.app.listen(this.port, () => { | |
| console.log(`Server running at http://localhost:${this.port}`); | |
| }); | |
| } | |
| } | |
| const server = new MainServer(); | |
| server.init(); | |
| server.start(); // Added to start the server | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment