Skip to content

Instantly share code, notes, and snippets.

@akansha-oi
Last active August 2, 2025 07:06
Show Gist options
  • Select an option

  • Save akansha-oi/4c5b0db28b0028711c26dc005e9c58af to your computer and use it in GitHub Desktop.

Select an option

Save akansha-oi/4c5b0db28b0028711c26dc005e9c58af to your computer and use it in GitHub Desktop.
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