From 4b49999f937e66debe6d4e295c65b2ee02338b7e Mon Sep 17 00:00:00 2001 From: Dirk Brenken Date: Tue, 14 Oct 2025 22:14:47 +0200 Subject: [PATCH] luci-app-travelmate: sync with release 2.2.0 Signed-off-by: Dirk Brenken --- applications/luci-app-travelmate/Makefile | 4 +- .../resources/view/travelmate/overview.js | 171 ++++---- .../resources/view/travelmate/stations.js | 377 +++++++++--------- .../share/rpcd/acl.d/luci-app-travelmate.json | 6 +- 4 files changed, 277 insertions(+), 281 deletions(-) diff --git a/applications/luci-app-travelmate/Makefile b/applications/luci-app-travelmate/Makefile index b6a528fe6e..19cc8f5e30 100644 --- a/applications/luci-app-travelmate/Makefile +++ b/applications/luci-app-travelmate/Makefile @@ -1,10 +1,10 @@ -# Copyright 2017-2023 Dirk Brenken (dev@brenken.org) +# Copyright 2017-2025 Dirk Brenken (dev@brenken.org) # This is free software, licensed under the Apache License, Version 2.0 include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for Travelmate -LUCI_DEPENDS:=+luci-base +travelmate +LUCI_DEPENDS:=+luci-base +luci-lib-uqr +travelmate PKG_LICENSE:=Apache-2.0 PKG_MAINTAINER:=Dirk Brenken diff --git a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js index 9f78582c5a..07d1f04213 100644 --- a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js +++ b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js @@ -6,12 +6,13 @@ 'require uci'; 'require form'; 'require tools.widgets as widgets'; +'require uqr'; /* button handling */ function handleAction(ev) { - var ifaceValue; + let ifaceValue; if (ev === 'restart') { ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'); return fs.exec('/etc/init.d/travelmate', ['stop']) @@ -41,25 +42,24 @@ function handleAction(ev) { ]), E('div', { 'class': 'right' }, [ E('button', { - 'class': 'btn', + 'class': 'cbi-button', 'click': L.hideModal }, _('Dismiss')), ' ', E('button', { 'class': 'cbi-button cbi-button-positive important', 'click': ui.createHandlerFn(this, function (ev) { - var iface = document.getElementById('iface').value || 'trm_wwan', + let iface = document.getElementById('iface').value || 'trm_wwan', zone = document.getElementById('zone').value || 'wan', metric = document.getElementById('metric').value || '100'; - L.resolveDefault(fs.exec('/etc/init.d/travelmate', ['setup', iface, zone, metric])) - .then(function (res) { - if (res) { - ui.addNotification(null, E('p', res.trim() + '.'), 'error'); - } else { - ui.addNotification(null, E('p', _('The uplink interface has been updated.')), 'info'); - } - }); - L.hideModal(); + fs.exec('/etc/init.d/travelmate', ['setup', iface, zone, metric]).then(function (rc) { + L.hideModal(); + if (rc.code == 1) { + ui.addNotification(null, E('p', _('Setup failed, the interface already exists!')), 'error'); + } else { + location.reload(); + } + }); }) }, _('Save')) ]) @@ -71,10 +71,10 @@ function handleAction(ev) { return Promise.all([ uci.load('wireless') ]).then(function () { - var w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result, + let w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result, w_sections = uci.sections('wireless', 'wifi-iface'), optionsAP = [E('option', { value: '' }, [_('-- AP Selection --')])]; - for (var i = 0; i < w_sections.length; i++) { + for (let i = 0; i < w_sections.length; i++) { if (w_sections[i].mode === 'ap' && w_sections[i].disabled !== '1') { w_sid = i; w_device = w_sections[i].device; @@ -82,7 +82,7 @@ function handleAction(ev) { optionsAP.push(E('option', { value: w_sid }, w_device + ', ' + w_ssid)); } } - var selectAP = E('select', { + let selectAP = E('select', { id: 'selectID', class: 'cbi-input-select', change: function (ev) { @@ -99,14 +99,14 @@ function handleAction(ev) { } else { w_enc = 'WPA'; } - L.resolveDefault(fs.exec_direct('/usr/bin/qrencode', ['--inline', '--8bit', '--type=SVG', '--output=-', 'WIFI:S:' + w_ssid + ';T:' + w_enc + ';P:' + w_key + ';H:' + w_hidden + ';']), null).then(function (res) { - if (res) { - result.innerHTML = res.trim(); - } - else { - result.textContent = _('The QR-Code could not be generated!'); - } - }); + let data = `WIFI:S: ${w_ssid};T: ${w_enc};P: ${w_key};H: ${w_hidden};;`; + const options = { + pixelSize: 4, + whiteColor: 'white', + blackColor: 'black' + }; + let svg = uqr.renderSVG(data, options); + result.innerHTML = svg.trim(); } else { result.textContent = ''; @@ -126,7 +126,7 @@ function handleAction(ev) { }), E('div', { 'class': 'right' }, [ E('button', { - 'class': 'btn', + 'class': 'cbi-button', 'click': L.hideModal }, _('Dismiss')) ]) @@ -147,18 +147,18 @@ return view.extend({ m = new form.Map('travelmate', 'Travelmate', _('Configuration of the travelmate package to enable travel router functionality. \ For further information check the online documentation.
\ - Please note: On first start please call the \'Interface Wizard\' once, to make the necessary network- and firewall settings.')); + Please note: On first start please call the \'Interface Wizard\' once, to make the necessary network- and firewall settings.')); /* poll runtime information */ pollData: poll.add(function () { return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) { - var status = document.getElementById('status'); + let status = document.getElementById('status'); if (res && res.size > 0) { L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) { if (res) { - var info = JSON.parse(res); + let info = JSON.parse(res); if (status && info) { status.textContent = (info.data.travelmate_status || '-') + ' / ' + (info.data.travelmate_version || '-'); if (info.data.travelmate_status.startsWith('running')) { @@ -176,31 +176,27 @@ return view.extend({ status.classList.remove("spinning"); } } - var station_id = document.getElementById('station_id'); + let station_id = document.getElementById('station_id'); if (station_id && info) { station_id.textContent = info.data.station_id || '-'; } - var station_mac = document.getElementById('station_mac'); + let station_mac = document.getElementById('station_mac'); if (station_mac && info) { station_mac.textContent = info.data.station_mac || '-'; } - var station_interfaces = document.getElementById('station_interfaces'); + let station_interfaces = document.getElementById('station_interfaces'); if (station_interfaces && info) { station_interfaces.textContent = info.data.station_interfaces || '-'; } - var wpa_flags = document.getElementById('wpa_flags'); - if (wpa_flags && info) { - wpa_flags.textContent = info.data.wpa_flags || '-'; - } - var run_flags = document.getElementById('run_flags'); + let run_flags = document.getElementById('run_flags'); if (run_flags && info) { run_flags.textContent = info.data.run_flags || '-'; } - var ext_hooks = document.getElementById('ext_hooks'); + let ext_hooks = document.getElementById('ext_hooks'); if (ext_hooks && info) { ext_hooks.textContent = info.data.ext_hooks || '-'; } - var run = document.getElementById('run'); + let run = document.getElementById('run'); if (run && info) { run.textContent = info.data.last_run || '-'; } @@ -223,60 +219,52 @@ return view.extend({ return E('div', { 'class': 'cbi-section' }, [ E('h3', _('Information')), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')), - E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'color:#37c' }, '\xa0') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Status / Version')), + E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'margin-bottom:-5px;color:#37c;' }, '\xa0') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')), - E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Station ID')), + E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'margin-bottom:-5px;color:#37c;' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station MAC')), - E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Station MAC')), + E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'margin-bottom:-5px;color:#37c;' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interfaces')), - E('div', { 'class': 'cbi-value-field', 'id': 'station_interfaces', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Station Interfaces')), + E('div', { 'class': 'cbi-value-field', 'id': 'station_interfaces', 'style': 'margin-bottom:-5px;color:#37c;' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')), - E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Run Flags')), + E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'margin-bottom:-5px;color:#37c;' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')), - E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Ext. Hooks')), + E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'margin-bottom:-5px;color:#37c;' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Ext. Hooks')), - E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'color:#37c' }, '-') - ]), - E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')), - E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Last Run')), + E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'margin-bottom:-5px;color:#37c;' }, '-') ]), E('div', { class: 'right' }, [ E('button', { 'class': 'cbi-button cbi-button-apply', + 'style': 'float:none;margin-right:.4em;', 'id': 'btn_suspend', 'click': ui.createHandlerFn(this, function () { - L.resolveDefault(fs.stat('/usr/bin/qrencode'), null).then(function (res) { - if (res) { - return handleAction('qrcode'); - } - return ui.addNotification(null, E('p', _('Please install the separate \'qrencode\' package.')), 'info'); - }) + return handleAction('qrcode'); }) }, [_('AP QR-Codes...')]), - '\xa0', E('button', { 'class': 'cbi-button cbi-button-negative', + 'style': 'float:none;margin-right:.4em;', 'click': ui.createHandlerFn(this, function () { return handleAction('restart'); }) }, [_('Restart Interface')]), - '\xa0', E('button', { 'class': 'cbi-button cbi-button-negative', + 'style': 'float:none;', 'click': ui.createHandlerFn(this, function () { return handleAction('setup'); }) @@ -293,7 +281,7 @@ return view.extend({ s.addremove = false; s.tab('general', _('General Settings')); s.tab('additional', _('Additional Settings')); - s.tab('adv_email', _('E-Mail Settings'), _('Please note: E-Mail notifications require the separate setup of the msmtp package.

 

')); + s.tab('adv_email', _('E-Mail Settings')); /* general settings tab @@ -301,14 +289,20 @@ return view.extend({ o = s.taboption('general', form.Flag, 'trm_enabled', _('Enabled'), _('Enable the travelmate service.')); o.rmempty = false; - o = s.taboption('general', form.Flag, 'trm_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.')); - o.rmempty = false; - - o = s.taboption('general', form.Value, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order.')); + o = s.taboption('general', form.ListValue, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order.')); o.value('radio0', _('use the first radio only (radio0)')); o.value('radio1', _('use the second radio only (radio1)')); o.value('radio0 radio1', _('use both radios, normal sort order (radio0 radio1)')); o.value('radio1 radio0', _('use both radios, reverse sort order (radio1 radio0)')); + o.placeholder = _('-- default --'); + o.optional = true; + o.rmempty = true; + + o = s.taboption('general', form.ListValue, 'trm_scanmode', _('WLAN Scan Mode'), _('Send active probe requests or passively listen for beacon frames that are regularly sent by access points.')); + o.value('active', _('active')); + o.value('passive', _('passive')); + o.placeholder = _('-- default --'); + o.optional = true; o.rmempty = true; o = s.taboption('general', form.Flag, 'trm_captive', _('Captive Portal Detection'), _('Check the internet availability, handle captive portal redirections and keep the uplink connection \'alive\'.')); @@ -342,7 +336,7 @@ return view.extend({ o.rmempty = false; o = s.taboption('general', form.Flag, 'trm_proactive', _('ProActive Uplink Switch'), _('Proactively scan and switch to a higher prioritized uplink, despite of an already existing connection.')); - o.default = 1; + o.default = 0; o.rmempty = false; o = s.taboption('general', form.Flag, 'trm_randomize', _('Randomize MAC Addresses'), _('Generate a random unicast MAC address for each uplink connection.')); @@ -362,6 +356,19 @@ return view.extend({ /* additional settings tab */ + o = s.taboption('additional', form.Flag, 'trm_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.')); + o.rmempty = false; + + o = s.taboption('additional', form.ListValue, 'trm_nice', _('Service Priority'), _('The selected priority will be used for travelmate processes.')); + o.value('-20', _('Highest Priority')); + o.value('-10', _('High Priority')); + o.value('0', _('Normal Priority')); + o.value('10', _('Less Priority')); + o.value('19', _('Least Priority')); + o.placeholder = _('-- default --'); + o.optional = true; + o.rmempty = true; + o = s.taboption('additional', form.Value, 'trm_triggerdelay', _('Trigger Delay'), _('Additional trigger delay in seconds before travelmate processing begins.')); o.placeholder = '2'; o.datatype = 'range(1,60)'; @@ -393,30 +400,28 @@ return view.extend({ o.value('http://captive.apple.com', 'Apple'); o.value('http://connectivitycheck.android.com/generate_204', 'Google'); o.value('http://www.msftncsi.com/ncsi.txt', 'Microsoft'); + o.placeholder = _('-- default --'); o.optional = true; o.rmempty = true; o = s.taboption('additional', form.ListValue, 'trm_useragent', _('User Agent'), _('The selected user agent will be used for connectivity- and captive portal checks.')); - o.value('Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0', 'Firefox (default)'); - o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Chromium'); - o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Safari'); - o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61', 'Edge'); - o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 OPR/103.0.0.0', 'Opera'); - o.optional = true; - o.rmempty = true; - - o = s.taboption('additional', form.ListValue, 'trm_nice', _('Service Priority'), _('The selected priority will be used for travelmate processes.')); - o.value('-20', 'Highest Priority'); - o.value('-10', 'High Priority'); - o.value('0', 'Normal Priority (default)'); - o.value('10', 'Less Priority'); - o.value('19', 'Least Priority'); + o.value('Mozilla/5.0 (X11; Linux x86_64; rv:144.0) Gecko/20100101 Firefox/144.0', 'Firefox (default)'); + o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36', 'Chromium'); + o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15', 'Safari'); + o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.3537.71', 'Edge'); + o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 OPR/122.0.0.0', 'Opera'); + o.placeholder = _('-- default --'); o.optional = true; o.rmempty = true; /* advanced email settings tab */ + o = s.taboption('adv_email', form.DummyValue, '_sub'); + o.rawhtml = true; + o.default = '' + _('E-Mail notifications require the separate setup of the msmtp package.') + '' + + '
' + o = s.taboption('adv_email', form.Flag, 'trm_mail', _('E-Mail Hook'), _('Sends notification E-Mails after every succesful uplink connect.')); o.rmempty = false; diff --git a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js index 5bc5bf4951..c471d75d59 100644 --- a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js +++ b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js @@ -8,18 +8,39 @@ 'require network'; 'require tools.widgets as widgets'; +/* + Cipher helper function +*/ +function resolveCipher(cipherRaw) { + const cipherMap = { + '2': 'TKIP', + '4': 'CCMP-128', + '6': 'BIP', + '8': 'GCMP-128', + '9': 'GCMP-256', + '10': 'CCMP-256', + '11': 'BIP-GMAC-128', + '12': 'BIP-GMAC-256', + '13': 'BIP-CMAC-256' + }; + if (!cipherRaw) return "unknown"; + if (!cipherRaw.includes(':')) return cipherRaw; + let id = cipherRaw.split(':').pop(); + return cipherMap[id] || `Unknown (${cipherRaw})`; +} + /* change the status of travelmate stations */ function handleToggle(sid) { - var w_device, w_ssid, w_bssid, t_sections, row, element, value, enabled; + let w_device, w_ssid, w_bssid, t_sections, row, element, value, enabled; w_device = uci.get('wireless', sid, 'device'); w_ssid = uci.get('wireless', sid, 'ssid'); w_bssid = uci.get('wireless', sid, 'bssid'); t_sections = uci.sections('travelmate', 'uplink'); - for (var i = 0; i < t_sections.length; i++) { + for (let i = 0; i < t_sections.length; i++) { if (t_sections[i].device === w_device && t_sections[i].ssid === w_ssid && t_sections[i].bssid === w_bssid) { value = t_sections[i]['enabled']; value = (value == 0 ? 1 : 0); @@ -39,14 +60,14 @@ function handleToggle(sid) { remove wireless and stale travelmate sections */ function handleRemove(sid) { - var w_sections, t_sections, match, row; + let w_sections, t_sections, match, row; uci.remove('wireless', sid); w_sections = uci.sections('wireless', 'wifi-iface'); t_sections = uci.sections('travelmate', 'uplink'); - for (var i = 0; i < t_sections.length; i++) { + for (let i = 0; i < t_sections.length; i++) { match = false; - for (var j = 0; j < w_sections.length; j++) { + for (let j = 0; j < w_sections.length; j++) { if (t_sections[i].device === w_sections[j].device && t_sections[i].ssid === w_sections[j].ssid && t_sections[i].bssid === w_sections[j].bssid) { match = true; break; @@ -66,26 +87,26 @@ function handleRemove(sid) { add missing travelmate sections */ function handleSectionsAdd(iface) { - var w_sections, t_sections, match; + let w_sections, t_sections, match; w_sections = uci.sections('wireless', 'wifi-iface'); t_sections = uci.sections('travelmate', 'uplink'); - for (var i = 0; i < w_sections.length; i++) { + for (let i = 0; i < w_sections.length; i++) { if (w_sections[i].mode !== 'sta' || w_sections[i].network !== iface) { continue; } match = false; - for (var j = 0; j < t_sections.length; j++) { + for (let j = 0; j < t_sections.length; j++) { if (w_sections[i].device === t_sections[j].device && w_sections[i].ssid === t_sections[j].ssid && w_sections[i].bssid === t_sections[j].bssid) { match = true; break; } } if (match === false) { - var vpn_stdservice = uci.get('travelmate', 'global', 'trm_stdvpnservice'); - var vpn_stdiface = uci.get('travelmate', 'global', 'trm_stdvpniface'); - var sid = uci.add('travelmate', 'uplink'); + let vpn_stdservice = uci.get('travelmate', 'global', 'trm_stdvpnservice'); + let vpn_stdiface = uci.get('travelmate', 'global', 'trm_stdvpniface'); + let sid = uci.add('travelmate', 'uplink'); uci.set('travelmate', sid, 'enabled', '1'); uci.set('travelmate', sid, 'device', w_sections[i].device); @@ -106,14 +127,14 @@ function handleSectionsAdd(iface) { update travelmate sections */ function handleSectionsVal(action, section_id, option, value) { - var date, oldValue, w_device, w_ssid, w_bssid, t_sections; + let date, oldValue, w_device, w_ssid, w_bssid, t_sections; w_device = uci.get('wireless', section_id, 'device'); w_ssid = uci.get('wireless', section_id, 'ssid'); w_bssid = uci.get('wireless', section_id, 'bssid'); t_sections = uci.sections('travelmate', 'uplink'); - for (var i = 0; i < t_sections.length; i++) { + for (let i = 0; i < t_sections.length; i++) { if (t_sections[i].device === w_device && t_sections[i].ssid === w_ssid && t_sections[i].bssid === w_bssid) { if (action === 'get') { return t_sections[i][option]; @@ -159,9 +180,9 @@ function handleStatus() { uci.load('wireless'), uci.load('travelmate') ]); - var rows, item, value; + let rows, item, value; rows = document.querySelectorAll('.cbi-section-table-row[data-sid]'); - for (var i = 0; i < rows.length; i++) { + for (let i = 0; i < rows.length; i++) { item = rows[i].querySelector('.cbi-value-field[data-title="Enabled"]'); value = handleSectionsVal('get', rows[i].getAttribute('data-sid'), 'enabled'); item.textContent = (value == 0 ? 'No' : 'Yes'); @@ -174,16 +195,16 @@ function handleStatus() { if (res) { L.resolveDefault(fs.read('/tmp/trm_runtime.json'), null).then(function (res) { if (res) { - var info = JSON.parse(res); + let info = JSON.parse(res); if (info) { - var t_device, t_ssid, t_bssid, oldUplinkView, newUplinkView, uplinkColor, + let t_device, t_ssid, t_bssid, newUplinkView, uplinkColor, uplinkId = info.data.station_id.trim().split('/'), oldUplinkView = document.getElementsByName('uplinkStation'), w_sections = uci.sections('wireless', 'wifi-iface'), vpnStatus = info.data.ext_hooks.substr(13, 1); t_device = uplinkId[0]; t_bssid = uplinkId[uplinkId.length - 1]; - for (var i = 1; i < uplinkId.length - 1; i++) { + for (let i = 1; i < uplinkId.length - 1; i++) { if (!t_ssid) { t_ssid = uplinkId[i]; } @@ -199,7 +220,7 @@ function handleStatus() { } else { uplinkColor = (vpnStatus === "✔" ? 'rgb(68, 170, 68)' : 'rgb(51, 119, 204)'); - for (var i = 0; i < w_sections.length; i++) { + for (let i = 0; i < w_sections.length; i++) { newUplinkView = document.getElementById('cbi-wireless-' + w_sections[i]['.name']); if (t_device === w_sections[i].device && t_ssid === w_sections[i].ssid && t_bssid === (w_sections[i].bssid || '-')) { if (oldUplinkView.length === 0 && newUplinkView) { @@ -229,15 +250,14 @@ function handleStatus() { return view.extend({ load: function () { return Promise.all([ - L.resolveDefault(fs.exec('/etc/init.d/travelmate', ['assoc']), null), uci.load('wireless'), uci.load('travelmate') ]); }, render: function (result) { - var m, s, o, - iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'; + var m, s, o + let iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'; m = new form.Map('wireless'); m.chain('travelmate'); @@ -254,21 +274,23 @@ return view.extend({ s.tab('travelmate', _('Travelmate Settings')); s.tab('vpn', _('VPN Settings')); s.renderRowActions = function (section_id) { - var btns; - btns = [ + let btns = [ E('button', { - 'class': 'btn cbi-button drag-handle center', + 'class': 'btn cbi-button drag-handle right', + 'style': 'float:none;margin-right:.4em;', 'title': _('Drag to reorder'), 'style': 'cursor:move', 'disabled': this.map.readonly || null }, '☰'), E('button', { 'class': 'cbi-button cbi-button-action important', + 'style': 'float:none;margin-right:.4em;', 'title': _('Edit this network'), 'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id) }, _('Edit')), E('button', { 'class': 'cbi-button cbi-button-apply', + 'style': 'float:none;margin-right:.4em;', 'title': _('Enable/Disable this network'), 'click': ui.createHandlerFn(this, handleToggle, section_id) }, _('On/Off')), @@ -305,81 +327,75 @@ return view.extend({ o.readonly = true; o = s.taboption('wireless', form.ListValue, 'encryption', _('Encryption')); - o.value('sae', _('WPA3 Pers. (SAE)')); - o.value('sae-mixed', _('WPA2/WPA3 Pers. (CCMP)')); - o.value('psk2', _('WPA2 Pers.')); - o.value('psk2+ccmp', _('WPA2 Pers. (CCMP)')); - o.value('psk2+tkip', _('WPA2 Pers. (TKIP)')); - o.value('psk', _('WPA Pers.')); - o.value('psk+ccmp', _('WPA Pers. (CCMP)')); - o.value('psk+tkip', _('WPA Pers. (TKIP)')); - o.value('psk-mixed+ccmp', _('WPA/WPA2 Pers. (CCMP)')); - o.value('psk-mixed+tkip', _('WPA/WPA2 Pers. (TKIP)')); - o.value('wpa3', _('WPA3 Ent. (CCMP)')); - o.value('wpa3-mixed', _('WPA2/WPA3 Ent. (CCMP)')); - o.value('wpa2', _('WPA2 Ent.')); - o.value('wpa2+ccmp', _('WPA2 Ent. (CCMP)')); - o.value('wpa2+tkip', _('WPA2 Ent. (TKIP)')); - o.value('wpa+ccmp', _('WPA Ent. (CCMP)')); - o.value('wpa+tkip', _('WPA Ent. (TKIP)')); - o.value('wpa-mixed+ccmp', _('WPA/WPA2 Ent. (CCMP)')); - o.value('wpa-mixed+tkip', _('WPA/WPA2 Ent. (TKIP)')); - o.value('owe', _('OWE')); - o.value('none', _('none')); + o.value('sae', _('WPA3 PSK (SAE)')); + o.value('sae-mixed', _('Mixed WPA2/WPA3 PSK (CCMP)')); + o.value('psk2+ccmp', _('WPA2 PSK (CCMP)')); + o.value('psk2+tkip', _('WPA2 PSK (TKIP)')); + o.value('psk+ccmp', _('WPA PSK (CCMP)')); + o.value('psk+tkip', _('WPA PSK (TKIP)')); + o.value('psk-mixed+ccmp', _('Mixed WPA/WPA2 PSK (CCMP)')); + o.value('psk-mixed+tkip', _('Mixed WPA/WPA2 PSK (TKIP)')); + o.value('wpa3', _('WPA3 802.1X')); + o.value('wpa3-mixed', _('Mixed WPA2/WPA3 802.1X')); + o.value('wpa2+ccmp', _('WPA2 802.1X (CCMP)')); + o.value('wpa2+tkip', _('WPA2 802.1X (TKIP)')); + o.value('wpa+ccmp', _('WPA 802.1X (CCMP)')); + o.value('wpa+tkip', _('WPA 802.1X (TKIP)')); + o.value('wpa-mixed+ccmp', _('Mixed WPA/WPA2 802.1X (CCMP)')); + o.value('wpa-mixed+tkip', _('Mixed WPA/WPA2 802.1X (TKIP)')); + o.value('owe', _('WPA3 OWE')); + o.value('none', _('Open')); o.default = 'none'; o.textvalue = function (section_id) { - var cfgvalue = this.map.data.get('wireless', section_id, 'encryption'); + let cfgvalue = this.map.data.get('wireless', section_id, 'encryption'); switch (cfgvalue) { case 'sae': - cfgvalue = 'WPA3 Pers. (SAE)'; + cfgvalue = 'WPA3 PSK (SAE)'; break; case 'sae-mixed': - cfgvalue = 'WPA2/WPA3 Pers. (CCMP)'; - break; - case 'psk2': - cfgvalue = 'WPA2 Pers.'; + cfgvalue = 'Mixed WPA2/WPA3 PSK (CCMP)'; break; case 'psk2+ccmp': - cfgvalue = 'WPA2 Pers. (CCMP)'; + cfgvalue = 'WPA2 PSK (CCMP)'; break; case 'psk2+tkip': - cfgvalue = 'WPA2 Pers. (TKIP)'; + cfgvalue = 'WPA2 PSK (TKIP)'; + break; + case 'psk+ccmp': + cfgvalue = 'WPA PSK (CCMP)'; break; - case 'psk': - cfgvalue = 'WPA Pers.'; + case 'psk+tkip': + cfgvalue = 'WPA PSK (TKIP)'; break; - case 'psk-mixed+ccmp': - cfgvalue = 'WPA/WPA2 Pers. (CCMP)'; + case 'psk-mixed+ccmp': + cfgvalue = 'Mixed WPA/WPA2 PSK (CCMP)'; break; case 'psk-mixed+tkip': - cfgvalue = 'WPA/WPA2 Pers. (TKIP)'; + cfgvalue = 'Mixed WPA/WPA2 PSK (TKIP)'; break; case 'wpa3': - cfgvalue = 'WPA3 Ent. (CCMP)'; + cfgvalue = 'WPA3 802.1X'; break; case 'wpa3-mixed': - cfgvalue = 'WPA2/WPA3 Ent. (CCMP)'; - break; - case 'wpa2': - cfgvalue = 'WPA2 Ent.'; + cfgvalue = 'Mixed WPA2/WPA3 802.1X'; break; case 'wpa2+ccmp': - cfgvalue = 'WPA2 Ent. (CCMP)'; + cfgvalue = 'WPA2 802.1X (CCMP)'; break; case 'wpa2+tkip': - cfgvalue = 'WPA2 Ent. (TKIP)'; + cfgvalue = 'WPA2 802.1X (TKIP)'; break; case 'wpa+ccmp': - cfgvalue = 'WPA Ent. (CCMP)'; + cfgvalue = 'WPA 802.1X (CCMP)'; break; case 'wpa+tkip': - cfgvalue = 'WPA Ent. (TKIP)'; + cfgvalue = 'WPA 802.1X (TKIP)'; break; case 'wpa-mixed+ccmp': - cfgvalue = 'WPA/WPA2 Ent. (CCMP)'; + cfgvalue = 'Mixed WPA/WPA2 802.1X (CCMP)'; break; case 'wpa-mixed+tkip': - cfgvalue = 'WPA/WPA2 Ent. (TKIP)'; + cfgvalue = 'Mixed WPA/WPA2 802.1X (TKIP)'; break; case 'owe': cfgvalue = 'WPA3 OWE (CCMP)'; @@ -487,11 +503,6 @@ return view.extend({ /* modal travelmate tab */ - var mac, mac_array = []; - if (result[0] && result[0].code === 0) { - mac_array = result[0].stdout.trim().split('\n'); - } - o = s.taboption('travelmate', form.Value, '_ssid', _('SSID')); o.modalonly = true; o.uciconfig = 'travelmate'; @@ -555,12 +566,6 @@ return view.extend({ o = s.taboption('travelmate', form.Value, '_macaddr', _('MAC Address'), _('Use the specified MAC address for this uplink.')); - for (var i = 0; i < mac_array.length; i++) { - if (mac_array[i].match(/^\s+([0-9A-Fa-f]{2}[:]?){5}[0-9A-Fa-f]{2}/)) { - mac = mac_array[i].slice(4).trim(); - o.value(mac); - } - } o.modalonly = true; o.uciconfig = 'travelmate'; o.ucisection = 'uplink'; @@ -624,7 +629,7 @@ return view.extend({ o.ucisection = 'uplink'; o.ucioption = 'script'; o.renderWidget = function (section_id, option_index, cfgvalue) { - var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, { + let browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, { id: this.cbid(section_id), name: this.cbid(section_id), show_hidden: this.show_hidden, @@ -728,16 +733,16 @@ return view.extend({ s.addremove = false; s.render = function () { return network.getWifiDevices().then(L.bind(function (radios) { - var radio, ifname, btns = []; - for (var i = 0; i < radios.length; i++) { + let radio, ifname, btns = []; + for (let i = 0; i < radios.length; i++) { radio = radios[i].sid; if (radio) { btns.push(E('button', { 'class': 'cbi-button cbi-button-apply', + 'style': 'float:none;margin-right:.4em;', 'id': radio, 'click': ui.createHandlerFn(this, 'handleScan', radio) - }, [_('Scan on ' + radio + '...')]), - '\xa0') + }, [_('Scan on ' + radio + '...')])) } } return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns)); @@ -749,7 +754,7 @@ return view.extend({ */ s.handleScan = function (radio) { poll.stop(); - var table = E('table', { 'class': 'table' }, [ + let table = E('table', { 'class': 'table' }, [ E('tr', { 'class': 'tr table-titles' }, [ E('th', { 'class': 'th col-1 middle left' }, _('Strength')), E('th', { 'class': 'th col-1 middle left hide-xs' }, _('Channel')), @@ -761,14 +766,14 @@ return view.extend({ ]); cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan on \'' + radio + '\'...'))); - var md = ui.showModal(_('Wireless Scan'), [ + let md = ui.showModal(_('Wireless Scan'), [ table, E('div', { 'class': 'right' }, [ E('button', { 'class': 'btn', + 'style': 'float:none;margin-right:.4em;', 'click': ui.hideModal }, _('Dismiss')), - '\xa0', E('button', { 'class': 'cbi-button cbi-button-positive important', 'click': L.bind(this.handleScan, this, radio) @@ -783,91 +788,84 @@ return view.extend({ .then(L.bind(function () { return L.resolveDefault(fs.read('/var/run/travelmate.scan'), '') .then(L.bind(function (res) { - var lines, strength, channel, encryption, tbl_encryption, bssid, ssid, tbl_ssid, rows = []; + let lines, strength, channel, bssid, wpa, rsn, cipher, auth = [], ssid, rows = []; if (res) { lines = res.split('\n'); - for (var i = 0; i < lines.length; i++) { + for (let i = 0; i < lines.length; i++) { if (lines[i].match(/^\s+[0-9]/)) { - encryption = lines[i].slice(80).trim(); - if (!encryption.includes('WEP')) { - strength = lines[i].slice(4, 7).trim(); - channel = lines[i].slice(15, 18).trim(); - bssid = lines[i].slice(60, 77).trim(); - ssid = lines[i].slice(25, 59).trim(); - if (ssid.startsWith('"')) { - ssid = ssid.slice(1, ssid.length - 1); - tbl_ssid = ssid; - } - else { - ssid = "hidden"; - tbl_ssid = "hidden"; - } - switch (encryption) { - case 'WPA3 PSK (SAE)': - encryption = 'sae'; - tbl_encryption = 'WPA3 Pers. (SAE)'; - break; - case 'mixed WPA2/WPA3 PSK/SAE (CCMP)': - encryption = 'sae-mixed'; - tbl_encryption = 'WPA2/WPA3 Pers. (CCMP)'; - break; - case 'WPA2 PSK (CCMP)': - encryption = 'psk2+ccmp'; - tbl_encryption = 'WPA2 Pers. (CCMP)'; - break; - case 'WPA2 PSK (TKIP)': - encryption = 'psk2+tkip'; - tbl_encryption = 'WPA2 Pers. (TKIP)'; - break; - case 'mixed WPA/WPA2 PSK (TKIP, CCMP)': - encryption = 'psk-mixed+ccmp'; - tbl_encryption = 'WPA/WPA2 Pers. (CCMP)'; - break; - case 'WPA PSK (CCMP)': - encryption = 'psk2+ccmp'; - tbl_encryption = 'WPA Pers. (CCMP)'; - break; - case 'WPA PSK (TKIP)': - encryption = 'psk2+tkip'; - tbl_encryption = 'WPA Pers. (TKIP)'; - break; - case 'WPA3 802.1X (CCMP)': - encryption = 'wpa3'; - tbl_encryption = 'WPA3 Ent. (CCMP)'; - break; - case 'mixed WPA2/WPA3 802.1X (CCMP)': - encryption = 'wpa3-mixed'; - tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)'; - break; - case 'WPA2 802.1X': - encryption = 'wpa2'; - tbl_encryption = 'WPA2 Ent.'; - break; - case 'WPA2 802.1X (CCMP)': - encryption = 'wpa2+ccmp'; - tbl_encryption = 'WPA2 Ent. (CCMP)'; - break; - case 'WPA3 OWE (CCMP)': - encryption = 'owe'; - tbl_encryption = 'WPA3 OWE (CCMP)'; - break; - case 'none': - encryption = 'none'; - tbl_encryption = 'none'; - break; - } - rows.push([ - strength, - channel, - tbl_ssid, - bssid, - tbl_encryption, - E('div', { 'class': 'right' }, E('button', { + strength = lines[i].slice(0,3).trim(); + channel = lines[i].slice(3,7).trim(); + bssid = lines[i].slice(7,25).trim(); + rsn = lines[i].slice(26,27).trim(); + wpa = lines[i].slice(28,29).trim(); + cipher = lines[i].slice(29,40).trim(); + auth = lines[i].slice(40,71).trim().split(','); + ssid = lines[i].slice(71).trim(); + let encryption = 'Open'; + let tbl_encryption = ''; + let hasWPA = wpa === '+'; + let hasRSN = rsn === '+'; + let hasPSK = auth.some(a => a.includes("PSK")); + let hasSAE = auth.includes("SAE") || auth.some(a => a.includes("SHA-256")); + let has8021x = auth.some(a => a.includes("802.1X")); + let hasSuiteB = auth.some(a => a.includes("SUITE-B")); + let hasOWE = auth.includes("OWE"); + let resCipher = resolveCipher(cipher); + if (cipher === '-' && !hasWPA && !hasRSN) { + tbl_encryption = 'Open'; + encryption = 'none'; + } else if (hasOWE) { + tbl_encryption = `WPA3 OWE (${resCipher})`; + encryption = 'owe'; + } else if (hasSuiteB) { + tbl_encryption = `WPA3 Enterprise (${resCipher})`; + encryption = 'wpa3'; + } else if (hasSAE && hasPSK && !has8021x) { + tbl_encryption = `Mixed WPA2/WPA3 PSK (${resCipher})`; + encryption = 'sae-mixed'; + } else if (hasSAE && has8021x) { + tbl_encryption = `Mixed WPA2/WPA3 802.1X (${resCipher})`; + encryption = 'wpa3-mixed'; + } else if (hasSAE && !hasPSK && !has8021x) { + tbl_encryption = `WPA3 PSK (${resCipher})`; + encryption = 'sae'; + } else if (hasSAE && !hasPSK && has8021x) { + tbl_encryption = `WPA3 802.1X (${resCipher})`; + encryption = 'wpa3'; + } else if (has8021x && hasRSN && hasWPA) { + tbl_encryption = `Mixed WPA/WPA2 802.1X (${resCipher})`; + encryption = (resCipher === 'CCMP') ? 'wpa-mixed+ccmp' : 'wpa-mixed+tkip'; + } else if (has8021x && hasRSN) { + tbl_encryption = `WPA2 802.1X (${resCipher})`; + encryption = (resCipher === 'CCMP' || resCipher === 'GCMP-256') ? 'wpa2+ccmp' : 'wpa2+tkip'; + } else if (has8021x) { + tbl_encryption = `WPA 802.1X (${resCipher})`; + encryption = (resCipher === 'CCMP') ? 'wpa+ccmp' : 'wpa+tkip'; + } else if (hasPSK && hasRSN && hasWPA) { + tbl_encryption = `Mixed WPA/WPA2 PSK (${resCipher})`; + encryption = (resCipher === 'CCMP') ? 'psk-mixed+ccmp' : 'psk-mixed+tkip'; + } else if (hasPSK && hasRSN) { + tbl_encryption = `WPA2 PSK (${resCipher})`; + encryption = (resCipher === 'CCMP' || resCipher === 'GCMP-256') ? 'psk2+ccmp' : 'psk2+tkip'; + } else if (hasPSK && hasWPA) { + tbl_encryption = `WPA PSK (${resCipher})`; + encryption = (resCipher === 'CCMP') ? 'psk+ccmp' : 'psk+tkip'; + } else { + tbl_encryption = 'Unknown'; + encryption = 'none'; + } + rows.push([ + strength, + channel, + ssid, + bssid, + tbl_encryption, + E('div', { 'class': 'right' }, + E('button', { 'class': 'cbi-button cbi-button-action', 'click': ui.createHandlerFn(this, 'handleAdd', radio, iface, ssid, bssid, encryption) }, _('Add Uplink...'))) ]); - } } } } @@ -932,27 +930,24 @@ return view.extend({ o2.default = bssid; o2 = s2.option(form.ListValue, 'encryption', _('Encryption')); - o2.value('sae', _('WPA3 Pers. (SAE)')); - o2.value('sae-mixed', _('WPA2/WPA3 Pers. (CCMP)')); - o2.value('psk2', _('WPA2 Pers.')); - o2.value('psk2+ccmp', _('WPA2 Pers. (CCMP)')); - o2.value('psk2+tkip', _('WPA2 Pers. (TKIP)')); - o2.value('psk', _('WPA Pers.')); - o2.value('psk+ccmp', _('WPA Pers. (CCMP)')); - o2.value('psk+tkip', _('WPA Pers. (TKIP)')); - o2.value('psk-mixed+ccmp', _('WPA/WPA2 Pers. (CCMP)')); - o2.value('psk-mixed+tkip', _('WPA/WPA2 Pers. (TKIP)')); - o2.value('wpa3', _('WPA3 Ent.')); - o2.value('wpa3-mixed', _('WPA2/WPA3 Ent.')); - o2.value('wpa2', _('WPA2 Ent.')); - o2.value('wpa2+ccmp', _('WPA2 Ent. (CCMP)')); - o2.value('wpa2+tkip', _('WPA2 Ent. (TKIP)')); - o2.value('wpa+ccmp', _('WPA Ent. (CCMP)')); - o2.value('wpa+tkip', _('WPA Ent. (TKIP)')); - o2.value('wpa-mixed+ccmp', _('WPA/WPA2 Ent. (CCMP)')); - o2.value('wpa-mixed+tkip', _('WPA/WPA2 Ent. (TKIP)')); - o2.value('owe', _('WPA3 OWE (CCMP)')); - o2.value('none', _('none')); + o2.value('sae', _('WPA3 PSK (SAE)')); + o2.value('sae-mixed', _('Mixed WPA2/WPA3 PSK (CCMP)')); + o2.value('psk2+ccmp', _('WPA2 PSK (CCMP)')); + o2.value('psk2+tkip', _('WPA2 PSK (TKIP)')); + o2.value('psk+ccmp', _('WPA PSK (CCMP)')); + o2.value('psk+tkip', _('WPA PSK (TKIP)')); + o2.value('psk-mixed+ccmp', _('Mixed WPA/WPA2 PSK (CCMP)')); + o2.value('psk-mixed+tkip', _('Mixed WPA/WPA2 PSK (TKIP)')); + o2.value('wpa3', _('WPA3 802.1X')); + o2.value('wpa3-mixed', _('Mixed WPA2/WPA3 802.1X')); + o2.value('wpa2+ccmp', _('WPA2 802.1X (CCMP)')); + o2.value('wpa2+tkip', _('WPA2 802.1X (TKIP)')); + o2.value('wpa+ccmp', _('WPA 802.1X (CCMP)')); + o2.value('wpa+tkip', _('WPA 802.1X (TKIP)')); + o2.value('wpa-mixed+ccmp', _('Mixed WPA/WPA2 802.1X (CCMP)')); + o2.value('wpa-mixed+tkip', _('Mixed WPA/WPA2 802.1X (TKIP)')); + o2.value('owe', _('WPA3 OWE')); + o2.value('none', _('Open')); o2.default = encryption; o2 = s2.option(form.Value, 'key', _('Password')); @@ -1039,9 +1034,9 @@ return view.extend({ E('div', { 'class': 'right' }, [ E('button', { 'class': 'btn', + 'style': 'float:none;margin-right:.4em;', 'click': ui.hideModal }, _('Dismiss')), - '\xa0', E('button', { 'class': 'cbi-button cbi-button-positive important', 'click': ui.createHandlerFn(this, 'handleCommit', m2) @@ -1088,7 +1083,7 @@ return view.extend({ } return ui.hideModal(); } - for (var i = 0; i < w_sections.length; i++) { + for (let i = 0; i < w_sections.length; i++) { if (w_sections[i].device === device && w_sections[i].ssid === ssid) { if (ignore_bssid === '1' || (ignore_bssid === '0' && w_sections[i].bssid === bssid)) { ui.addNotification(null, E('p', 'Duplicate wireless entry, the uplink station could not be saved.'), 'error'); @@ -1134,7 +1129,7 @@ return view.extend({ .then(L.bind(this.map.load, this.map)) .then(L.bind(this.map.reset, this.map)) .then(function () { - var row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(new_sid)); + let row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(new_sid)); row.setAttribute('style', 'opacity: 0.5; color: #4a4 !important;'); }) .then(ui.hideModal) diff --git a/applications/luci-app-travelmate/root/usr/share/rpcd/acl.d/luci-app-travelmate.json b/applications/luci-app-travelmate/root/usr/share/rpcd/acl.d/luci-app-travelmate.json index 2283b377c6..35fe60aeb9 100644 --- a/applications/luci-app-travelmate/root/usr/share/rpcd/acl.d/luci-app-travelmate.json +++ b/applications/luci-app-travelmate/root/usr/share/rpcd/acl.d/luci-app-travelmate.json @@ -20,12 +20,8 @@ "/sbin/ifup *": [ "exec" ], "/etc/init.d/travelmate start" : [ "exec" ], "/etc/init.d/travelmate stop" : [ "exec" ], - "/etc/init.d/travelmate reload" : [ "exec" ], - "/etc/init.d/travelmate restart" : [ "exec" ], - "/etc/init.d/travelmate assoc" : [ "exec" ], "/etc/init.d/travelmate setup [0-9a-z_]* [0-9a-z_]* [0-9]*" : [ "exec" ], - "/etc/init.d/travelmate scan radio[0-9]" : [ "exec" ], - "/usr/bin/qrencode --inline --8bit --type=SVG --output=- *" : [ "exec" ] + "/etc/init.d/travelmate scan radio[0-1]" : [ "exec" ] }, "uci": [ "travelmate", "wireless" ] } -- 2.30.2