luci-app-travelmate: sync with travelmate 2.0.5

* support new features of travelmate 2.0.5
* made the station manager more comfortable
* a few minor bugfixes
* sync translations

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken 2021-08-11 18:28:07 +02:00
parent 7f5becc69e
commit 863238ee51
No known key found for this signature in database
GPG key ID: 9D71CD547BFAE684
36 changed files with 9867 additions and 8098 deletions

View file

@ -10,30 +10,32 @@
/* /*
button handling button handling
*/ */
async function handleAction(ev) { function handleAction(ev) {
var ifaceValue;
if (ev === 'restart') { if (ev === 'restart') {
fs.exec_direct('/etc/init.d/travelmate', [ev]) ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan');
return fs.exec('/sbin/ifup', [ifaceValue])
.then(fs.exec('/etc/init.d/travelmate', ['restart']))
} }
if (ev === 'setup') { if (ev === 'setup') {
var ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || ''); ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || '');
L.ui.showModal(_('Interface Wizard'), [ L.ui.showModal(_('Interface Wizard'), [
E('p', _('To use Travelmate, you have to set up an uplink interface once. This wizard creates an IPv4- and an IPv6 alias network interface with all required network- and firewall settings.')), E('p', _('To use Travelmate, you have to set up an uplink interface once. This wizard creates an IPv4- and an IPv6 alias network interface with all required network- and firewall settings.')),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [ E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [ E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'id': 'iface', 'placeholder': 'trm_wwan', 'value': ifaceValue, 'maxlength': '15', 'spellcheck': 'false' }, [ E('input', { 'class': 'cbi-input-text', 'id': 'iface', 'placeholder': 'trm_wwan', 'value': ifaceValue, 'maxlength': '15', 'spellcheck': 'false' }),
]), '\xa0\xa0\xa0',
'\xa0\xa0\xa0', _('The uplink interface name')
_('The uplink interface name')
]), ]),
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [ E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'id': 'zone', 'placeholder': 'wan', 'maxlength': '15', 'spellcheck': 'false' }), E('input', { 'class': 'cbi-input-text', 'id': 'zone', 'placeholder': 'wan', 'maxlength': '15', 'spellcheck': 'false' }),
'\xa0\xa0\xa0', '\xa0\xa0\xa0',
_('The firewall zone name') _('The firewall zone name')
]), ]),
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [ E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'id': 'metric', 'placeholder': '100', 'maxlength': '3', 'spellcheck': 'false' }), E('input', { 'class': 'cbi-input-text', 'id': 'metric', 'placeholder': '100', 'maxlength': '3', 'spellcheck': 'false' }),
'\xa0\xa0\xa0', '\xa0\xa0\xa0',
_('The interface metric') _('The interface metric')
]) ])
]), ]),
E('div', { 'class': 'right' }, [ E('div', { 'class': 'right' }, [
@ -44,18 +46,18 @@ async function handleAction(ev) {
' ', ' ',
E('button', { E('button', {
'class': 'cbi-button cbi-button-positive important', 'class': 'cbi-button cbi-button-positive important',
'click': ui.createHandlerFn(this, function(ev) { 'click': ui.createHandlerFn(this, function (ev) {
var iface = document.getElementById('iface').value || 'trm_wwan', var iface = document.getElementById('iface').value || 'trm_wwan',
zone = document.getElementById('zone').value || 'wan', zone = document.getElementById('zone').value || 'wan',
metric = document.getElementById('metric').value || '100'; metric = document.getElementById('metric').value || '100';
L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['setup', iface, zone, metric])) L.resolveDefault(fs.exec('/etc/init.d/travelmate', ['setup', iface, zone, metric]))
.then(function(res) { .then(function (res) {
if (res) { if (res) {
ui.addNotification(null, E('p', res.trim() + '.'), 'error'); ui.addNotification(null, E('p', res.trim() + '.'), 'error');
} else { } else {
ui.addNotification(null, E('p', _('The uplink interface has been updated.')), 'info'); ui.addNotification(null, E('p', _('The uplink interface has been updated.')), 'info');
} }
}); });
L.hideModal(); L.hideModal();
}) })
}, _('Save')) }, _('Save'))
@ -67,28 +69,28 @@ async function handleAction(ev) {
if (ev === 'qrcode') { if (ev === 'qrcode') {
return Promise.all([ return Promise.all([
uci.load('wireless') uci.load('wireless')
]).then(function() { ]).then(function () {
var w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result, var w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result,
w_sections = uci.sections('wireless', 'wifi-iface'), w_sections = uci.sections('wireless', 'wifi-iface'),
optionsAP = [E('option', { value: '' }, [_('-- AP Selection --')])]; optionsAP = [E('option', { value: '' }, [_('-- AP Selection --')])];
for (var i = 0; i < w_sections.length; i++) { for (var i = 0; i < w_sections.length; i++) {
if (w_sections[i].mode === 'ap' && w_sections[i].disabled !== '1') { if (w_sections[i].mode === 'ap' && w_sections[i].disabled !== '1') {
w_sid = i; w_sid = i;
w_device = w_sections[i].device; w_device = w_sections[i].device;
w_ssid = w_sections[i].ssid; w_ssid = w_sections[i].ssid;
optionsAP.push(E('option', { value: w_sid }, w_device + ', ' + w_ssid)); optionsAP.push(E('option', { value: w_sid }, w_device + ', ' + w_ssid));
} }
} }
var selectAP = E('select', { var selectAP = E('select', {
id: 'selectID', id: 'selectID',
class: 'cbi-input-select', class: 'cbi-input-select',
change: function(ev) { change: function (ev) {
result = document.getElementById('qrcode'); result = document.getElementById('qrcode');
if (document.getElementById("selectID").value) { if (document.getElementById("selectID").value) {
w_sid = document.getElementById("selectID").value; w_sid = document.getElementById("selectID").value;
w_ssid = w_sections[w_sid].ssid; w_ssid = w_sections[w_sid].ssid;
w_enc = w_sections[w_sid].encryption; w_enc = w_sections[w_sid].encryption;
w_key = w_sections[w_sid].key; w_key = w_sections[w_sid].key;
w_hidden = (w_sections[w_sid].hidden == 1 ? 'true' : 'false'); w_hidden = (w_sections[w_sid].hidden == 1 ? 'true' : 'false');
if (w_enc.startsWith('psk')) { if (w_enc.startsWith('psk')) {
w_enc = 'WPA'; w_enc = 'WPA';
@ -97,17 +99,17 @@ async function handleAction(ev) {
w_enc = 'nopass'; w_enc = 'nopass';
w_key = 'nokey'; w_key = 'nokey';
} }
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) { 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) { if (res) {
result.innerHTML = res.trim(); result.innerHTML = res.trim();
} }
else { else {
result.innerHTML = _('The QR-Code could not be generated!'); result.textContent = _('The QR-Code could not be generated!');
} }
}); });
} }
else { else {
result.innerHTML = ''; result.textContent = '';
} }
} }
}, optionsAP); }, optionsAP);
@ -135,13 +137,13 @@ async function handleAction(ev) {
} }
return view.extend({ return view.extend({
load: function() { load: function () {
return Promise.all([ return Promise.all([
uci.load('travelmate') uci.load('travelmate')
]); ]);
}, },
render: function(result) { render: function (result) {
var m, s, o; var m, s, o;
m = new form.Map('travelmate', 'Travelmate', _('Configuration of the travelmate package to enable travel router functionality. \ m = new form.Map('travelmate', 'Travelmate', _('Configuration of the travelmate package to enable travel router functionality. \
@ -151,11 +153,11 @@ return view.extend({
/* /*
poll runtime information poll runtime information
*/ */
pollData: poll.add(function() { pollData: poll.add(function () {
return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function(res) { return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) {
var status = document.getElementById('status'); var status = document.getElementById('status');
if (res) { if (res) {
L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function(res) { L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) {
if (res) { if (res) {
var info = JSON.parse(res); var info = JSON.parse(res);
if (status && info) { if (status && info) {
@ -206,12 +208,6 @@ return view.extend({
} }
}); });
} }
else {
if (status && status.classList.contains("spinning")) {
status.textContent = '-';
status.classList.remove("spinning");
}
}
}); });
}, 1); }, 1);
@ -219,53 +215,68 @@ return view.extend({
runtime information and buttons runtime information and buttons
*/ */
s = m.section(form.NamedSection, 'global'); s = m.section(form.NamedSection, 'global');
s.render = L.bind(function(view, section_id) { s.render = L.bind(function (view, section_id) {
return E('div', { 'class': 'cbi-section' }, [ return E('div', { 'class': 'cbi-section' }, [
E('h3', _('Information')), E('h3', _('Information')),
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')), E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')),
E('div', { 'class': 'cbi-value-field', 'id': 'status', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'color:#37c' }, '\xa0')
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ ]),
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')), E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')),
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'color:#37c' }, '-')
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station MAC')), ]),
E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station MAC')),
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interface')), E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'color:#37c' }, '-')
E('div', { 'class': 'cbi-value-field', 'id': 'station_interface', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), ]),
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')), E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interface')),
E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), E('div', { 'class': 'cbi-value-field', 'id': 'station_interface', 'style': 'color:#37c' }, '-')
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ ]),
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')), E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')),
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'color:#37c' }, '-')
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Ext. Hooks')), ]),
E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')),
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')), E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'color:#37c' }, '-')
E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'font-weight: bold;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('div', { class: 'right' }, [ E('div', { class: 'right' }, [
E('button', { E('button', {
'class': 'cbi-button cbi-button-apply', 'class': 'cbi-button cbi-button-apply',
'id': 'btn_suspend', 'id': 'btn_suspend',
'click': ui.createHandlerFn(this, function() { 'click': ui.createHandlerFn(this, function () {
L.resolveDefault(fs.stat('/usr/bin/qrencode'), null).then(function(res) { L.resolveDefault(fs.stat('/usr/bin/qrencode'), null).then(function (res) {
if (res) { if (res) {
return handleAction('qrcode'); return handleAction('qrcode');
} }
return ui.addNotification(null, E('p', _('Please install the separate \'qrencode\' package.')), 'info'); return ui.addNotification(null, E('p', _('Please install the separate \'qrencode\' package.')), 'info');
}) })
}) })
}, [ _('AP QR-Codes...') ]), }, [_('AP QR-Codes...')]),
'\xa0', '\xa0',
E('button', { E('button', {
'class': 'cbi-button cbi-button-reset', 'class': 'cbi-button cbi-button-negative',
'click': ui.createHandlerFn(this, function() { 'click': ui.createHandlerFn(this, function () {
return handleAction('restart');
})
}, [_('Restart Interface')]),
'\xa0',
E('button', {
'class': 'cbi-button cbi-button-negative',
'click': ui.createHandlerFn(this, function () {
return handleAction('setup'); return handleAction('setup');
}) })
}, [ _('Interface Wizard...') ]) }, [_('Interface Wizard...')])
]) ])
]); ]);
}, o, this); }, o, this);
@ -276,9 +287,8 @@ return view.extend({
*/ */
s = m.section(form.NamedSection, 'global', 'travelmate', _('Settings')); s = m.section(form.NamedSection, 'global', 'travelmate', _('Settings'));
s.addremove = false; s.addremove = false;
s.tab('general', _('General Settings')); s.tab('general', _('General Settings'));
s.tab('additional', _('Additional Settings')); s.tab('additional', _('Additional Settings'));
s.tab('adv_vpn', _('VPN Settings'), _('Please note: VPN connections require the separate setup of the <em>Wireguard</em> or <em>OpenVPN</em> package.<br /><p>&#xa0;</p>'));
s.tab('adv_email', _('E-Mail Settings'), _('Please note: E-Mail notifications require the separate setup of the <em>mstmp</em> package.<br /><p>&#xa0;</p>')); s.tab('adv_email', _('E-Mail Settings'), _('Please note: E-Mail notifications require the separate setup of the <em>mstmp</em> package.<br /><p>&#xa0;</p>'));
/* /*
@ -290,8 +300,11 @@ return view.extend({
o = s.taboption('general', form.Flag, 'trm_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.')); 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.rmempty = false;
o = s.taboption('general', form.Value, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order (e.g. \'radio1 radio0\').')); o = s.taboption('general', form.Value, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order.'));
o.placeholder = 'radio0'; 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.rmempty = 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\'.')); 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\'.'));
@ -307,13 +320,19 @@ return view.extend({
o.default = 1; o.default = 1;
o.rmempty = false; o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_randomize', _('Randomize MAC Addresses'), _('Generate a random unicast MAC address for each uplink connection.'));
o.default = 0;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_autoadd', _('AutoAdd Open Uplinks'), _('Automatically add open uplinks like hotel captive portals to your wireless config.')); o = s.taboption('general', form.Flag, 'trm_autoadd', _('AutoAdd Open Uplinks'), _('Automatically add open uplinks like hotel captive portals to your wireless config.'));
o.default = 0; o.default = 0;
o.rmempty = false; o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_randomize', _('Randomize MAC Addresses'), _('Generate a random unicast MAC address for each uplink connection.')); o = s.taboption('general', form.Value, 'trm_maxautoadd', _('Limit AutoAdd'), _('Limit the maximum number of automatically added open uplinks. To disable this limitation set it to \'0\'.'));
o.default = 0; o.depends('trm_autoadd', '1');
o.rmempty = false; o.placeholder = '5';
o.datatype = 'range(0,30)';
o.rmempty = true;
/* /*
additional settings tab additional settings tab
@ -349,19 +368,20 @@ return view.extend({
o.rmempty = true; o.rmempty = true;
o = s.taboption('additional', form.ListValue, 'trm_captiveurl', _('Captive Portal URL'), _('The selected URL will be used for connectivity- and captive portal checks.')); o = s.taboption('additional', form.ListValue, 'trm_captiveurl', _('Captive Portal URL'), _('The selected URL will be used for connectivity- and captive portal checks.'));
o.value('http://captive.apple.com', 'Apple (default)'); o.value('http://detectportal.firefox.com', 'Firefox (default)');
o.value('http://connectivity-check.ubuntu.com', 'Ubuntu'); o.value('http://connectivity-check.ubuntu.com', 'Ubuntu');
o.value('http://captive.apple.com', 'Apple');
o.value('http://connectivitycheck.android.com/generate_204', 'Google'); o.value('http://connectivitycheck.android.com/generate_204', 'Google');
o.value('http://www.msftncsi.com/ncsi.txt', 'Microsoft'); o.value('http://www.msftncsi.com/ncsi.txt', 'Microsoft');
o.optional = true; o.optional = true;
o.rmempty = 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 = 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:80.0) Gecko/20100101 Firefox/80.0', 'Firefox (default)'); o.value('Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0', 'Firefox (default)');
o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36', 'Chromium'); o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36', 'Chromium');
o.value('Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/85.0.4183.92 Mobile/15E148 Safari/604.1', 'Safari'); o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 11_5_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15', 'Safari');
o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44', 'Edge'); o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.55', 'Edge');
o.value('Mozilla/5.0 (Linux; Android 10; SM-G970F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.81 Mobile Safari/537.36 OPR/59.1.2926.54067', 'Opera'); o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 OPR/77.0.4054.277', 'Opera');
o.optional = true; o.optional = true;
o.rmempty = true; o.rmempty = true;
@ -374,30 +394,6 @@ return view.extend({
o.optional = true; o.optional = true;
o.rmempty = true; o.rmempty = true;
/*
advanced vpn settings tab
*/
o = s.taboption('adv_vpn', form.Flag, 'trm_vpn', _('VPN Hook'), _('Automatically handle VPN (re-) connections.'));
o.rmempty = false;
o = s.taboption('adv_vpn', form.ListValue, 'trm_vpnservice', _('VPN Service'));
o.depends('trm_vpn', '1');
o.value('wireguard');
o.value('openvpn');
o.rmempty = true;
o = s.taboption('adv_vpn', widgets.NetworkSelect, 'trm_vpniface', _('VPN Interface'), _('The logical vpn network interface, e.g. \'wg0\' or \'tun0\'.'));
o.depends('trm_vpn', '1');
o.unspecified = false;
o.nocreate = true;
o.rmempty = true;
o = s.taboption('adv_vpn', widgets.DeviceSelect, 'trm_landevice', _('LAN Device'), _('The lan network device, e.g. \'br-lan\'.'));
o.depends('trm_vpn', '1');
o.unspecified = false;
o.nocreate = true;
o.rmempty = true;
/* /*
advanced email settings tab advanced email settings tab
*/ */

View file

@ -8,11 +8,38 @@
'require network'; 'require network';
'require tools.widgets as widgets'; 'require tools.widgets as widgets';
/*
change the status of travelmate stations
*/
function handleToggle(sid) {
var 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++) {
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);
enabled = (value == 0 ? 'No' : 'Yes');
uci.set('travelmate', t_sections[i]['.name'], 'enabled', value);
uci.save().then(function () {
row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid));
element = row.querySelector('.cbi-value-field');
element.textContent = enabled;
row.setAttribute('style', 'opacity: 0.5; color: #37c !important;');
});
}
}
}
/* /*
remove wireless and stale travelmate sections remove wireless and stale travelmate sections
*/ */
function handleRemove(sid) { function handleRemove(sid) {
var w_sections, t_sections, match, changes; var w_sections, t_sections, match, row;
uci.remove('wireless', sid); uci.remove('wireless', sid);
w_sections = uci.sections('wireless', 'wifi-iface'); w_sections = uci.sections('wireless', 'wifi-iface');
@ -29,14 +56,17 @@ function handleRemove(sid) {
uci.remove('travelmate', t_sections[i]['.name']); uci.remove('travelmate', t_sections[i]['.name']);
} }
} }
uci.save(); return uci.save().then(function () {
row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid));
row.setAttribute('style', 'opacity: 0.5; color: #a22 !important;');
});
} }
/* /*
add missing travelmate sections add missing travelmate sections
*/ */
function handleSectionsAdd(iface) { function handleSectionsAdd(iface) {
var w_sections, t_sections, match, changes; var w_sections, t_sections, match;
w_sections = uci.sections('wireless', 'wifi-iface'); w_sections = uci.sections('wireless', 'wifi-iface');
t_sections = uci.sections('travelmate', 'uplink'); t_sections = uci.sections('travelmate', 'uplink');
@ -69,9 +99,9 @@ function handleSectionsAdd(iface) {
function handleSectionsVal(action, section_id, option, value) { function handleSectionsVal(action, section_id, option, value) {
var date, oldValue, w_device, w_ssid, w_bssid, t_sections; var date, oldValue, w_device, w_ssid, w_bssid, t_sections;
w_device = uci.get('wireless', section_id, 'device'); w_device = uci.get('wireless', section_id, 'device');
w_ssid = uci.get('wireless', section_id, 'ssid'); w_ssid = uci.get('wireless', section_id, 'ssid');
w_bssid = uci.get('wireless', section_id, 'bssid'); w_bssid = uci.get('wireless', section_id, 'bssid');
t_sections = uci.sections('travelmate', 'uplink'); t_sections = uci.sections('travelmate', 'uplink');
for (var i = 0; i < t_sections.length; i++) { for (var i = 0; i < t_sections.length; i++) {
@ -83,7 +113,7 @@ function handleSectionsVal(action, section_id, option, value) {
if (option === 'enabled') { if (option === 'enabled') {
oldValue = t_sections[i][option]; oldValue = t_sections[i][option];
if (oldValue !== value && value === '0') { if (oldValue !== value && value === '0') {
date = new Date(new Date().getTime() - new Date().getTimezoneOffset()*60*1000).toISOString().substr(0,19).replace(/-/g, '.').replace('T', '-'); date = new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60 * 1000).toISOString().substr(0, 19).replace(/-/g, '.').replace('T', '-');
uci.set('travelmate', t_sections[i]['.name'], 'con_end', date); uci.set('travelmate', t_sections[i]['.name'], 'con_end', date);
} }
else if (oldValue !== value && value === '1') { else if (oldValue !== value && value === '1') {
@ -103,10 +133,10 @@ function handleSectionsVal(action, section_id, option, value) {
update travelmate status update travelmate status
*/ */
function handleStatus() { function handleStatus() {
poll.add(function() { poll.add(function () {
L.resolveDefault(fs.stat('/var/state/travelmate.refresh'), null).then(function(res) { L.resolveDefault(fs.stat('/var/state/travelmate.refresh'), null).then(function (res) {
if (res) { if (res) {
L.resolveDefault(fs.read_direct('/var/state/travelmate.refresh'), null).then(function(res) { L.resolveDefault(fs.read_direct('/var/state/travelmate.refresh'), null).then(async function (res) {
fs.remove('/var/state/travelmate.refresh'); fs.remove('/var/state/travelmate.refresh');
if (res && res === 'ui_reload') { if (res && res === 'ui_reload') {
location.reload(); location.reload();
@ -116,36 +146,35 @@ function handleStatus() {
uci.unload('wireless'); uci.unload('wireless');
uci.unload('travelmate'); uci.unload('travelmate');
} }
return Promise.all([ await Promise.all([
uci.load('wireless'), uci.load('wireless'),
uci.load('travelmate') uci.load('travelmate')
]).then(function() { ]);
var item, value, var rows, item, value;
container = document.querySelectorAll('.cbi-section-table-row[data-sid]'); rows = document.querySelectorAll('.cbi-section-table-row[data-sid]');
for (var i = 0; i < container.length; i++) { for (var i = 0; i < rows.length; i++) {
item = container[i].querySelector('.cbi-value-field[data-title="Enabled"]'); item = rows[i].querySelector('.cbi-value-field[data-title="Enabled"]');
value = handleSectionsVal('get', container[i].getAttribute('data-sid'), 'enabled'); value = handleSectionsVal('get', rows[i].getAttribute('data-sid'), 'enabled');
item.textContent = (value == 0 ? 'No' : 'Yes'); item.textContent = (value == 0 ? 'No' : 'Yes');
} }
});
} }
}); });
} }
}); });
return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function(res) { return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) {
if (res) { if (res) {
L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function(res) { L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) {
if (res) { if (res) {
var info = JSON.parse(res); var info = JSON.parse(res);
if (info) { if (info) {
var t_device, t_ssid, t_bssid, oldUplinkView, newUplinkView, var t_device, t_ssid, t_bssid, oldUplinkView, newUplinkView,
uplinkId = info.data.station_id.trim().split('/'), uplinkId = info.data.station_id.trim().split('/'),
oldUplinkView = document.getElementsByName('uplinkStation'), oldUplinkView = document.getElementsByName('uplinkStation'),
w_sections = uci.sections('wireless', 'wifi-iface'); w_sections = uci.sections('wireless', 'wifi-iface');
t_device = uplinkId[0]; t_device = uplinkId[0];
t_bssid = uplinkId[uplinkId.length-1]; t_bssid = uplinkId[uplinkId.length - 1];
for (var i = 1; i < uplinkId.length-1; i++) { for (var i = 1; i < uplinkId.length - 1; i++) {
if (!t_ssid) { if (!t_ssid) {
t_ssid = uplinkId[i]; t_ssid = uplinkId[i];
} }
@ -185,29 +214,31 @@ function handleStatus() {
} }
return view.extend({ return view.extend({
load: function() { load: function () {
return Promise.all([ return Promise.all([
L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['assoc']), {}),
uci.load('wireless'), uci.load('wireless'),
uci.load('travelmate') uci.load('travelmate')
]); ]);
}, },
render: function() { render: function (result) {
var m, s, o, var m, s, o,
iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'; iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan';
m = new form.Map('wireless'); m = new form.Map('wireless');
m.chain('travelmate'); m.chain('travelmate');
s = m.section(form.GridSection, 'wifi-iface', null, _('Overview of all configured uplinks for travelmate.<br /> \ s = m.section(form.GridSection, 'wifi-iface', null, _('Overview of all configured uplinks for travelmate.<br /> \
You can edit, remove or prioritize existing uplinks by drag \&#38; drop and scan for new ones. The currently used uplink is emphasized in blue.')); You can edit, remove or prioritize existing uplinks by drag \&#38; drop and scan for new ones. The currently used uplink is emphasized in blue.'));
s.anonymous = true; s.anonymous = true;
s.sortable = true; s.sortable = true;
s.filter = function(section_id) { s.filter = function (section_id) {
return (uci.get('wireless', section_id, 'network') == iface && uci.get('wireless', section_id, 'mode') == 'sta'); return (uci.get('wireless', section_id, 'network') == iface && uci.get('wireless', section_id, 'mode') == 'sta');
}; };
s.tab('wireless', _('Wireless Settings')); s.tab('wireless', _('Wireless Settings'));
s.tab('travelmate', _('Travelmate Settings')); s.tab('travelmate', _('Travelmate Settings'));
s.renderRowActions = function(section_id) { s.tab('vpn', _('VPN Settings'));
s.renderRowActions = function (section_id) {
var btns; var btns;
btns = [ btns = [
E('button', { E('button', {
@ -221,11 +252,16 @@ return view.extend({
'title': _('Edit this network'), 'title': _('Edit this network'),
'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id) 'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id)
}, _('Edit')), }, _('Edit')),
E('button', {
'class': 'cbi-button cbi-button-apply',
'title': _('Enable/Disable this network'),
'click': ui.createHandlerFn(this, handleToggle, section_id)
}, _('On/Off')),
E('button', { E('button', {
'class': 'cbi-button cbi-button-negative remove', 'class': 'cbi-button cbi-button-negative remove',
'title': _('Delete this network'), 'title': _('Remove this network'),
'click': ui.createHandlerFn(this, handleRemove, section_id) 'click': ui.createHandlerFn(this, handleRemove, section_id)
}, _('Del')) }, _('Remove'))
]; ];
return E('td', { 'class': 'td middle cbi-section-actions' }, E('div', btns)); return E('td', { 'class': 'td middle cbi-section-actions' }, E('div', btns));
}; };
@ -235,10 +271,10 @@ return view.extend({
o.ucisection = 'uplink'; o.ucisection = 'uplink';
o.ucioption = 'enabled'; o.ucioption = 'enabled';
o.rmempty = false; o.rmempty = false;
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'enabled'); return handleSectionsVal('get', section_id, 'enabled');
} }
o.write = function(section_id, value) { o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'enabled', value); return handleSectionsVal('set', section_id, 'enabled', value);
} }
@ -275,7 +311,7 @@ return view.extend({
o.value('owe', _('OWE')); o.value('owe', _('OWE'));
o.value('none', _('none')); o.value('none', _('none'));
o.default = 'none'; o.default = 'none';
o.textvalue = function(section_id) { o.textvalue = function (section_id) {
var cfgvalue = this.map.data.get('wireless', section_id, 'encryption'); var cfgvalue = this.map.data.get('wireless', section_id, 'encryption');
switch (cfgvalue) { switch (cfgvalue) {
case 'sae': case 'sae':
@ -401,6 +437,11 @@ return view.extend({
/* /*
modal travelmate tab modal travelmate tab
*/ */
var mac, mac_array = [];
if (result[0]) {
mac_array = result[0].trim().split('\n');
}
o = s.taboption('travelmate', form.Value, '_ssid', _('SSID')); o = s.taboption('travelmate', form.Value, '_ssid', _('SSID'));
o.modalonly = true; o.modalonly = true;
o.uciconfig = 'travelmate'; o.uciconfig = 'travelmate';
@ -408,7 +449,7 @@ return view.extend({
o.ucioption = 'ssid'; o.ucioption = 'ssid';
o.rmempty = false; o.rmempty = false;
o.readonly = true; o.readonly = true;
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'ssid'); return handleSectionsVal('get', section_id, 'ssid');
} }
@ -419,7 +460,7 @@ return view.extend({
o.ucioption = 'bssid'; o.ucioption = 'bssid';
o.rmempty = true; o.rmempty = true;
o.readonly = true; o.readonly = true;
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'bssid'); return handleSectionsVal('get', section_id, 'bssid');
} }
@ -430,7 +471,7 @@ return view.extend({
o.ucioption = 'con_start'; o.ucioption = 'con_start';
o.rmempty = true; o.rmempty = true;
o.readonly = true; o.readonly = true;
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'con_start'); return handleSectionsVal('get', section_id, 'con_start');
} }
@ -441,10 +482,53 @@ return view.extend({
o.ucioption = 'con_end'; o.ucioption = 'con_end';
o.rmempty = true; o.rmempty = true;
o.readonly = true; o.readonly = true;
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'con_end'); return handleSectionsVal('get', section_id, 'con_end');
} }
o = s.taboption('travelmate', form.Flag, '_opensta', _('Auto Added Open Uplink'),
_('This option is selected by default if this uplink was added automatically and counts as \'Open Uplink\'.'));
o.rmempty = true;
o.modalonly = true;
o.uciconfig = 'travelmate';
o.ucisection = 'uplink';
o.ucioption = 'opensta';
o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'opensta');
}
o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'opensta', value);
}
o.remove = function (section_id, value) {
return handleSectionsVal('set', section_id, 'opensta', value);
}
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';
o.ucioption = 'macaddr';
o.nocreate = false;
o.unspecified = true;
o.rmempty = true;
o.datatype = 'macaddr';
o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'macaddr');
}
o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'macaddr', value);
}
o.remove = function (section_id, value) {
return handleSectionsVal('set', section_id, 'macaddr', value);
}
o = s.taboption('travelmate', form.Value, '_con_start_expiry', _('Connection Start Expiry'), o = s.taboption('travelmate', form.Value, '_con_start_expiry', _('Connection Start Expiry'),
_('Automatically disable the uplink after <em>n</em> minutes, e.g. for timed connections.<br /> \ _('Automatically disable the uplink after <em>n</em> minutes, e.g. for timed connections.<br /> \
The default of \'0\' disables this feature.')); The default of \'0\' disables this feature.'));
@ -456,10 +540,10 @@ return view.extend({
o.placeholder = '0'; o.placeholder = '0';
o.default = '0'; o.default = '0';
o.datatype = 'range(0,720)'; o.datatype = 'range(0,720)';
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'con_start_expiry'); return handleSectionsVal('get', section_id, 'con_start_expiry');
} }
o.write = function(section_id, value) { o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'con_start_expiry', value); return handleSectionsVal('set', section_id, 'con_start_expiry', value);
} }
@ -474,10 +558,10 @@ return view.extend({
o.placeholder = '0'; o.placeholder = '0';
o.default = '0'; o.default = '0';
o.datatype = 'range(0,720)'; o.datatype = 'range(0,720)';
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'con_end_expiry'); return handleSectionsVal('get', section_id, 'con_end_expiry');
} }
o.write = function(section_id, value) { o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'con_end_expiry', value); return handleSectionsVal('set', section_id, 'con_end_expiry', value);
} }
@ -490,7 +574,7 @@ return view.extend({
o.uciconfig = 'travelmate'; o.uciconfig = 'travelmate';
o.ucisection = 'uplink'; o.ucisection = 'uplink';
o.ucioption = 'script'; o.ucioption = 'script';
o.renderWidget = function(section_id, option_index, cfgvalue) { o.renderWidget = function (section_id, option_index, cfgvalue) {
var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, { var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, {
id: this.cbid(section_id), id: this.cbid(section_id),
name: this.cbid(section_id), name: this.cbid(section_id),
@ -500,23 +584,23 @@ return view.extend({
root_directory: this.root_directory, root_directory: this.root_directory,
disabled: (this.readonly != null) ? this.readonly : this.map.readonly disabled: (this.readonly != null) ? this.readonly : this.map.readonly
}); });
browserEl.renderListing = function(container, path, list) { browserEl.renderListing = function (container, path, list) {
return ui.FileUpload.prototype.renderListing.apply(this, [ return ui.FileUpload.prototype.renderListing.apply(this, [
container, path, container, path,
list.filter(function(entry) { list.filter(function (entry) {
return ((entry.type == 'directory') || (entry.type == 'file' && entry.name.match(/\.login$/))); return ((entry.type == 'directory') || (entry.type == 'file' && entry.name.match(/\.login$/)));
}) })
]); ]);
}; };
return browserEl.render(); return browserEl.render();
}; };
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'script'); return handleSectionsVal('get', section_id, 'script');
} }
o.write = function(section_id, value) { o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'script', value); return handleSectionsVal('set', section_id, 'script', value);
} }
o.remove = function(section_id) { o.remove = function (section_id) {
return handleSectionsVal('del', section_id, 'script'); return handleSectionsVal('del', section_id, 'script');
} }
@ -528,34 +612,84 @@ return view.extend({
o.ucioption = 'script_args'; o.ucioption = 'script_args';
o.rmempty = true; o.rmempty = true;
o.depends({ _script: '/etc/travelmate', '!contains': true }); o.depends({ _script: '/etc/travelmate', '!contains': true });
o.cfgvalue = function(section_id) { o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'script_args'); return handleSectionsVal('get', section_id, 'script_args');
} }
o.write = function(section_id, value) { o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'script_args', value); return handleSectionsVal('set', section_id, 'script_args', value);
} }
o.remove = function(section_id) { o.remove = function (section_id) {
return handleSectionsVal('del', section_id, 'script_args'); return handleSectionsVal('del', section_id, 'script_args');
} }
/*
modal vpn tab
*/
o = s.taboption('vpn', form.Flag, '_vpn', _('VPN Hook'), _('Automatically handle VPN connections.<br /> \
Please note: This feature requires the additional configuration of <em>Wireguard</em> or <em>OpenVPN</em>.'));
o.rmempty = true;
o.modalonly = true;
o.uciconfig = 'travelmate';
o.ucisection = 'uplink';
o.ucioption = 'vpn';
o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'vpn');
}
o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'vpn', value);
}
o.remove = function (section_id, value) {
return handleSectionsVal('set', section_id, 'vpn', value);
}
o = s.taboption('vpn', form.ListValue, '_vpnservice', _('VPN Service'));
o.value('wireguard');
o.value('openvpn');
o.optional = true;
o.modalonly = true;
o.uciconfig = 'travelmate';
o.ucisection = 'uplink';
o.ucioption = 'vpnservice';
o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'vpnservice');
}
o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'vpnservice', value);
}
o = s.taboption('vpn', widgets.NetworkSelect, '_vpniface', _('VPN Interface'), _('The logical vpn network interface, e.g. \'wg0\' or \'tun0\'.'));
o.unspecified = false;
o.nocreate = true;
o.optional = true;
o.modalonly = true;
o.uciconfig = 'travelmate';
o.ucisection = 'uplink';
o.ucioption = 'vpniface';
o.cfgvalue = function (section_id) {
return handleSectionsVal('get', section_id, 'vpniface');
}
o.write = function (section_id, value) {
return handleSectionsVal('set', section_id, 'vpniface', value);
}
/* /*
scan buttons scan buttons
*/ */
s = m.section(form.GridSection, 'wifi-device'); s = m.section(form.GridSection, 'wifi-device');
s.anonymous = true; s.anonymous = true;
s.addremove = false; s.addremove = false;
s.render = function() { s.render = function () {
return network.getWifiDevices().then(L.bind(function(radios) { return network.getWifiDevices().then(L.bind(function (radios) {
var radio, ifname, btns = []; var radio, ifname, btns = [];
for (var i = 0; i < radios.length; i++) { for (var i = 0; i < radios.length; i++) {
radio = radios[i].sid; radio = radios[i].sid;
if (radio) { if (radio) {
btns.push(E('button', { btns.push(E('button', {
'class': 'cbi-button cbi-button-apply', 'class': 'cbi-button cbi-button-positive',
'id': radio, 'id': radio,
'click': ui.createHandlerFn(this, 'handleScan', radio) 'click': ui.createHandlerFn(this, 'handleScan', radio)
}, [ _('Scan on ' + radio + '...') ]), }, [_('Scan on ' + radio + '...')]),
'\xa0') '\xa0')
} }
} }
return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns)); return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns));
@ -565,7 +699,7 @@ return view.extend({
/* /*
modal 'scan' dialog modal 'scan' dialog
*/ */
s.handleScan = function(radio) { s.handleScan = function (radio) {
var table = E('table', { 'class': 'table' }, [ var table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [ E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th col-1 middle left' }, _('Strength')), E('th', { 'class': 'th col-1 middle left' }, _('Strength')),
@ -596,117 +730,116 @@ return view.extend({
md.style.maxWidth = '90%'; md.style.maxWidth = '90%';
md.style.maxHeight = 'none'; md.style.maxHeight = 'none';
return L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', [ 'scan', radio ]), null) return L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['scan', radio]), null)
.then(L.bind(function(res) { .then(L.bind(function (res) {
if (res) {
var lines, strength, channel, encryption, tbl_encryption, bssid, ssid, tbl_ssid, rows = []; var lines, strength, channel, encryption, tbl_encryption, bssid, ssid, tbl_ssid, rows = [];
lines = res.trim().split('\n'); if (res) {
for (var i = 0; i < lines.length; i++) { lines = res.trim().split('\n');
if (lines[i].match(/^\s+[0-9]/)) { for (var i = 0; i < lines.length; i++) {
encryption = lines[i].slice(80).trim(); if (lines[i].match(/^\s+[0-9]/)) {
if (!encryption.includes('WEP')) { encryption = lines[i].slice(80).trim();
strength = lines[i].slice(4,7).trim(); if (!encryption.includes('WEP')) {
channel = lines[i].slice(15,18).trim(); strength = lines[i].slice(4, 7).trim();
bssid = lines[i].slice(60,77).trim(); channel = lines[i].slice(15, 18).trim();
ssid = lines[i].slice(25,59).trim(); bssid = lines[i].slice(60, 77).trim();
if (ssid.startsWith('"')) { ssid = lines[i].slice(25, 59).trim();
ssid = ssid.slice(1, ssid.length-1); if (ssid.startsWith('"')) {
tbl_ssid = ssid; ssid = ssid.slice(1, ssid.length - 1);
} tbl_ssid = ssid;
else { }
ssid = "hidden"; else {
tbl_ssid = "<em>hidden</em>"; ssid = "hidden";
} tbl_ssid = "<em>hidden</em>";
switch (encryption) { }
case 'WPA3 PSK (SAE)': switch (encryption) {
encryption = 'sae'; case 'WPA3 PSK (SAE)':
tbl_encryption = 'WPA3 Pers. (SAE)'; encryption = 'sae';
break; tbl_encryption = 'WPA3 Pers. (SAE)';
case 'mixed WPA2/WPA3 PSK/SAE (CCMP)': break;
encryption = 'sae-mixed'; case 'mixed WPA2/WPA3 PSK/SAE (CCMP)':
tbl_encryption = 'WPA2/WPA3 Pers. (CCMP)'; encryption = 'sae-mixed';
break; tbl_encryption = 'WPA2/WPA3 Pers. (CCMP)';
case 'WPA2 PSK (CCMP)': break;
encryption = 'psk2+ccmp'; case 'WPA2 PSK (CCMP)':
tbl_encryption = 'WPA2 Pers. (CCMP)'; encryption = 'psk2+ccmp';
break; tbl_encryption = 'WPA2 Pers. (CCMP)';
case 'WPA2 PSK (TKIP)': break;
encryption = 'psk2+tkip'; case 'WPA2 PSK (TKIP)':
tbl_encryption = 'WPA2 Pers. (TKIP)'; encryption = 'psk2+tkip';
break; tbl_encryption = 'WPA2 Pers. (TKIP)';
case 'mixed WPA/WPA2 PSK (TKIP, CCMP)': break;
encryption = 'psk-mixed+ccmp'; case 'mixed WPA/WPA2 PSK (TKIP, CCMP)':
tbl_encryption = 'WPA/WPA2 Pers. (CCMP)'; encryption = 'psk-mixed+ccmp';
break; tbl_encryption = 'WPA/WPA2 Pers. (CCMP)';
case 'WPA3 802.1X (CCMP)': break;
encryption = 'wpa3'; case 'WPA3 802.1X (CCMP)':
tbl_encryption = 'WPA3 Ent. (CCMP)'; encryption = 'wpa3';
break; tbl_encryption = 'WPA3 Ent. (CCMP)';
case 'mixed WPA2/WPA3 802.1X (CCMP)': break;
encryption = 'wpa3-mixed'; case 'mixed WPA2/WPA3 802.1X (CCMP)':
tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)'; encryption = 'wpa3-mixed';
break; tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)';
case 'WPA PSK (CCMP)': break;
encryption = 'psk2+ccmp'; case 'WPA PSK (CCMP)':
tbl_encryption = 'WPA Pers. (CCMP)'; encryption = 'psk2+ccmp';
break; tbl_encryption = 'WPA Pers. (CCMP)';
case 'WPA PSK (TKIP)': break;
encryption = 'psk2+tkip'; case 'WPA PSK (TKIP)':
tbl_encryption = 'WPA Pers. (TKIP)'; encryption = 'psk2+tkip';
break; tbl_encryption = 'WPA Pers. (TKIP)';
case 'WPA2 802.1X (CCMP)': break;
encryption = 'wpa2+ccmp'; case 'WPA2 802.1X (CCMP)':
tbl_encryption = 'WPA2 Ent. (CCMP)'; encryption = 'wpa2+ccmp';
break; tbl_encryption = 'WPA2 Ent. (CCMP)';
case 'WPA3 OWE (CCMP)': break;
encryption = 'owe'; case 'WPA3 OWE (CCMP)':
tbl_encryption = 'WPA3 OWE (CCMP)'; encryption = 'owe';
break; tbl_encryption = 'WPA3 OWE (CCMP)';
case 'none': break;
encryption = 'none'; case 'none':
tbl_encryption = 'none'; encryption = 'none';
break; tbl_encryption = 'none';
break;
}
rows.push([
strength,
channel,
tbl_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...')))
]);
} }
}
else if (lines[i] === '::: Empty resultset') {
rows.push([ rows.push([
strength, 'No scan results (empty resultset)'
channel,
tbl_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...')))
]); ]);
} }
} }
else if (lines[i] === '::: No scan results') {
rows.push([
'No scan results'
]);
}
} }
} else {
else { rows.push([
rows.push([ 'No scan results (timeout)'
'No scan results' ]);
]); }
} cbi_update_table(table, rows);
cbi_update_table(table, rows); }, this));
}, this));
}; };
/* /*
modal 'add' dialog modal 'add' dialog
*/ */
s.handleAdd = function(radio, iface, ssid, bssid, encryption, ev) { s.handleAdd = function (radio, iface, ssid, bssid, encryption, ev) {
ui.hideModal;
var m2, s2, o2; var m2, s2, o2;
m2 = new form.Map('wireless'), m2 = new form.Map('wireless'),
s2 = m2.section(form.NamedSection, '_add_trm'); s2 = m2.section(form.NamedSection, '_add_trm');
s2.render = function() { s2.render = function () {
return Promise.all([ return Promise.all([
{}, {},
this.renderUCISection('_add_trm') this.renderUCISection('_add_trm')
@ -819,7 +952,7 @@ return view.extend({
o2.password = true; o2.password = true;
o2.rmempty = true; o2.rmempty = true;
return m2.render().then(L.bind(function(elements) { return m2.render().then(L.bind(function (elements) {
ui.showModal(_('Add Uplink %q').replace(/%q/, '"%h"'.format(ssid)), [ ui.showModal(_('Add Uplink %q').replace(/%q/, '"%h"'.format(ssid)), [
elements, elements,
E('div', { 'class': 'right' }, [ E('div', { 'class': 'right' }, [
@ -830,7 +963,7 @@ return view.extend({
'\xa0', '\xa0',
E('button', { E('button', {
'class': 'cbi-button cbi-button-positive important', 'class': 'cbi-button cbi-button-positive important',
'click': ui.createHandlerFn(this, 'handleSave', m2) 'click': ui.createHandlerFn(this, 'handleCommit', m2)
}, _('Save')) }, _('Save'))
]) ])
]); ]);
@ -840,16 +973,16 @@ return view.extend({
/* /*
save new uplink save new uplink
*/ */
s.handleSave = function(map, ev) { s.handleCommit = function (map, ev) {
var w_sections = uci.sections('wireless', 'wifi-iface'), var w_sections = uci.sections('wireless', 'wifi-iface'),
device = L.toArray(map.lookupOption('device', '_add_trm'))[0].formvalue('_add_trm'), device = L.toArray(map.lookupOption('device', '_add_trm'))[0].formvalue('_add_trm'),
network = L.toArray(map.lookupOption('network', '_add_trm'))[0].formvalue('_add_trm'), network = L.toArray(map.lookupOption('network', '_add_trm'))[0].formvalue('_add_trm'),
ssid = L.toArray(map.lookupOption('ssid', '_add_trm'))[0].formvalue('_add_trm'), ssid = L.toArray(map.lookupOption('ssid', '_add_trm'))[0].formvalue('_add_trm'),
ignore_bssid = L.toArray(map.lookupOption('ignore_bssid', '_add_trm'))[0].formvalue('_add_trm'), ignore_bssid = L.toArray(map.lookupOption('ignore_bssid', '_add_trm'))[0].formvalue('_add_trm'),
bssid = L.toArray(map.lookupOption('bssid', '_add_trm'))[0].formvalue('_add_trm'), bssid = L.toArray(map.lookupOption('bssid', '_add_trm'))[0].formvalue('_add_trm'),
encryption = L.toArray(map.lookupOption('encryption', '_add_trm'))[0].formvalue('_add_trm'), encryption = L.toArray(map.lookupOption('encryption', '_add_trm'))[0].formvalue('_add_trm'),
password = L.toArray(map.lookupOption('key', '_add_trm'))[0].formvalue('_add_trm'); password = L.toArray(map.lookupOption('key', '_add_trm'))[0].formvalue('_add_trm');
if (!ssid || ((encryption.includes('psk') || encryption.includes('wpa') || encryption.includes('sae')) && !password )) { if (!ssid || ((encryption.includes('psk') || encryption.includes('wpa') || encryption.includes('sae')) && !password)) {
if (!ssid) { if (!ssid) {
ui.addNotification(null, E('p', 'Empty SSID, the uplink station could not be saved.'), 'error'); ui.addNotification(null, E('p', 'Empty SSID, the uplink station could not be saved.'), 'error');
} }
@ -867,8 +1000,8 @@ return view.extend({
} }
} }
var offset = w_sections.length, var offset = w_sections.length,
new_sid = 'trm_uplink' + (++offset); new_sid = 'trm_uplink' + (++offset);
while (uci.get('wireless', new_sid)) { while (uci.get('wireless', new_sid)) {
new_sid = 'trm_uplink' + (++offset); new_sid = 'trm_uplink' + (++offset);
} }
@ -884,8 +1017,14 @@ return view.extend({
uci.set('wireless', new_sid, 'key', password); uci.set('wireless', new_sid, 'key', password);
uci.set('wireless', new_sid, 'disabled', '1'); uci.set('wireless', new_sid, 'disabled', '1');
handleSectionsAdd(network); handleSectionsAdd(network);
uci.save(); uci.save()
ui.hideModal(); .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));
row.setAttribute('style', 'opacity: 0.5; color: #4a4 !important;');
})
.then(ui.hideModal)
}; };
return m.render(); return m.render();
}, },

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,8 +16,10 @@
"/tmp/trm_runtime.json": [ "read" ], "/tmp/trm_runtime.json": [ "read" ],
"/sbin/logread -e trm-": [ "exec" ], "/sbin/logread -e trm-": [ "exec" ],
"/usr/sbin/logread -e trm-": [ "exec" ], "/usr/sbin/logread -e trm-": [ "exec" ],
"/usr/sbin/ifup *": [ "exec" ],
"/etc/init.d/travelmate reload" : [ "exec" ], "/etc/init.d/travelmate reload" : [ "exec" ],
"/etc/init.d/travelmate restart" : [ "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 setup [0-9a-z_]* [0-9a-z_]* [0-9]*" : [ "exec" ],
"/etc/init.d/travelmate scan radio[0-9]" : [ "exec" ], "/etc/init.d/travelmate scan radio[0-9]" : [ "exec" ],
"/usr/bin/qrencode --inline --8bit --type=SVG --output=- *" : [ "exec" ] "/usr/bin/qrencode --inline --8bit --type=SVG --output=- *" : [ "exec" ]