From c8310a68212710597e5eba8dd9b498c050f9abc3 Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Sun, 26 Oct 2025 18:17:23 +0100 Subject: [PATCH] luci-mod-network: DHCP; ES6 treatment Signed-off-by: Paul Donald --- .../resources/view/network/dhcp.js | 158 ++++++++---------- 1 file changed, 74 insertions(+), 84 deletions(-) diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js index 7a4fef340b..8d9050a5d0 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js @@ -9,35 +9,32 @@ 'require validation'; 'require tools.widgets as widgets'; -var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status; -var callUfpList; - -callHostHints = rpc.declare({ +const callHostHints = rpc.declare({ object: 'luci-rpc', method: 'getHostHints', expect: { '': {} } }); -callDUIDHints = rpc.declare({ +const callDUIDHints = rpc.declare({ object: 'luci-rpc', method: 'getDUIDHints', expect: { '': {} } }); -callDHCPLeases = rpc.declare({ +const callDHCPLeases = rpc.declare({ object: 'luci-rpc', method: 'getDHCPLeases', expect: { '': {} } }); -callUfpList = rpc.declare({ +const callUfpList = rpc.declare({ object: 'fingerprint', method: 'fingerprint', expect: { '': {} } }); -CBILeaseStatus = form.DummyValue.extend({ - renderWidget: function(section_id, option_id, cfgvalue) { +const CBILeaseStatus = form.DummyValue.extend({ + renderWidget(section_id, option_id, cfgvalue) { return E([ E('h4', _('Active DHCP Leases')), E('table', { 'id': 'lease_status_table', 'class': 'table' }, [ @@ -55,8 +52,8 @@ CBILeaseStatus = form.DummyValue.extend({ } }); -CBILease6Status = form.DummyValue.extend({ - renderWidget: function(section_id, option_id, cfgvalue) { +const CBILease6Status = form.DummyValue.extend({ + renderWidget(section_id, option_id, cfgvalue) { return E([ E('h4', _('Active DHCPv6 Leases')), E('table', { 'id': 'lease6_status_table', 'class': 'table' }, [ @@ -114,18 +111,17 @@ function generateDnsmasqInstanceEntry(data) { function getDHCPPools() { return uci.load('dhcp').then(function() { - let sections = uci.sections('dhcp', 'dhcp'), - tasks = [], pools = []; + const tasks = [], pools = []; - for (var i = 0; i < sections.length; i++) { - if (sections[i].ignore == '1' || !sections[i].interface) + for (const section of uci.sections('dhcp', 'dhcp')) { + if (section.ignore == '1' || !section.interface) continue; - tasks.push(network.getNetwork(sections[i].interface).then(L.bind(function(section_id, net) { - var cidr = net ? (net.getIPAddrs()[0] || '').split('/') : null; + tasks.push(network.getNetwork(section.interface).then(L.bind(function(section_id, net) { + const cidr = net ? (net.getIPAddrs()[0] || '').split('/') : null; if (cidr && cidr.length == 2) { - var net_mask = calculateNetwork(cidr[0], cidr[1]); + const net_mask = calculateNetwork(cidr[0], cidr[1]); pools.push({ section_id: section_id, @@ -133,7 +129,7 @@ function getDHCPPools() { netmask: net_mask[1] }); } - }, null, sections[i]['.name']))); + }, null, section['.name']))); } return Promise.all(tasks).then(function() { @@ -143,26 +139,25 @@ function getDHCPPools() { } function validateHostname(sid, s) { - if (s == null || s == '') - return true; + if (!s) return true; if (s.length > 256) return _('Expecting: %s').format(_('valid hostname')); - var labels = s.replace(/^\*?\.?|\.$/g, '').split(/\./); + const labels = s.replace(/^\*?\.?|\.$/g, '').split(/\./); - for (var i = 0; i < labels.length; i++) - if (!labels[i].match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i)) + for (const label of labels) { + if (!label.match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i)) return _('Expecting: %s').format(_('valid hostname')); + } return true; } function validateDUIDIAID(sid, s) { - if (s == null || s == '') - return true; + if (!s) return true; - var parts = s.split('%'); + const parts = s.split('%'); if (parts.length > 2) return _('Expecting: %s').format(_('maximum one "%"')); @@ -177,7 +172,7 @@ function validateDUIDIAID(sid, s) { }; function expandAndFormatMAC(macs) { - let result = []; + const result = []; macs.forEach(mac => { if (isValidMAC(mac)) { @@ -192,20 +187,17 @@ function expandAndFormatMAC(macs) { } function isValidMAC(sid, s) { - if (!s) - return true; + if (!s) return true; - let macaddrs = L.toArray(s); - - for (var i = 0; i < macaddrs.length; i++) - if (!macaddrs[i].match(/^(([0-9a-f]{1,2}|\*)[:-]){5}([0-9a-f]{1,2}|\*)$/i)) - return _('Expecting a valid MAC address, optionally including wildcards') + _('; invalid MAC: ') + macaddrs[i]; + for (const mac of L.toArray(s)) + if (!mac.match(/^(([0-9a-f]{1,2}|\*)[:-]){5}([0-9a-f]{1,2}|\*)$/i)) + return _('Expecting a valid MAC address, optionally including wildcards') + _('; invalid MAC: ') + mac; return true; } return view.extend({ - load: function() { + load() { return Promise.all([ callHostHints(), callDUIDHints(), @@ -215,7 +207,7 @@ return view.extend({ ]); }, - render: function([hosts, duids, pools, networks, macdata]) { + render([hosts, duids, pools, networks, macdata]) { let m; m = new form.Map('dhcp', _('DHCP')); @@ -230,13 +222,13 @@ return view.extend({ return m.render().then(function(mapEl) { poll.add(function() { return callDHCPLeases().then(function(leaseinfo) { - var leases = Array.isArray(leaseinfo.dhcp_leases) ? leaseinfo.dhcp_leases : [], - leases6 = Array.isArray(leaseinfo.dhcp6_leases) ? leaseinfo.dhcp6_leases : []; + const leases = Array.isArray(leaseinfo.dhcp_leases) ? leaseinfo.dhcp_leases : []; + const leases6 = Array.isArray(leaseinfo.dhcp6_leases) ? leaseinfo.dhcp6_leases : []; cbi_update_table('#lease_status_table', leases.map(function(lease) { - var exp; - var vendor; + let exp; + let vendor; if (lease.expires === false) exp = E('em', _('unlimited')); @@ -252,9 +244,9 @@ return view.extend({ } } - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? hint.name : null, - host = null; + const hint = lease.macaddr ? hosts[lease.macaddr] : null; + const name = hint ? hint.name : null; + let host = null; if (name && lease.hostname && lease.hostname != name) host = '%s (%s)'.format(lease.hostname, name); @@ -273,7 +265,7 @@ return view.extend({ cbi_update_table('#lease6_status_table', leases6.map(function(lease) { - var exp; + let exp; if (lease.expires === false) exp = E('em', _('unlimited')); @@ -282,9 +274,9 @@ return view.extend({ else exp = '%t'.format(lease.expires); - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null, - host = null; + const hint = lease.macaddr ? hosts[lease.macaddr] : null; + const name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null; + let host = null; if (name && lease.hostname && lease.hostname != name && lease.ip6addr != name) host = '%s (%s)'.format(lease.hostname, name); @@ -310,8 +302,8 @@ return view.extend({ }); }, - add_dnsmasq_cfg: function(m, networks) { - var s, o, ss, so; + add_dnsmasq_cfg(m, networks) { + let s, o, ss, so; s = m.section(form.TypedSection, 'dnsmasq', _('dnsmasq')); s.hidetitle = true; @@ -319,8 +311,8 @@ return view.extend({ s.addremove = true; s.addbtntitle = _('Add server instance', 'Dnsmasq instance'); s.renderContents = function(/* ... */) { - var renderTask = form.TypedSection.prototype.renderContents.apply(this, arguments), - sections = this.cfgsections(); + const renderTask = form.TypedSection.prototype.renderContents.apply(this, arguments); + const sections = this.cfgsections(); return Promise.resolve(renderTask).then(function(nodes) { if (sections.length < 2) { @@ -329,9 +321,9 @@ return view.extend({ } else { nodes.querySelectorAll('#cbi-dhcp-dnsmasq > .cbi-section-remove').forEach(function(div, i) { - var section = uci.get('dhcp', sections[i]), - hline = div.nextElementSibling, - btn = div.firstElementChild; + const section = uci.get('dhcp', sections[i]); + const hline = div.nextElementSibling; + const btn = div.firstElementChild; if (!section || section['.anonymous']) { hline.innerText = i ? _('Unnamed instance #%d', 'Dnsmasq instance').format(i+1) : _('Default instance', 'Dnsmasq instance'); @@ -474,9 +466,9 @@ return view.extend({ so.optional = false; so.placeholder = '192.168.10.1#535'; so.validate = function(section, value) { - var m = this.section.formvalue(section, 'local_addr'), - n = this.section.formvalue(section, 'server_addr'), - p; + const m = this.section.formvalue(section, 'local_addr'); + let n = this.section.formvalue(section, 'server_addr'); + let p; if (!m || !n) { return _('Both "Relay from" and "Relay to address" must be specified.'); @@ -575,7 +567,7 @@ return view.extend({ so.optional = true; Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); + const [name, display_str] = generateDnsmasqInstanceEntry(val); so.value(name, display_str); }); // End pxe_tftp @@ -583,8 +575,8 @@ return view.extend({ return s; }, - add_odhcpd_cfg: function(m) { - var s, o, ss, so; + add_odhcpd_cfg(m) { + let s, o, ss, so; s = m.section(form.TypedSection, 'odhcpd', _('odhcpd')); s.hidetitle = true; @@ -688,9 +680,9 @@ return view.extend({ // End pxe6 }, - add_leases_cfg: function(m, hosts, duids, pools, macdata) { - var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'), - s, o, ss, so; + add_leases_cfg(m, hosts, duids, pools, macdata) { + const has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'); + let s, o, ss, so; s = m.section(form.TypedSection, '__leases__', _('Leases')); s.hidetitle = true; @@ -730,9 +722,9 @@ return view.extend({ _('Only one of the MAC addresses is expected to be in active use on the network at any given time.')); so.rmempty = true; so.cfgvalue = function(section) { - var macs = uci.get('dhcp', section, 'mac'); - var formattedMacs; - var hint, entry; + const macs = uci.get('dhcp', section, 'mac'); + let formattedMacs; + let hint, entry; if(!Array.isArray(macs)){ formattedMacs = expandAndFormatMAC(L.toArray(macs)); @@ -780,8 +772,8 @@ return view.extend({ return isValidMAC(section_id, value); } Object.keys(hosts).forEach(function(mac) { - var vendor; - var lower_mac = mac.toLowerCase(); + let vendor; + const lower_mac = mac.toLowerCase(); if (macdata) vendor = macdata[lower_mac] ? macdata[lower_mac].vendor : null; const hint = vendor || hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; @@ -792,8 +784,8 @@ return view.extend({ so.value('ignore', _('Ignore')); so.datatype = 'or(ip4addr,"ignore")'; so.validate = function(section, value) { - var m = this.section.formvalue(section, 'mac'), - n = this.section.formvalue(section, 'name'); + const m = this.section.formvalue(section, 'mac'); + const n = this.section.formvalue(section, 'name'); if ((m && !m.length > 0) && !n) return _('One of hostname or MAC address must be specified!'); @@ -801,27 +793,25 @@ return view.extend({ if (!value || value == 'ignore') return true; - var leases = uci.sections('dhcp', 'host'); + const leases = uci.sections('dhcp', 'host'); - for (var i = 0; i < leases.length; i++) - if (leases[i]['.name'] != section && leases[i].ip == value) + for (const lease of leases) + if (lease['.name'] != section && lease.ip == value) return _('The IP address %h is already used by another static lease').format(value); - for (var i = 0; i < pools.length; i++) { - var net_mask = calculateNetwork(value, pools[i].netmask); + for (const pool of pools) { + const net_mask = calculateNetwork(value, pool.netmask); - if (net_mask && net_mask[0] == pools[i].network) + if (net_mask && net_mask[0] == pool.network) return true; } return _('The IP address is outside of any DHCP pool address range'); }; - var ipaddrs = {}; + const ipaddrs = {}; Object.keys(hosts).forEach(function(mac) { - var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4); - - for (var i = 0; i < addrs.length; i++) - ipaddrs[addrs[i]] = hosts[mac].name || mac; + for (const ip of L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)) + ipaddrs[ip] = hosts[mac].name || mac; }); L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { o.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); @@ -845,7 +835,7 @@ return view.extend({ so.rmempty = true; so.validate = validateDUIDIAID; Object.keys(duids).forEach(function(duid_iaid) { - var desc = duids[duid_iaid].hostname || duids[duid_iaid].macaddr || duids[duid_iaid].ip6addrs[0] || '?'; + const desc = duids[duid_iaid].hostname || duids[duid_iaid].macaddr || duids[duid_iaid].ip6addrs[0] || '?'; so.value(duid_iaid, '%s (%s)'.format(duid_iaid, desc)); }); @@ -874,7 +864,7 @@ return view.extend({ _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); so.optional = true; Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); + const [name, display_str] = generateDnsmasqInstanceEntry(val); so.value(name, display_str); }); -- 2.30.2