luci-app-travelmate: release 2.0
- sync with travelmate 2.0 - app migrated to client side JS Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
parent
45c914a016
commit
e3b357ac0e
54 changed files with 21752 additions and 12476 deletions
|
@ -1,13 +1,14 @@
|
|||
# Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
|
||||
# Copyright 2017-2020 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-compat +travelmate +luci-lib-jsonc
|
||||
LUCI_DEPENDS:=+travelmate +luci-lib-jsonc
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
include ../../luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
'use strict';
|
||||
'require view';
|
||||
'require poll';
|
||||
'require fs';
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
L.resolveDefault(fs.stat('/sbin/logread'), null),
|
||||
L.resolveDefault(fs.stat('/usr/sbin/logread'), null)
|
||||
]);
|
||||
},
|
||||
render: function(stat) {
|
||||
var logger = stat[0] ? stat[0].path : stat[1] ? stat[1].path : null;
|
||||
poll.add(function() {
|
||||
return L.resolveDefault(fs.exec_direct(logger, ['-e', 'trm-'])).then(function(res) {
|
||||
var log = document.getElementById("logfile");
|
||||
if (res) {
|
||||
log.value = res.trim();
|
||||
}
|
||||
else {
|
||||
log.value = _('No travelmate related logs yet!');
|
||||
}
|
||||
log.scrollTop = log.scrollHeight;
|
||||
});
|
||||
});
|
||||
return E('div', { class: 'cbi-map' },
|
||||
E('div', { class: 'cbi-section' }, [
|
||||
E('div', { class: 'cbi-section-descr' }, _('The syslog output, pre-filtered for travelmate related messages only.')),
|
||||
E('textarea', {
|
||||
'id': 'logfile',
|
||||
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
|
||||
'readonly': 'readonly',
|
||||
'wrap': 'off',
|
||||
'rows': 25
|
||||
})
|
||||
]));
|
||||
},
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
|
@ -0,0 +1,430 @@
|
|||
'use strict';
|
||||
'require view';
|
||||
'require poll';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require uci';
|
||||
'require form';
|
||||
'require tools.widgets as widgets';
|
||||
|
||||
/*
|
||||
button handling
|
||||
*/
|
||||
async function handleAction(ev) {
|
||||
if (ev === 'restart') {
|
||||
fs.exec_direct('/etc/init.d/travelmate', [ev])
|
||||
}
|
||||
if (ev === 'setup') {
|
||||
var ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || '');
|
||||
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('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
|
||||
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' }, [
|
||||
]),
|
||||
'\xa0\xa0\xa0',
|
||||
_('The uplink interface name')
|
||||
]),
|
||||
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
|
||||
E('input', { 'class': 'cbi-input-text', 'id': 'zone', 'placeholder': 'wan', 'maxlength': '15', 'spellcheck': 'false' }),
|
||||
'\xa0\xa0\xa0',
|
||||
_('The firewall zone name')
|
||||
]),
|
||||
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
|
||||
E('input', { 'class': 'cbi-input-text', 'id': 'metric', 'placeholder': '100', 'maxlength': '3', 'spellcheck': 'false' }),
|
||||
'\xa0\xa0\xa0',
|
||||
_('The interface metric')
|
||||
])
|
||||
]),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'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',
|
||||
zone = document.getElementById('zone').value || 'wan',
|
||||
metric = document.getElementById('metric').value || '100';
|
||||
L.resolveDefault(fs.exec_direct('/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();
|
||||
})
|
||||
}, _('Save'))
|
||||
])
|
||||
]);
|
||||
return document.getElementById('iface').focus();
|
||||
}
|
||||
|
||||
if (ev === 'qrcode') {
|
||||
return Promise.all([
|
||||
uci.load('wireless')
|
||||
]).then(function() {
|
||||
var 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++) {
|
||||
if (w_sections[i].mode === 'ap' && w_sections[i].disabled !== '1') {
|
||||
w_sid = i;
|
||||
w_device = w_sections[i].device;
|
||||
w_ssid = w_sections[i].ssid;
|
||||
optionsAP.push(E('option', { value: w_sid }, w_device + ', ' + w_ssid));
|
||||
}
|
||||
}
|
||||
var selectAP = E('select', {
|
||||
id: 'selectID',
|
||||
class: 'cbi-input-select',
|
||||
change: function(ev) {
|
||||
result = document.getElementById('qrcode');
|
||||
if (document.getElementById("selectID").value) {
|
||||
w_sid = document.getElementById("selectID").value;
|
||||
w_ssid = w_sections[w_sid].ssid;
|
||||
w_enc = w_sections[w_sid].encryption;
|
||||
w_key = w_sections[w_sid].key;
|
||||
w_hidden = (w_sections[w_sid].hidden == 1 ? 'true' : 'false');
|
||||
if (w_enc.startsWith('psk')) {
|
||||
w_enc = 'WPA';
|
||||
}
|
||||
else if (w_enc === 'none') {
|
||||
w_enc = 'nopass';
|
||||
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) {
|
||||
if (res) {
|
||||
result.innerHTML = res.trim();
|
||||
}
|
||||
else {
|
||||
result.innerHTML = _('The QR-Code could not be generated!');
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.innerHTML = '';
|
||||
}
|
||||
}
|
||||
}, optionsAP);
|
||||
L.ui.showModal(_('QR-Code Overview'), [
|
||||
E('p', _('Render the QR-Code of the selected Access Point to comfortably transfer the WLAN credentials to your mobile devices.')),
|
||||
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
|
||||
E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em' }, [
|
||||
selectAP,
|
||||
])
|
||||
]),
|
||||
'\xa0',
|
||||
E('div', {
|
||||
'id': 'qrcode'
|
||||
}),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'click': L.hideModal
|
||||
}, _('Dismiss'))
|
||||
])
|
||||
]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('travelmate')
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(result) {
|
||||
var m, s, o;
|
||||
|
||||
m = new form.Map('travelmate', 'Travelmate', _('Configuration of the travelmate package to to enable travel router functionality. \
|
||||
For further information <a href="https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md" target="_blank" rel="noreferrer noopener" >check the online documentation</a>. <br /> \
|
||||
<em>Please note:</em> 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');
|
||||
if (res) {
|
||||
L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function(res) {
|
||||
if (res) {
|
||||
var info = JSON.parse(res);
|
||||
if (status && info) {
|
||||
status.textContent = (info.data.travelmate_status || '-') + ' / ' + (info.data.travelmate_version || '-');
|
||||
if (info.data.travelmate_status.startsWith('running')) {
|
||||
if (!status.classList.contains("spinning")) {
|
||||
status.classList.add("spinning");
|
||||
}
|
||||
} else {
|
||||
if (status.classList.contains("spinning")) {
|
||||
status.classList.remove("spinning");
|
||||
}
|
||||
}
|
||||
} else if (status) {
|
||||
status.textContent = '-';
|
||||
if (status.classList.contains("spinning")) {
|
||||
status.classList.remove("spinning");
|
||||
}
|
||||
}
|
||||
var station_id = document.getElementById('station_id');
|
||||
if (station_id && info) {
|
||||
station_id.textContent = info.data.station_id || '-';
|
||||
}
|
||||
var station_mac = document.getElementById('station_mac');
|
||||
if (station_mac && info) {
|
||||
station_mac.textContent = info.data.station_mac || '-';
|
||||
}
|
||||
var station_interface = document.getElementById('station_interface');
|
||||
if (station_interface && info) {
|
||||
station_interface.textContent = info.data.station_interface || '-';
|
||||
}
|
||||
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');
|
||||
if (run_flags && info) {
|
||||
run_flags.textContent = info.data.run_flags || '-';
|
||||
}
|
||||
var ext_hooks = document.getElementById('ext_hooks');
|
||||
if (ext_hooks && info) {
|
||||
ext_hooks.textContent = info.data.ext_hooks || '-';
|
||||
}
|
||||
var run = document.getElementById('run');
|
||||
if (run && info) {
|
||||
run.textContent = info.data.last_run || '-';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (status && status.classList.contains("spinning")) {
|
||||
status.textContent = '-';
|
||||
status.classList.remove("spinning");
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 1);
|
||||
|
||||
/*
|
||||
runtime information and buttons
|
||||
*/
|
||||
s = m.section(form.NamedSection, 'global');
|
||||
s.render = L.bind(function(view, section_id) {
|
||||
return E('div', { 'class': 'cbi-section' }, [
|
||||
E('h3', _('Information')),
|
||||
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [
|
||||
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', 'style': 'margin-bottom:5px' }, [
|
||||
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')),
|
||||
E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]),
|
||||
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [
|
||||
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', 'style': 'margin-bottom:5px' }, [
|
||||
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interface')),
|
||||
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('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')),
|
||||
E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'font-weight: bold;margin-bottom:5px;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-field', 'id': 'run_flags', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]),
|
||||
E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [
|
||||
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', 'style': 'margin-bottom:5px' }, [
|
||||
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')),
|
||||
E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]),
|
||||
E('div', { class: 'right' }, [
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-apply',
|
||||
'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');
|
||||
})
|
||||
})
|
||||
}, [ _('AP QR-Codes...') ]),
|
||||
'\xa0',
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-reset',
|
||||
'click': ui.createHandlerFn(this, function() {
|
||||
return handleAction('setup');
|
||||
})
|
||||
}, [ _('Interface Wizard...') ])
|
||||
])
|
||||
]);
|
||||
}, o, this);
|
||||
this.pollData;
|
||||
|
||||
/*
|
||||
tabbed config section
|
||||
*/
|
||||
s = m.section(form.NamedSection, 'global', 'travelmate', _('Settings'));
|
||||
s.addremove = false;
|
||||
s.tab('general', _('General 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> </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> </p>'));
|
||||
|
||||
/*
|
||||
general settings tab
|
||||
*/
|
||||
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 (e.g. \'radio1 radio0\').'));
|
||||
o.placeholder = 'radio0';
|
||||
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.default = 1;
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('general', form.Flag, 'trm_netcheck', _('Net Error Check'), _('Treat missing internet availability as an error.'));
|
||||
o.depends('trm_captive', '1');
|
||||
o.default = 0;
|
||||
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.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.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.'));
|
||||
o.default = 0;
|
||||
o.rmempty = false;
|
||||
|
||||
/*
|
||||
additional settings tab
|
||||
*/
|
||||
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)';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('additional', form.Value, 'trm_maxretry', _('Connection Limit'), _('Retry limit to connect to an uplink.'));
|
||||
o.placeholder = '3';
|
||||
o.datatype = 'range(1,10)';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('additional', form.Value, 'trm_minquality', _('Signal Quality Threshold'), _('Minimum signal quality threshold as percent for conditional uplink (dis-) connections.'));
|
||||
o.placeholder = '35';
|
||||
o.datatype = 'range(20,80)';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('additional', form.Value, 'trm_maxwait', _('Interface Timeout'), _('How long should travelmate wait for a successful wlan uplink connection.'));
|
||||
o.placeholder = '30';
|
||||
o.datatype = 'range(20,40)';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('additional', form.Value, 'trm_timeout', _('Overall Timeout'), _('Overall retry timeout in seconds.'));
|
||||
o.placeholder = '60';
|
||||
o.datatype = 'range(30,300)';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('additional', form.Value, 'trm_scanbuffer', _('Scan Buffer Size'), _('Buffer size in bytes to prepare nearby scan results.'));
|
||||
o.placeholder = '1024';
|
||||
o.datatype = 'range(256,4096)';
|
||||
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.value('http://captive.apple.com', 'Apple (default)');
|
||||
o.value('http://connectivity-check.ubuntu.com', 'Ubuntu');
|
||||
o.value('http://connectivitycheck.android.com/generate_204', 'Google');
|
||||
o.value('http://www.msftncsi.com/ncsi.txt', 'Microsoft');
|
||||
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:80.0) Gecko/20100101 Firefox/80.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 (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 (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 (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.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.optional = 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
|
||||
*/
|
||||
o = s.taboption('adv_email', form.Flag, 'trm_mail', _('E-Mail Hook'), _('Sends notification E-Mails after every succesful uplink connect.'));
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('adv_email', form.Value, 'trm_mailreceiver', _('E-Mail Receiver Address'), _('Receiver address for travelmate notification E-Mails.'));
|
||||
o.depends('trm_mail', '1');
|
||||
o.placeholder = 'name@example.com';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('adv_email', form.Value, 'trm_mailsender', _('E-Mail Sender Address'), _('Sender address for travelmate notification E-Mails.'));
|
||||
o.depends({ 'trm_mailreceiver': '@', '!contains': true });
|
||||
o.placeholder = 'no-reply@travelmate';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('adv_email', form.Value, 'trm_mailtopic', _('E-Mail Topic'), _('Topic for travelmate notification E-Mails.'));
|
||||
o.depends({ 'trm_mailreceiver': '@', '!contains': true });
|
||||
o.placeholder = 'travelmate connection to \'<station>\'';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('adv_email', form.Value, 'trm_mailprofile', _('E-Mail Profile'), _('Profile used by \'msmtp\' for travelmate notification E-Mails.'));
|
||||
o.depends({ 'trm_mailreceiver': '@', '!contains': true });
|
||||
o.placeholder = 'trm_notify';
|
||||
o.rmempty = true;
|
||||
|
||||
return m.render();
|
||||
},
|
||||
handleReset: null
|
||||
});
|
|
@ -0,0 +1,879 @@
|
|||
'use strict';
|
||||
'require view';
|
||||
'require poll';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require uci';
|
||||
'require form';
|
||||
'require network';
|
||||
'require tools.widgets as widgets';
|
||||
|
||||
/*
|
||||
remove wireless and stale travelmate sections
|
||||
*/
|
||||
function handleRemove(sid) {
|
||||
var w_sections, t_sections, match, changes;
|
||||
|
||||
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++) {
|
||||
match = false;
|
||||
for (var 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;
|
||||
}
|
||||
}
|
||||
if (match === false) {
|
||||
uci.remove('travelmate', t_sections[i]['.name']);
|
||||
}
|
||||
}
|
||||
uci.save();
|
||||
}
|
||||
|
||||
/*
|
||||
add missing travelmate sections
|
||||
*/
|
||||
function handleSectionsAdd(iface) {
|
||||
var w_sections, t_sections, match, changes;
|
||||
|
||||
w_sections = uci.sections('wireless', 'wifi-iface');
|
||||
t_sections = uci.sections('travelmate', 'uplink');
|
||||
for (var 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++) {
|
||||
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 sid = uci.add('travelmate', 'uplink');
|
||||
uci.set('travelmate', sid, 'enabled', '1');
|
||||
uci.set('travelmate', sid, 'device', w_sections[i].device);
|
||||
uci.set('travelmate', sid, 'ssid', w_sections[i].ssid);
|
||||
uci.set('travelmate', sid, 'bssid', w_sections[i].bssid);
|
||||
uci.set('travelmate', sid, 'con_start_expiry', '0');
|
||||
uci.set('travelmate', sid, 'con_end_expiry', '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
update travelmate sections
|
||||
*/
|
||||
function handleSectionsVal(action, section_id, option, value) {
|
||||
var 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++) {
|
||||
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];
|
||||
}
|
||||
else if (action === 'set') {
|
||||
if (option === 'enabled') {
|
||||
oldValue = t_sections[i][option];
|
||||
if (oldValue !== value && value === '0') {
|
||||
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);
|
||||
}
|
||||
else if (oldValue !== value && value === '1') {
|
||||
uci.unset('travelmate', t_sections[i]['.name'], 'con_end');
|
||||
}
|
||||
}
|
||||
return uci.set('travelmate', t_sections[i]['.name'], option, value);
|
||||
}
|
||||
else if (action === 'del') {
|
||||
return uci.unset('travelmate', t_sections[i]['.name'], option);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
update travelmate status
|
||||
*/
|
||||
function handleStatus() {
|
||||
poll.add(function() {
|
||||
L.resolveDefault(fs.stat('/var/run/travelmate.refresh'), null).then(function(res) {
|
||||
if (res) {
|
||||
L.resolveDefault(fs.read_direct('/var/run/travelmate.refresh'), null).then(function(res) {
|
||||
fs.remove('/var/run/travelmate.refresh');
|
||||
if (res && res === 'ui_reload') {
|
||||
location.reload();
|
||||
}
|
||||
else if (res && res === 'cfg_reload') {
|
||||
if (document.readyState === 'complete') {
|
||||
uci.unload('wireless');
|
||||
uci.unload('travelmate');
|
||||
}
|
||||
return Promise.all([
|
||||
uci.load('wireless'),
|
||||
uci.load('travelmate')
|
||||
]).then(function() {
|
||||
var item, value,
|
||||
container = document.querySelectorAll('.cbi-section-table-row[data-sid]');
|
||||
for (var i = 0; i < container.length; i++) {
|
||||
item = container[i].querySelector('.cbi-value-field[data-title="Enabled"]');
|
||||
value = handleSectionsVal('get', container[i].getAttribute('data-sid'), 'enabled');
|
||||
item.textContent = (value == 0 ? 'No' : 'Yes');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function(res) {
|
||||
if (res) {
|
||||
L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function(res) {
|
||||
if (res) {
|
||||
var info = JSON.parse(res);
|
||||
if (info) {
|
||||
var t_device, t_ssid, t_bssid, oldUplinkView, newUplinkView,
|
||||
uplinkId = info.data.station_id.trim().split('/'),
|
||||
oldUplinkView = document.getElementsByName('uplinkStation'),
|
||||
w_sections = uci.sections('wireless', 'wifi-iface');
|
||||
|
||||
t_device = uplinkId[0];
|
||||
t_bssid = uplinkId[uplinkId.length-1];
|
||||
for (var i = 1; i < uplinkId.length-1; i++) {
|
||||
if (!t_ssid) {
|
||||
t_ssid = uplinkId[i];
|
||||
}
|
||||
else {
|
||||
t_ssid = t_ssid + '/' + uplinkId[i];
|
||||
}
|
||||
}
|
||||
if (t_ssid === '-') {
|
||||
if (oldUplinkView.length > 0) {
|
||||
oldUplinkView[0].removeAttribute('style');
|
||||
oldUplinkView[0].removeAttribute('name', 'uplinkStation');
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var 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) {
|
||||
newUplinkView.setAttribute('name', 'uplinkStation');
|
||||
newUplinkView.setAttribute('style', 'text-align: left !important; color: #37c !important;font-weight: bold !important;');
|
||||
}
|
||||
else if (oldUplinkView.length > 0 && newUplinkView && oldUplinkView[0].getAttribute('id') !== newUplinkView.getAttribute('id')) {
|
||||
oldUplinkView[0].removeAttribute('style');
|
||||
oldUplinkView[0].removeAttribute('name', 'uplinkStation');
|
||||
newUplinkView.setAttribute('name', 'uplinkStation');
|
||||
newUplinkView.setAttribute('style', 'text-align: left !important; color: #37c !important;font-weight: bold !important;');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('wireless'),
|
||||
uci.load('travelmate')
|
||||
]);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var m, s, o,
|
||||
iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan';
|
||||
|
||||
m = new form.Map('wireless');
|
||||
m.chain('travelmate');
|
||||
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 \& drop and scan for new ones. The currently used uplink is emphasized in blue.'));
|
||||
s.anonymous = true;
|
||||
s.sortable = true;
|
||||
s.filter = function(section_id) {
|
||||
return (uci.get('wireless', section_id, 'network') == iface && uci.get('wireless', section_id, 'mode') == 'sta');
|
||||
};
|
||||
s.tab('wireless', _('Wireless Settings'));
|
||||
s.tab('travelmate', _('Travelmate Settings'));
|
||||
s.renderRowActions = function(section_id) {
|
||||
var btns;
|
||||
btns = [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button drag-handle center',
|
||||
'title': _('Drag to reorder'),
|
||||
'style': 'cursor:move',
|
||||
'disabled': this.map.readonly || null
|
||||
}, '☰'),
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-action important',
|
||||
'title': _('Edit this network'),
|
||||
'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id)
|
||||
}, _('Edit')),
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-negative remove',
|
||||
'title': _('Delete this network'),
|
||||
'click': ui.createHandlerFn(this, handleRemove, section_id)
|
||||
}, _('Del'))
|
||||
];
|
||||
return E('div', { 'class': 'td middle cbi-section-actions' }, E('div', btns));
|
||||
};
|
||||
|
||||
o = s.taboption('travelmate', form.Flag, '_enabled', _('Enabled'));
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'enabled';
|
||||
o.rmempty = false;
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'enabled');
|
||||
}
|
||||
o.write = function(section_id, value) {
|
||||
return handleSectionsVal('set', section_id, 'enabled', value);
|
||||
}
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'device', _('Device'));
|
||||
o.readonly = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'ssid', _('SSID'));
|
||||
o.datatype = 'maxlength(32)';
|
||||
o.readonly = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'bssid', _('BSSID'));
|
||||
o.datatype = 'macaddr';
|
||||
o.readonly = true;
|
||||
|
||||
o = s.taboption('wireless', form.ListValue, 'encryption', _('Encryption'));
|
||||
o.value('sae', _('WPA3 Pers.'));
|
||||
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.'));
|
||||
o.value('wpa3-mixed', _('WPA3/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.default = 'none';
|
||||
o.textvalue = function(section_id) {
|
||||
var cfgvalue = this.map.data.get('wireless', section_id, 'encryption');
|
||||
switch (cfgvalue) {
|
||||
case 'sae':
|
||||
cfgvalue = 'WPA3 Pers. (SAE)';
|
||||
break;
|
||||
case 'sae-mixed':
|
||||
cfgvalue = 'WPA2/WPA3 Pers. (CCMP)';
|
||||
break;
|
||||
case 'psk2':
|
||||
cfgvalue = 'WPA2 Pers.';
|
||||
break;
|
||||
case 'psk2+ccmp':
|
||||
cfgvalue = 'WPA2 Pers. (CCMP)';
|
||||
break;
|
||||
case 'psk2+tkip':
|
||||
cfgvalue = 'WPA2 Ent. (TKIP)';
|
||||
break;
|
||||
case 'psk':
|
||||
cfgvalue = 'WPA Pers.';
|
||||
break;
|
||||
case 'psk-mixed+ccmp':
|
||||
cfgvalue = 'WPA/WPA2 Pers. (CCMP)';
|
||||
break;
|
||||
case 'psk-mixed+tkip':
|
||||
cfgvalue = 'WPA/WPA2 Pers. (TKIP)';
|
||||
break;
|
||||
case 'wpa3':
|
||||
cfgvalue = 'WPA3 Ent.';
|
||||
break;
|
||||
case 'wpa3-mixed':
|
||||
cfgvalue = 'WPA3/WPA2 Ent.';
|
||||
break;
|
||||
case 'wpa2+ccmp':
|
||||
cfgvalue = 'WPA2 Ent. (CCMP)';
|
||||
break;
|
||||
case 'wpa2+tkip':
|
||||
cfgvalue = 'WPA2 Ent. (TKIP)';
|
||||
break;
|
||||
case 'wpa+ccmp':
|
||||
cfgvalue = 'WPA Ent. (CCMP)';
|
||||
break;
|
||||
case 'wpa+tkip':
|
||||
cfgvalue = 'WPA Ent. (TKIP)';
|
||||
break;
|
||||
case 'wpa-mixed+ccmp':
|
||||
cfgvalue = 'WPA/WPA2 Ent. (CCMP)';
|
||||
break;
|
||||
case 'wpa-mixed+tkip':
|
||||
cfgvalue = 'WPA/WPA2 Ent. (TKIP)';
|
||||
break;
|
||||
case 'owe':
|
||||
cfgvalue = 'WPA3 OWE (CCMP)';
|
||||
break;
|
||||
case 'none':
|
||||
cfgvalue = 'none';
|
||||
break;
|
||||
}
|
||||
return cfgvalue;
|
||||
};
|
||||
handleStatus();
|
||||
|
||||
/*
|
||||
modal wireless tab
|
||||
*/
|
||||
o = s.taboption('wireless', form.Value, 'key', _('Password'));
|
||||
o.datatype = 'wpakey';
|
||||
o.depends({ encryption: 'sae', '!contains': true });
|
||||
o.depends({ encryption: 'psk', '!contains': true });
|
||||
o.depends({ encryption: 'wpa', '!contains': true });
|
||||
o.modalonly = true;
|
||||
o.password = true;
|
||||
|
||||
o = s.taboption('wireless', form.ListValue, 'eap_type', _('EAP-Method'));
|
||||
o.value('tls', _('TLS'));
|
||||
o.value('ttls', _('TTLS'));
|
||||
o.value('peap', _('PEAP'));
|
||||
o.value('fast', _('FAST'));
|
||||
o.default = 'peap';
|
||||
o.depends({ encryption: 'wpa', '!contains': true });
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('wireless', form.ListValue, 'auth', _('Authentication'));
|
||||
o.value('PAP', _('PAP'));
|
||||
o.value('CHAP', _('CHAP'));
|
||||
o.value('MSCHAP', _('MSCHAP'));
|
||||
o.value('MSCHAPV2', _('MSCHAPV2'));
|
||||
o.value('EAP-GTC', _('EAP-GTC'));
|
||||
o.value('EAP-MD5', _('EAP-MD5'));
|
||||
o.value('EAP-MSCHAPV2', _('EAP-MSCHAPV2'));
|
||||
o.value('EAP-TLS', _('EAP-TLS'));
|
||||
o.value('auth=PAP', _('auth=PAP'));
|
||||
o.value('auth=MSCHAPV2', _('auth=MSCHAPV2'));
|
||||
o.default = 'EAP-MSCHAPV2';
|
||||
o.depends({ encryption: 'wpa', '!contains': true });
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'identify', _('Identify'));
|
||||
o.depends({ encryption: 'wpa', '!contains': true });
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'ca_cert', _('Path to CA-Certificate'));
|
||||
o.depends({ eap_type: 'tls' });
|
||||
o.modalonly = true;
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'client_cert', _('Path to Client-Certificate'));
|
||||
o.depends({ eap_type: 'tls' });
|
||||
o.modalonly = true;
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'priv_key', _('Path to Private Key'));
|
||||
o.depends({ eap_type: 'tls' });
|
||||
o.modalonly = true;
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.taboption('wireless', form.Value, 'priv_key_pwd', _('Password of Private Key'));
|
||||
o.datatype = 'wpakey';
|
||||
o.depends({ eap_type: 'tls' });
|
||||
o.modalonly = true;
|
||||
o.password = true;
|
||||
o.rmempty = true;
|
||||
|
||||
/*
|
||||
modal travelmate tab
|
||||
*/
|
||||
o = s.taboption('travelmate', form.Value, '_ssid', _('SSID'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'ssid';
|
||||
o.rmempty = false;
|
||||
o.readonly = true;
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'ssid');
|
||||
}
|
||||
|
||||
o = s.taboption('travelmate', form.Value, '_bssid', _('BSSID'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'bssid';
|
||||
o.rmempty = true;
|
||||
o.readonly = true;
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'bssid');
|
||||
}
|
||||
|
||||
o = s.taboption('travelmate', form.Value, '_con_start', _('Connection Start'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'con_start';
|
||||
o.rmempty = true;
|
||||
o.readonly = true;
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'con_start');
|
||||
}
|
||||
|
||||
o = s.taboption('travelmate', form.Value, '_con_end', _('Connection End'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'con_end';
|
||||
o.rmempty = true;
|
||||
o.readonly = true;
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'con_end');
|
||||
}
|
||||
|
||||
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 /> \
|
||||
The default of \'0\' disables this feature.'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'con_start_expiry';
|
||||
o.rmempty = false;
|
||||
o.placeholder = '0';
|
||||
o.default = '0';
|
||||
o.datatype = 'range(0,720)';
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'con_start_expiry');
|
||||
}
|
||||
o.write = function(section_id, value) {
|
||||
return handleSectionsVal('set', section_id, 'con_start_expiry', value);
|
||||
}
|
||||
|
||||
o = s.taboption('travelmate', form.Value, '_con_end_expiry', _('Connection End Expiry'),
|
||||
_('Automatically (re-)enable the uplink after <em>n</em> minutes, e.g. after failed login attempts.<br /> \
|
||||
The default of \'0\' disables this feature.'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'con_end_expiry';
|
||||
o.rmempty = false;
|
||||
o.placeholder = '0';
|
||||
o.default = '0';
|
||||
o.datatype = 'range(0,720)';
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'con_end_expiry');
|
||||
}
|
||||
o.write = function(section_id, value) {
|
||||
return handleSectionsVal('set', section_id, 'con_end_expiry', value);
|
||||
}
|
||||
|
||||
o = s.taboption('travelmate', form.FileUpload, '_script', _('Auto Login Script'),
|
||||
_('External script reference which will be called for automated captive portal logins.'));
|
||||
o.root_directory = '/etc/travelmate';
|
||||
o.enable_remove = false;
|
||||
o.enable_upload = false;
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'script';
|
||||
o.renderWidget = function(section_id, option_index, cfgvalue) {
|
||||
var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, {
|
||||
id: this.cbid(section_id),
|
||||
name: this.cbid(section_id),
|
||||
show_hidden: this.show_hidden,
|
||||
enable_upload: this.enable_upload,
|
||||
enable_remove: this.enable_remove,
|
||||
root_directory: this.root_directory,
|
||||
disabled: (this.readonly != null) ? this.readonly : this.map.readonly
|
||||
});
|
||||
browserEl.renderListing = function(container, path, list) {
|
||||
return ui.FileUpload.prototype.renderListing.apply(this, [
|
||||
container, path,
|
||||
list.filter(function(entry) {
|
||||
return ((entry.type == 'directory') || (entry.type == 'file' && entry.name.match(/\.login$/)));
|
||||
})
|
||||
]);
|
||||
};
|
||||
return browserEl.render();
|
||||
};
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'script');
|
||||
}
|
||||
o.write = function(section_id, value) {
|
||||
return handleSectionsVal('set', section_id, 'script', value);
|
||||
}
|
||||
o.remove = function(section_id) {
|
||||
return handleSectionsVal('del', section_id, 'script');
|
||||
}
|
||||
|
||||
o = s.taboption('travelmate', form.Value, '_args', _('Script Arguments'),
|
||||
_('Space separated list of additional arguments passed to the Auto Login Script, i.e. username and password'));
|
||||
o.modalonly = true;
|
||||
o.uciconfig = 'travelmate';
|
||||
o.ucisection = 'uplink';
|
||||
o.ucioption = 'script_args';
|
||||
o.rmempty = true;
|
||||
o.depends({ _script: '/etc/travelmate', '!contains': true });
|
||||
o.cfgvalue = function(section_id) {
|
||||
return handleSectionsVal('get', section_id, 'script_args');
|
||||
}
|
||||
o.write = function(section_id, value) {
|
||||
return handleSectionsVal('set', section_id, 'script_args', value);
|
||||
}
|
||||
o.remove = function(section_id) {
|
||||
return handleSectionsVal('del', section_id, 'script_args');
|
||||
}
|
||||
|
||||
/*
|
||||
scan buttons
|
||||
*/
|
||||
s = m.section(form.GridSection, 'wifi-device');
|
||||
s.anonymous = true;
|
||||
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++) {
|
||||
radio = radios[i].sid;
|
||||
if (radio) {
|
||||
btns.push(E('button', {
|
||||
'class': 'cbi-button cbi-button-apply',
|
||||
'id': radio,
|
||||
'click': ui.createHandlerFn(this, 'handleScan', radio)
|
||||
}, [ _('Scan on ' + radio + '...') ]),
|
||||
'\xa0')
|
||||
}
|
||||
}
|
||||
return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns));
|
||||
}, this))
|
||||
};
|
||||
|
||||
/*
|
||||
modal 'scan' dialog
|
||||
*/
|
||||
s.handleScan = function(radio) {
|
||||
var table = E('div', { 'class': 'table' }, [
|
||||
E('div', { 'class': 'tr table-titles' }, [
|
||||
E('div', { 'class': 'th col-1 middle left' }, _('Strength')),
|
||||
E('div', { 'class': 'th col-1 middle left hide-xs' }, _('Channel')),
|
||||
E('div', { 'class': 'th col-2 middle left' }, _('SSID')),
|
||||
E('div', { 'class': 'th col-2 middle left' }, _('BSSID')),
|
||||
E('div', { 'class': 'th col-3 middle left' }, _('Encryption')),
|
||||
E('div', { 'class': 'th cbi-section-actions right' }, '\xa0')
|
||||
])
|
||||
]);
|
||||
cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan on \'' + radio + '\'...')));
|
||||
|
||||
var md = ui.showModal(_('Wireless Scan'), [
|
||||
table,
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'click': ui.hideModal
|
||||
}, _('Dismiss')),
|
||||
'\xa0',
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-positive important',
|
||||
'click': L.bind(this.handleScan, this, radio)
|
||||
}, _('Repeat Scan'))
|
||||
])
|
||||
]);
|
||||
|
||||
md.style.maxWidth = '90%';
|
||||
md.style.maxHeight = 'none';
|
||||
|
||||
return L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', [ 'scan', radio ]), null)
|
||||
.then(L.bind(function(res) {
|
||||
if (res) {
|
||||
var lines, strength, channel, encryption, tbl_encryption, bssid, ssid, tbl_ssid, rows = [];
|
||||
lines = res.trim().split('\n');
|
||||
for (var 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 = "<em>hidden</em>";
|
||||
}
|
||||
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 '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', {
|
||||
'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 {
|
||||
rows.push([
|
||||
'No scan results'
|
||||
]);
|
||||
}
|
||||
cbi_update_table(table, rows);
|
||||
}, this));
|
||||
};
|
||||
|
||||
/*
|
||||
modal 'add' dialog
|
||||
*/
|
||||
s.handleAdd = function(radio, iface, ssid, bssid, encryption, ev) {
|
||||
ui.hideModal;
|
||||
var m2, s2, o2;
|
||||
|
||||
m2 = new form.Map('wireless'),
|
||||
s2 = m2.section(form.NamedSection, '_add_trm');
|
||||
|
||||
s2.render = function() {
|
||||
return Promise.all([
|
||||
{},
|
||||
this.renderUCISection('_add_trm')
|
||||
]).then(this.renderContents.bind(this));
|
||||
};
|
||||
|
||||
o2 = s2.option(form.Value, 'device', _('Device Name'));
|
||||
o2.default = radio;
|
||||
o2.readonly = true;
|
||||
|
||||
o2 = s2.option(form.Value, 'network', _('Interface Name'));
|
||||
o2.default = iface;
|
||||
o2.readonly = true;
|
||||
|
||||
if (ssid === "hidden") {
|
||||
o2 = s2.option(form.Value, 'ssid', _('SSID (hidden)'));
|
||||
o2.placeholder = 'hidden SSID';
|
||||
}
|
||||
else {
|
||||
o2 = s2.option(form.Value, 'ssid', _('SSID'));
|
||||
o2.default = ssid;
|
||||
}
|
||||
o2.datatype = 'maxlength(32)';
|
||||
o2.rmempty = false;
|
||||
|
||||
o2 = s2.option(form.Flag, 'ignore_bssid', _('Ignore BSSID'));
|
||||
if (ssid === "hidden") {
|
||||
o2.default = '0';
|
||||
}
|
||||
else {
|
||||
o2.default = '1';
|
||||
}
|
||||
|
||||
o2 = s2.option(form.Value, 'bssid', _('BSSID'));
|
||||
o2.depends({ ignore_bssid: '0' });
|
||||
o2.datatype = 'macaddr';
|
||||
o2.rmempty = true;
|
||||
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+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.default = encryption;
|
||||
|
||||
o2 = s2.option(form.Value, 'key', _('Password'));
|
||||
o2.depends({ encryption: 'sae', '!contains': true });
|
||||
o2.depends({ encryption: 'psk', '!contains': true });
|
||||
o2.depends({ encryption: 'wpa', '!contains': true });
|
||||
o2.datatype = 'wpakey';
|
||||
o2.password = true;
|
||||
|
||||
o2 = s2.option(form.ListValue, 'eap_type', _('EAP-Method'));
|
||||
o2.depends({ encryption: 'wpa', '!contains': true });
|
||||
o2.value('tls', _('TLS'));
|
||||
o2.value('ttls', _('TTLS'));
|
||||
o2.value('peap', _('PEAP'));
|
||||
o2.value('fast', _('FAST'));
|
||||
o2.default = 'peap';
|
||||
|
||||
o2 = s2.option(form.ListValue, 'auth', _('Authentication'));
|
||||
o2.depends({ encryption: 'wpa', '!contains': true });
|
||||
o2.value('PAP', _('PAP'));
|
||||
o2.value('CHAP', _('CHAP'));
|
||||
o2.value('MSCHAP', _('MSCHAP'));
|
||||
o2.value('MSCHAPV2', _('MSCHAPV2'));
|
||||
o2.value('EAP-GTC', _('EAP-GTC'));
|
||||
o2.value('EAP-MD5', _('EAP-MD5'));
|
||||
o2.value('EAP-MSCHAPV2', _('EAP-MSCHAPV2'));
|
||||
o2.value('EAP-TLS', _('EAP-TLS'));
|
||||
o2.value('auth=PAP', _('auth=PAP'));
|
||||
o2.value('auth=MSCHAPV2', _('auth=MSCHAPV2'));
|
||||
o2.default = 'EAP-MSCHAPV2';
|
||||
|
||||
o2 = s2.option(form.Value, 'identify', _('Identify'));
|
||||
o2.depends({ encryption: 'wpa', '!contains': true });
|
||||
|
||||
o2 = s2.option(form.Value, 'ca_cert', _('Path to CA-Certificate'));
|
||||
o2.depends({ eap_type: 'tls' });
|
||||
o2.rmempty = true;
|
||||
|
||||
o2 = s2.option(form.Value, 'client_cert', _('Path to Client-Certificate'));
|
||||
o2.depends({ eap_type: 'tls' });
|
||||
o2.rmempty = true;
|
||||
|
||||
o2 = s2.option(form.Value, 'priv_key', _('Path to Private Key'));
|
||||
o2.depends({ eap_type: 'tls' });
|
||||
o2.rmempty = true;
|
||||
|
||||
o2 = s2.option(form.Value, 'priv_key_pwd', _('Password of Private Key'));
|
||||
o2.depends({ eap_type: 'tls' });
|
||||
o2.datatype = 'wpakey';
|
||||
o2.password = true;
|
||||
o2.rmempty = true;
|
||||
|
||||
return m2.render().then(L.bind(function(elements) {
|
||||
ui.showModal(_('Add Uplink %q').replace(/%q/, '"%h"'.format(ssid)), [
|
||||
elements,
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'click': ui.hideModal
|
||||
}, _('Dismiss')),
|
||||
'\xa0',
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-positive important',
|
||||
'click': ui.createHandlerFn(this, 'handleSave', m2)
|
||||
}, _('Save'))
|
||||
])
|
||||
]);
|
||||
}, this));
|
||||
};
|
||||
|
||||
/*
|
||||
save new uplink
|
||||
*/
|
||||
s.handleSave = function(map, ev) {
|
||||
var w_sections = uci.sections('wireless', 'wifi-iface'),
|
||||
device = L.toArray(map.lookupOption('device', '_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'),
|
||||
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'),
|
||||
encryption = L.toArray(map.lookupOption('encryption', '_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)) {
|
||||
return;
|
||||
}
|
||||
for (var 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.hideModal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var offset = w_sections.length,
|
||||
new_sid = 'trm_uplink' + (++offset);
|
||||
while (uci.get('wireless', new_sid)) {
|
||||
new_sid = 'trm_uplink' + (++offset);
|
||||
}
|
||||
uci.add('wireless', 'wifi-iface', new_sid);
|
||||
uci.set('wireless', new_sid, 'device', device);
|
||||
uci.set('wireless', new_sid, 'mode', 'sta');
|
||||
uci.set('wireless', new_sid, 'network', network);
|
||||
uci.set('wireless', new_sid, 'ssid', ssid);
|
||||
if (ignore_bssid === '0') {
|
||||
uci.set('wireless', new_sid, 'bssid', bssid);
|
||||
}
|
||||
uci.set('wireless', new_sid, 'encryption', encryption);
|
||||
uci.set('wireless', new_sid, 'key', password);
|
||||
uci.set('wireless', new_sid, 'disabled', '1');
|
||||
handleSectionsAdd(network);
|
||||
uci.save();
|
||||
ui.hideModal();
|
||||
};
|
||||
return m.render();
|
||||
},
|
||||
handleReset: null
|
||||
});
|
|
@ -1,69 +0,0 @@
|
|||
-- Copyright 2017-2019 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
module("luci.controller.travelmate", package.seeall)
|
||||
|
||||
local sys = require("luci.sys")
|
||||
local util = require("luci.util")
|
||||
local http = require("luci.http")
|
||||
local i18n = require("luci.i18n")
|
||||
local json = require("luci.jsonc")
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/travelmate") then
|
||||
return
|
||||
end
|
||||
|
||||
local e = entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40)
|
||||
e.dependent = false
|
||||
e.acl_depends = { "luci-app-travelmate" }
|
||||
|
||||
entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
|
||||
entry({"admin", "services", "travelmate", "stations"}, template("travelmate/stations"), _("Wireless Stations"), 20).leaf = true
|
||||
entry({"admin", "services", "travelmate", "log"}, template("travelmate/logread"), _("View Logfile"), 30).leaf = true
|
||||
entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100)
|
||||
entry({"admin", "services", "travelmate", "advanced", "configuration"}, form("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true
|
||||
entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, form("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true
|
||||
entry({"admin", "services", "travelmate", "advanced", "cfg_network"}, form("travelmate/cfg_network_tab"), _("Edit Network Configuration"), 130).leaf = true
|
||||
entry({"admin", "services", "travelmate", "advanced", "cfg_firewall"}, form("travelmate/cfg_firewall_tab"), _("Edit Firewall Configuration"), 140).leaf = true
|
||||
|
||||
entry({"admin", "services", "travelmate", "logread"}, call("logread"), nil).leaf = true
|
||||
entry({"admin", "services", "travelmate", "status"}, call("status_update"), nil).leaf = true
|
||||
entry({"admin", "services", "travelmate", "action"}, call("trm_action"), nil).leaf = true
|
||||
entry({"admin", "services", "travelmate", "wifiscan"}, template("travelmate/wifi_scan")).leaf = true
|
||||
entry({"admin", "services", "travelmate", "wifiadd"}, form("travelmate/wifi_add", {hideresetbtn=true, hidesavebtn=true})).leaf = true
|
||||
entry({"admin", "services", "travelmate", "wifiedit"}, form("travelmate/wifi_edit", {hideresetbtn=true, hidesavebtn=true})).leaf = true
|
||||
entry({"admin", "services", "travelmate", "wifidelete"}, form("travelmate/wifi_delete", {hideresetbtn=true, hidesavebtn=true})).leaf = true
|
||||
entry({"admin", "services", "travelmate", "wifiorder"}, form("travelmate/wifi_order", {hideresetbtn=true, hidesavebtn=true})).leaf = true
|
||||
end
|
||||
|
||||
function trm_action(name)
|
||||
if name == "do_restart" then
|
||||
luci.sys.call("/etc/init.d/travelmate restart >/dev/null 2>&1")
|
||||
end
|
||||
luci.http.prepare_content("text/plain")
|
||||
luci.http.write("0")
|
||||
end
|
||||
|
||||
function status_update()
|
||||
local rt_file
|
||||
local content
|
||||
|
||||
rt_file = uci:get("travelmate", "global", "trm_rtfile") or "/tmp/trm_runtime.json"
|
||||
|
||||
if nixio.fs.access(rt_file) then
|
||||
content = json.parse(nixio.fs.readfile(rt_file) or "")
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(content)
|
||||
end
|
||||
end
|
||||
|
||||
function logread()
|
||||
local content = util.trim(util.exec("logread -e 'travelmate-'")) or ""
|
||||
|
||||
if content == "" then
|
||||
content = "No travelmate related logs yet!"
|
||||
end
|
||||
http.write(content)
|
||||
end
|
|
@ -1,41 +0,0 @@
|
|||
-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local util = require("luci.util")
|
||||
local input = "/etc/config/firewall"
|
||||
|
||||
if not fs.access(input) then
|
||||
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
|
||||
return m
|
||||
end
|
||||
|
||||
m = SimpleForm("input", nil)
|
||||
m:append(Template("travelmate/travelmate_css"))
|
||||
m.submit = translate("Save")
|
||||
m.reset = false
|
||||
|
||||
s = m:section(SimpleSection, nil,
|
||||
translate("This form allows you to modify the content of the main firewall configuration file (/etc/config/firewall)."))
|
||||
|
||||
f = s:option(TextValue, "data")
|
||||
f.rows = 20
|
||||
f.rmempty = true
|
||||
|
||||
function f.cfgvalue()
|
||||
return fs.readfile(input) or ""
|
||||
end
|
||||
|
||||
function f.write(self, section, data)
|
||||
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
|
||||
end
|
||||
|
||||
function f.remove(self, section, value)
|
||||
return fs.writefile(input, "")
|
||||
end
|
||||
|
||||
function s.handle(self, state, data)
|
||||
return true
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,41 +0,0 @@
|
|||
-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local util = require("luci.util")
|
||||
local input = "/etc/config/network"
|
||||
|
||||
if not fs.access(input) then
|
||||
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
|
||||
return m
|
||||
end
|
||||
|
||||
m = SimpleForm("input", nil)
|
||||
m:append(Template("travelmate/travelmate_css"))
|
||||
m.submit = translate("Save")
|
||||
m.reset = false
|
||||
|
||||
s = m:section(SimpleSection, nil,
|
||||
translate("This form allows you to modify the content of the main network configuration file (/etc/config/network)."))
|
||||
|
||||
f = s:option(TextValue, "data")
|
||||
f.rows = 20
|
||||
f.rmempty = true
|
||||
|
||||
function f.cfgvalue()
|
||||
return fs.readfile(input) or ""
|
||||
end
|
||||
|
||||
function f.write(self, section, data)
|
||||
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
|
||||
end
|
||||
|
||||
function f.remove(self, section, value)
|
||||
return fs.writefile(input, "")
|
||||
end
|
||||
|
||||
function s.handle(self, state, data)
|
||||
return true
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,41 +0,0 @@
|
|||
-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local util = require("luci.util")
|
||||
local input = "/etc/config/wireless"
|
||||
|
||||
if not fs.access(input) then
|
||||
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
|
||||
return m
|
||||
end
|
||||
|
||||
m = SimpleForm("input", nil)
|
||||
m:append(Template("travelmate/travelmate_css"))
|
||||
m.submit = translate("Save")
|
||||
m.reset = false
|
||||
|
||||
s = m:section(SimpleSection, nil,
|
||||
translate("This form allows you to modify the content of the main wireless configuration file (/etc/config/wireless)."))
|
||||
|
||||
f = s:option(TextValue, "data")
|
||||
f.rows = 20
|
||||
f.rmempty = true
|
||||
|
||||
function f.cfgvalue()
|
||||
return fs.readfile(input) or ""
|
||||
end
|
||||
|
||||
function f.write(self, section, data)
|
||||
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
|
||||
end
|
||||
|
||||
function f.remove(self, section, value)
|
||||
return fs.writefile(input, "")
|
||||
end
|
||||
|
||||
function s.handle(self, state, data)
|
||||
return true
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,43 +0,0 @@
|
|||
-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local util = require("luci.util")
|
||||
local input = "/etc/config/travelmate"
|
||||
|
||||
if not fs.access(input) then
|
||||
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
|
||||
m.reset = false
|
||||
m.submit = false
|
||||
return m
|
||||
end
|
||||
|
||||
m = SimpleForm("input", nil)
|
||||
m:append(Template("travelmate/travelmate_css"))
|
||||
m.submit = translate("Save")
|
||||
m.reset = false
|
||||
|
||||
s = m:section(SimpleSection, nil,
|
||||
translate("This form allows you to modify the content of the main travelmate configuration file (/etc/config/travelmate)."))
|
||||
|
||||
f = s:option(TextValue, "data")
|
||||
f.rows = 20
|
||||
f.rmempty = true
|
||||
|
||||
function f.cfgvalue()
|
||||
return fs.readfile(input) or ""
|
||||
end
|
||||
|
||||
function f.write(self, section, data)
|
||||
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
|
||||
end
|
||||
|
||||
function f.remove(self, section, value)
|
||||
return fs.writefile(input, "")
|
||||
end
|
||||
|
||||
function s.handle(self, state, data)
|
||||
return true
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,153 +0,0 @@
|
|||
-- Copyright 2017-2019 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local util = require("luci.util")
|
||||
local nw = require("luci.model.network").init()
|
||||
local fw = require("luci.model.firewall").init()
|
||||
local dump = util.ubus("network.interface", "dump", {})
|
||||
local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan"
|
||||
local uplink = uci:get("network", trmiface) or ""
|
||||
|
||||
m = Map("travelmate", translate("Travelmate"),
|
||||
translate("Configuration of the travelmate package to to enable travel router functionality. ")
|
||||
.. translatef("For further information "
|
||||
.. "<a href=\"%s\" target=\"_blank\">"
|
||||
.. "see online documentation</a>", "https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md"))
|
||||
m:chain("network")
|
||||
m:chain("firewall")
|
||||
|
||||
-- Interface Wizard
|
||||
|
||||
if uplink == "" then
|
||||
ds = m:section(NamedSection, "global", "travelmate", translate("Interface Wizard"))
|
||||
o = ds:option(Value, "trm_iface", translate("Create Uplink interface"),
|
||||
translate("Create a new wireless wan uplink interface, configure it to use dhcp and ")
|
||||
.. translate("add it to the wan zone of the firewall. ")
|
||||
.. translate("This step has only to be done once."))
|
||||
o.datatype = "and(uciname,rangelength(3,15))"
|
||||
o.default = trmiface
|
||||
o.rmempty = false
|
||||
|
||||
function o.validate(self, value)
|
||||
if value then
|
||||
local nwnet = nw:get_network(value)
|
||||
local zone = fw:get_zone("wan")
|
||||
local fwnet = fw:get_zone_by_network(value)
|
||||
if not nwnet then
|
||||
nwnet = nw:add_network(value, { proto = "dhcp" })
|
||||
end
|
||||
if zone and not fwnet then
|
||||
fwnet = zone:add_network(value)
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
-- Main travelmate options
|
||||
|
||||
s = m:section(NamedSection, "global", "travelmate")
|
||||
|
||||
o1 = s:option(Flag, "trm_enabled", translate("Enable Travelmate"))
|
||||
o1.default = o1.disabled
|
||||
o1.rmempty = false
|
||||
|
||||
o2 = s:option(Flag, "trm_captive", translate("Captive Portal Detection"),
|
||||
translate("Check the internet availability, log captive portal redirections and keep the uplink connection 'alive'."))
|
||||
o2.default = o2.enabled
|
||||
o2.rmempty = false
|
||||
|
||||
o3 = s:option(Flag, "trm_netcheck", translate("Net Error Check"),
|
||||
translate("Treat missing internet availability as an error."))
|
||||
o3:depends("trm_captive", 1)
|
||||
o3.default = o3.disabled
|
||||
o3.rmempty = false
|
||||
|
||||
o4 = s:option(Flag, "trm_proactive", translate("ProActive Uplink Switch"),
|
||||
translate("Proactively scan and switch to a higher prioritized uplink, despite of an already existing connection."))
|
||||
o4.default = o4.enabled
|
||||
o4.rmempty = false
|
||||
|
||||
o5 = s:option(Flag, "trm_autoadd", translate("Add Open Uplinks"),
|
||||
translate("Automatically add open uplinks like hotel captive portals to your wireless config."))
|
||||
o5.default = o5.disabled
|
||||
o5.rmempty = false
|
||||
|
||||
o6 = s:option(ListValue, "trm_iface", translate("Uplink / Trigger interface"),
|
||||
translate("Name of the used uplink interface."))
|
||||
if dump then
|
||||
local i, v
|
||||
for i, v in ipairs(dump.interface) do
|
||||
if v.interface ~= "loopback" and v.interface ~= "lan" then
|
||||
local device = v.l3_device or v.device or "-"
|
||||
o6:value(v.interface, v.interface.. " (" ..device.. ")")
|
||||
end
|
||||
end
|
||||
end
|
||||
o6.default = trmiface
|
||||
o6.rmempty = false
|
||||
|
||||
-- Runtime information
|
||||
|
||||
ds = s:option(DummyValue, "_dummy")
|
||||
ds.template = "travelmate/runtime"
|
||||
|
||||
-- Extra options
|
||||
|
||||
e = m:section(NamedSection, "global", "travelmate", translate("Extra Options"),
|
||||
translate("Options for further tweaking in case the defaults are not suitable for you."))
|
||||
|
||||
e1 = e:option(Flag, "trm_debug", translate("Enable Verbose Debug Logging"))
|
||||
e1.default = e1.disabled
|
||||
e1.rmempty = false
|
||||
|
||||
e2 = e:option(Value, "trm_radio", translate("Radio Selection / Order"),
|
||||
translate("Restrict travelmate to a single radio (e.g. 'radio1') or change the overall scanning order (e.g. 'radio1 radio2 radio0')."))
|
||||
e2.rmempty = true
|
||||
|
||||
e3 = e:option(Value, "trm_listexpiry", translate("List Auto Expiry"),
|
||||
translate("Automatically resets the 'Faulty Stations' list after n minutes. Default is '0' which means no expiry."))
|
||||
e3.datatype = "range(0,300)"
|
||||
e3.default = 0
|
||||
e3.rmempty = false
|
||||
|
||||
e4 = e:option(Value, "trm_triggerdelay", translate("Trigger Delay"),
|
||||
translate("Additional trigger delay in seconds before travelmate processing begins."))
|
||||
e4.datatype = "range(1,60)"
|
||||
e4.default = 2
|
||||
e4.rmempty = false
|
||||
|
||||
e5 = e:option(Value, "trm_maxretry", translate("Connection Limit"),
|
||||
translate("Retry limit to connect to an uplink."))
|
||||
e5.default = 5
|
||||
e5.datatype = "range(1,10)"
|
||||
e5.rmempty = false
|
||||
|
||||
e6 = e:option(Value, "trm_minquality", translate("Signal Quality Threshold"),
|
||||
translate("Minimum signal quality threshold as percent for conditional uplink (dis-) connections."))
|
||||
e6.default = 35
|
||||
e6.datatype = "range(20,80)"
|
||||
e6.rmempty = false
|
||||
|
||||
e7 = e:option(Value, "trm_maxwait", translate("Interface Timeout"),
|
||||
translate("How long should travelmate wait for a successful wlan uplink connection."))
|
||||
e7.default = 30
|
||||
e7.datatype = "range(20,40)"
|
||||
e7.rmempty = false
|
||||
|
||||
e8 = e:option(Value, "trm_timeout", translate("Overall Timeout"),
|
||||
translate("Overall retry timeout in seconds."))
|
||||
e8.default = 60
|
||||
e8.datatype = "range(30,300)"
|
||||
e8.rmempty = false
|
||||
|
||||
e10 = e:option(Value, "trm_scanbuffer", translate("Scan Buffer Size"),
|
||||
translate("Buffer size in bytes to prepare nearby scan results."))
|
||||
e10.default = 1024
|
||||
e10.datatype = "range(512,4096)"
|
||||
e10.optional = true
|
||||
|
||||
return m
|
|
@ -1,226 +0,0 @@
|
|||
-- Copyright 2017-2019 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local http = require("luci.http")
|
||||
local util = require("luci.util")
|
||||
local scripts = util.split(util.trim(util.exec("ls /etc/travelmate/*.login 2>/dev/null")), "\n", nil, true) or {}
|
||||
local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan"
|
||||
local encr_psk = {"psk", "psk2", "psk-mixed", "sae", "owe", "sae-mixed"}
|
||||
local encr_wpa = {"wpa", "wpa2", "wpa-mixed"}
|
||||
|
||||
m = SimpleForm("add", translate("Add Wireless Uplink Configuration"))
|
||||
m.submit = translate("Save")
|
||||
m.cancel = translate("Back to overview")
|
||||
m.reset = false
|
||||
|
||||
function m.on_cancel()
|
||||
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
|
||||
end
|
||||
|
||||
m.hidden = {
|
||||
device = http.formvalue("device"),
|
||||
ssid = http.formvalue("ssid"),
|
||||
bssid = http.formvalue("bssid"),
|
||||
description = http.formvalue("description"),
|
||||
wep = tonumber(http.formvalue("wep")) or 0,
|
||||
wpa_suites = http.formvalue("wpa_suites"),
|
||||
wpa_version = tonumber(http.formvalue("wpa_version")) or 0
|
||||
}
|
||||
|
||||
if m.hidden.wpa_version == 4 then
|
||||
if string.find(m.hidden.description, "OWE") then
|
||||
m.hidden.wpa_version = 5
|
||||
end
|
||||
end
|
||||
|
||||
if m.hidden.ssid == "" then
|
||||
wssid = m:field(Value, "ssid", translate("SSID (hidden)"))
|
||||
else
|
||||
wssid = m:field(Value, "ssid", translate("SSID"))
|
||||
end
|
||||
wssid.datatype = "rangelength(1,32)"
|
||||
wssid.default = m.hidden.ssid or ""
|
||||
|
||||
nobssid = m:field(Flag, "no_bssid", translate("Ignore BSSID"))
|
||||
if m.hidden.ssid == "" then
|
||||
nobssid.default = nobssid.disabled
|
||||
else
|
||||
nobssid.default = nobssid.enabled
|
||||
end
|
||||
|
||||
bssid = m:field(Value, "bssid", translate("BSSID"),
|
||||
translatef("The BSSID information '%s' is optional and only required for hidden networks", m.hidden.bssid or ""))
|
||||
bssid:depends("no_bssid", 0)
|
||||
bssid.datatype = "macaddr"
|
||||
bssid.default = m.hidden.bssid or ""
|
||||
|
||||
if m.hidden.wep == 1 then
|
||||
encr = m:field(ListValue, "encryption", translate("Encryption"))
|
||||
encr:value("wep", "WEP")
|
||||
encr:value("wep+open", "WEP Open System")
|
||||
encr:value("wep+mixed", "WEP mixed")
|
||||
encr:value("wep+shared", "WEP Shared Key")
|
||||
encr.default = "wep+open"
|
||||
|
||||
wkey = m:field(Value, "key", translate("WEP-Passphrase"))
|
||||
wkey.password = true
|
||||
wkey.datatype = "wepkey"
|
||||
elseif m.hidden.wpa_version > 0 then
|
||||
if m.hidden.wpa_suites == "802.1X" then
|
||||
encr = m:field(ListValue, "encryption", translate("Encryption"))
|
||||
encr:value("wpa", "WPA Enterprise")
|
||||
encr:value("wpa-mixed", "WPA/WPA2 Enterprise mixed")
|
||||
encr:value("wpa2", "WPA2 Enterprise")
|
||||
encr.default = encr_wpa[m.hidden.wpa_version] or "wpa2"
|
||||
|
||||
ciph = m:field(ListValue, "cipher", translate("Cipher"))
|
||||
ciph:value("auto", translate("Automatic"))
|
||||
ciph:value("ccmp", translate("Force CCMP (AES)"))
|
||||
ciph:value("tkip", translate("Force TKIP"))
|
||||
ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)"))
|
||||
ciph.default = "auto"
|
||||
|
||||
eaptype = m:field(ListValue, "eap_type", translate("EAP-Method"))
|
||||
eaptype:value("tls", "TLS")
|
||||
eaptype:value("ttls", "TTLS")
|
||||
eaptype:value("peap", "PEAP")
|
||||
eaptype:value("fast", "FAST")
|
||||
eaptype.default = "peap"
|
||||
|
||||
authentication = m:field(ListValue, "auth", translate("Authentication"))
|
||||
authentication:value("PAP")
|
||||
authentication:value("CHAP")
|
||||
authentication:value("MSCHAP")
|
||||
authentication:value("MSCHAPV2")
|
||||
authentication:value("EAP-GTC")
|
||||
authentication:value("EAP-MD5")
|
||||
authentication:value("EAP-MSCHAPV2")
|
||||
authentication:value("EAP-TLS")
|
||||
authentication:value("auth=PAP")
|
||||
authentication:value("auth=MSCHAPV2")
|
||||
authentication.default = "EAP-MSCHAPV2"
|
||||
|
||||
ident = m:field(Value, "identity", translate("Identity"))
|
||||
|
||||
wkey = m:field(Value, "password", translate("Password"))
|
||||
wkey.password = true
|
||||
wkey.datatype = "wpakey"
|
||||
|
||||
cacert = m:field(Value, "ca_cert", translate("Path to CA-Certificate"))
|
||||
cacert.rmempty = true
|
||||
|
||||
clientcert = m:field(Value, "client_cert", translate("Path to Client-Certificate"))
|
||||
clientcert:depends("eap_type","tls")
|
||||
clientcert.rmempty = true
|
||||
|
||||
privkey = m:field(Value, "priv_key", translate("Path to Private Key"))
|
||||
privkey:depends("eap_type","tls")
|
||||
privkey.rmempty = true
|
||||
|
||||
privkeypwd = m:field(Value, "priv_key_pwd", translate("Password of Private Key"))
|
||||
privkeypwd:depends("eap_type","tls")
|
||||
privkeypwd.datatype = "wpakey"
|
||||
privkeypwd.password = true
|
||||
privkeypwd.rmempty = true
|
||||
else
|
||||
encr = m:field(ListValue, "encryption", translate("Encryption"))
|
||||
encr:value("psk", "WPA-PSK")
|
||||
encr:value("psk2", "WPA2-PSK")
|
||||
encr:value("psk-mixed", "WPA/WPA2 mixed")
|
||||
encr:value("sae", "WPA3-SAE")
|
||||
encr:value("owe", "OWE (open network)")
|
||||
encr:value("sae-mixed", "WPA2/WPA3 mixed")
|
||||
encr.default = encr_psk[m.hidden.wpa_version] or "psk2"
|
||||
|
||||
ciph = m:field(ListValue, "cipher", translate("Cipher"))
|
||||
ciph:value("auto", translate("Automatic"))
|
||||
ciph:value("ccmp", translate("Force CCMP (AES)"))
|
||||
ciph:value("tkip", translate("Force TKIP"))
|
||||
ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)"))
|
||||
ciph:depends("encryption", "psk")
|
||||
ciph:depends("encryption", "psk2")
|
||||
ciph:depends("encryption", "psk-mixed")
|
||||
ciph.default = "auto"
|
||||
|
||||
wkey = m:field(Value, "key", translate("WPA-Passphrase"))
|
||||
wkey.password = true
|
||||
wkey.datatype = "wpakey"
|
||||
wkey:depends("encryption", "psk")
|
||||
wkey:depends("encryption", "psk2")
|
||||
wkey:depends("encryption", "psk-mixed")
|
||||
wkey:depends("encryption", "sae")
|
||||
wkey:depends("encryption", "sae-mixed")
|
||||
end
|
||||
end
|
||||
|
||||
local login_section = (m.hidden.device or "") .. "_" .. (m.hidden.ssid or "") .. "_" .. (m.hidden.bssid or "")
|
||||
login_section = login_section:gsub("[^%w_]", "_")
|
||||
local cmd = uci:get("travelmate", login_section, "command")
|
||||
local cmd_args_default = uci:get("travelmate", login_section, "command_args")
|
||||
cmd_list = m:field(ListValue, "cmdlist", translate("Auto Login Script"),
|
||||
translate("External script reference which will be called for automated captive portal logins."))
|
||||
cmd_args = m:field(Value, "cmdargs", translate("Optional Arguments"),
|
||||
translate("Space separated list of additional arguments passed to the Auto Login Script, i.e. username and password"))
|
||||
for _, z in ipairs(scripts) do
|
||||
cmd_list:value(z)
|
||||
cmd_args:depends("cmdlist", z)
|
||||
end
|
||||
cmd_list:value("none")
|
||||
cmd_list.default = cmd or "none"
|
||||
cmd_args.default = cmd_args_default
|
||||
|
||||
function wssid.write(self, section, value)
|
||||
login_section = (m.hidden.device or "") .. "_" .. (wssid:formvalue(section) or "") .. "_" .. (bssid:formvalue(section) or "")
|
||||
login_section = login_section:gsub("[^%w_]", "_")
|
||||
newsection = uci:section("wireless", "wifi-iface", login_section, {
|
||||
mode = "sta",
|
||||
network = trmiface,
|
||||
device = m.hidden.device,
|
||||
ssid = wssid:formvalue(section),
|
||||
bssid = bssid:formvalue(section),
|
||||
disabled = "1"
|
||||
})
|
||||
|
||||
if encr then
|
||||
if string.find(encr:formvalue(section), '^wep') then
|
||||
uci:set("wireless", newsection, "encryption", encr:formvalue(section))
|
||||
uci:set("wireless", newsection, "key", wkey:formvalue(section) or "")
|
||||
elseif string.find(encr:formvalue(section), '^wpa') then
|
||||
uci:set("wireless", newsection, "eap_type", eaptype:formvalue(section))
|
||||
uci:set("wireless", newsection, "auth", authentication:formvalue(section))
|
||||
uci:set("wireless", newsection, "identity", ident:formvalue(section) or "")
|
||||
uci:set("wireless", newsection, "password", wkey:formvalue(section) or "")
|
||||
uci:set("wireless", newsection, "ca_cert", cacert:formvalue(section) or "")
|
||||
uci:set("wireless", newsection, "client_cert", clientcert:formvalue(section) or "")
|
||||
uci:set("wireless", newsection, "priv_key", privkey:formvalue(section) or "")
|
||||
uci:set("wireless", newsection, "priv_key_pwd", privkeypwd:formvalue(section) or "")
|
||||
elseif encr:formvalue(section) ~= "owe" then
|
||||
uci:set("wireless", newsection, "key", wkey:formvalue(section) or "")
|
||||
end
|
||||
if ciph and ciph:formvalue(section) and ciph:formvalue(section) ~= "auto" then
|
||||
uci:set("wireless", newsection, "encryption", encr:formvalue(section) .. "+" .. ciph:formvalue(section))
|
||||
else
|
||||
uci:set("wireless", newsection, "encryption", encr:formvalue(section))
|
||||
end
|
||||
else
|
||||
uci:set("wireless", newsection, "encryption", "none")
|
||||
end
|
||||
|
||||
if not uci:get("travelmate", login_section) and cmd_list:formvalue(section) ~= "none" then
|
||||
uci:set("travelmate", login_section, "login")
|
||||
end
|
||||
if uci:get("travelmate", login_section) then
|
||||
uci:set("travelmate", login_section, "command", cmd_list:formvalue(section))
|
||||
uci:set("travelmate", login_section, "command_args", cmd_args:formvalue(section))
|
||||
uci:save("travelmate")
|
||||
uci:commit("travelmate")
|
||||
end
|
||||
uci:save("wireless")
|
||||
uci:commit("wireless")
|
||||
luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
|
||||
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,14 +0,0 @@
|
|||
-- Copyright 2017 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local http = require("luci.http")
|
||||
local cfg = http.formvalue("cfg")
|
||||
|
||||
if cfg ~= nil then
|
||||
uci:delete("wireless", cfg)
|
||||
uci:save("wireless")
|
||||
uci:commit("wireless")
|
||||
luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
|
||||
end
|
||||
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
|
|
@ -1,207 +0,0 @@
|
|||
-- Copyright 2017-2019 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local fs = require("nixio.fs")
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local http = require("luci.http")
|
||||
local util = require("luci.util")
|
||||
local scripts = util.split(util.trim(util.exec("ls /etc/travelmate/*.login 2>/dev/null")), "\n", nil, true) or {}
|
||||
|
||||
m = SimpleForm("edit", translate("Edit Wireless Uplink Configuration"))
|
||||
m.submit = translate("Save")
|
||||
m.cancel = translate("Back to overview")
|
||||
m.reset = false
|
||||
|
||||
function m.on_cancel()
|
||||
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
|
||||
end
|
||||
|
||||
m.hidden = {
|
||||
cfg = http.formvalue("cfg")
|
||||
}
|
||||
|
||||
local s = uci:get_all("wireless", m.hidden.cfg)
|
||||
|
||||
if s ~= nil then
|
||||
wssid = m:field(Value, "ssid", translate("SSID"))
|
||||
wssid.datatype = "rangelength(1,32)"
|
||||
wssid.default = s.ssid or ""
|
||||
|
||||
bssid = m:field(Value, "bssid", translate("BSSID"))
|
||||
bssid.datatype = "macaddr"
|
||||
bssid.default = s.bssid or ""
|
||||
|
||||
if string.match(s.encryption, '%+') and not string.match(s.encryption, '^wep') then
|
||||
s.pos = string.find(s.encryption, '%+')
|
||||
s.cipher = string.sub(s.encryption, s.pos + 1)
|
||||
s.encryption = string.sub(s.encryption, 0, s.pos - 1)
|
||||
end
|
||||
|
||||
if s.encryption and s.encryption ~= "none" then
|
||||
if string.match(s.encryption, '^wep') then
|
||||
encr = m:field(ListValue, "encryption", translate("Encryption"))
|
||||
encr:value("wep", "WEP")
|
||||
encr:value("wep+open", "WEP Open System")
|
||||
encr:value("wep+mixed", "WEP mixed")
|
||||
encr:value("wep+shared", "WEP Shared Key")
|
||||
encr.default = s.encryption
|
||||
|
||||
wkey = m:field(Value, "key", translate("Passphrase"))
|
||||
wkey.datatype = "wepkey"
|
||||
wkey.password = true
|
||||
wkey.default = s.key
|
||||
elseif string.match(s.encryption, '^wpa') then
|
||||
encr = m:field(ListValue, "encryption", translate("Encryption"))
|
||||
encr:value("wpa", "WPA Enterprise")
|
||||
encr:value("wpa-mixed", "WPA/WPA2 Enterprise mixed")
|
||||
encr:value("wpa2", "WPA2 Enterprise")
|
||||
encr.default = s.encryption
|
||||
|
||||
ciph = m:field(ListValue, "cipher", translate("Cipher"))
|
||||
ciph:value("auto", translate("Automatic"))
|
||||
ciph:value("ccmp", translate("Force CCMP (AES)"))
|
||||
ciph:value("tkip", translate("Force TKIP"))
|
||||
ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)"))
|
||||
ciph.default = s.cipher
|
||||
|
||||
eaptype = m:field(ListValue, "eap_type", translate("EAP-Method"))
|
||||
eaptype:value("tls", "TLS")
|
||||
eaptype:value("ttls", "TTLS")
|
||||
eaptype:value("peap", "PEAP")
|
||||
eaptype:value("fast", "FAST")
|
||||
eaptype.default = s.eap_type or "peap"
|
||||
|
||||
authentication = m:field(ListValue, "auth", translate("Authentication"))
|
||||
authentication:value("PAP")
|
||||
authentication:value("CHAP")
|
||||
authentication:value("MSCHAP")
|
||||
authentication:value("MSCHAPV2")
|
||||
authentication:value("EAP-GTC")
|
||||
authentication:value("EAP-MD5")
|
||||
authentication:value("EAP-MSCHAPV2")
|
||||
authentication:value("EAP-TLS")
|
||||
authentication:value("auth=PAP")
|
||||
authentication:value("auth=MSCHAPV2")
|
||||
authentication.default = s.auth or "EAP-MSCHAPV2"
|
||||
|
||||
ident = m:field(Value, "identity", translate("Identity"))
|
||||
ident.default = s.identity or ""
|
||||
|
||||
wkey = m:field(Value, "password", translate("Passphrase"))
|
||||
wkey.datatype = "wpakey"
|
||||
wkey.password = true
|
||||
wkey.default = s.password
|
||||
|
||||
cacert = m:field(Value, "ca_cert", translate("Path to CA-Certificate"))
|
||||
cacert.rmempty = true
|
||||
cacert.default = s.ca_cert or ""
|
||||
|
||||
clientcert = m:field(Value, "client_cert", translate("Path to Client-Certificate"))
|
||||
clientcert:depends("eap_type","tls")
|
||||
clientcert.rmempty = true
|
||||
clientcert.default = s.client_cert or ""
|
||||
|
||||
privkey = m:field(Value, "priv_key", translate("Path to Private Key"))
|
||||
privkey:depends("eap_type","tls")
|
||||
privkey.rmempty = true
|
||||
privkey.default = s.priv_key or ""
|
||||
|
||||
privkeypwd = m:field(Value, "priv_key_pwd", translate("Password of Private Key"))
|
||||
privkeypwd:depends("eap_type","tls")
|
||||
privkeypwd.datatype = "wpakey"
|
||||
privkeypwd.password = true
|
||||
privkeypwd.rmempty = true
|
||||
privkeypwd.default = s.priv_key_pwd or ""
|
||||
else
|
||||
encr = m:field(ListValue, "encryption", translate("Encryption"))
|
||||
encr:value("psk", "WPA-PSK")
|
||||
encr:value("psk2", "WPA2-PSK")
|
||||
encr:value("psk-mixed", "WPA/WPA2 mixed")
|
||||
encr:value("sae", "WPA3-SAE")
|
||||
encr:value("owe", "OWE (open network)")
|
||||
encr:value("sae-mixed", "WPA2/WPA3 mixed")
|
||||
encr.default = s.encryption
|
||||
|
||||
ciph = m:field(ListValue, "cipher", translate("Cipher"))
|
||||
ciph:value("auto", translate("Automatic"))
|
||||
ciph:value("ccmp", translate("Force CCMP (AES)"))
|
||||
ciph:value("tkip", translate("Force TKIP"))
|
||||
ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)"))
|
||||
ciph:depends("encryption", "psk")
|
||||
ciph:depends("encryption", "psk2")
|
||||
ciph:depends("encryption", "psk-mixed")
|
||||
ciph.default = s.cipher or "auto"
|
||||
|
||||
wkey = m:field(Value, "key", translate("Passphrase"))
|
||||
wkey.datatype = "wpakey"
|
||||
wkey.password = true
|
||||
wkey:depends("encryption", "psk")
|
||||
wkey:depends("encryption", "psk2")
|
||||
wkey:depends("encryption", "psk-mixed")
|
||||
wkey:depends("encryption", "sae")
|
||||
wkey:depends("encryption", "sae-mixed")
|
||||
wkey.default = s.key
|
||||
end
|
||||
end
|
||||
else
|
||||
m.on_cancel()
|
||||
end
|
||||
|
||||
local login_section = (s.device or "") .. "_" .. (s.ssid or "") .. "_" .. (s.bssid or "")
|
||||
login_section = login_section:gsub("[^%w_]", "_")
|
||||
local cmd = uci:get("travelmate", login_section, "command")
|
||||
local cmd_args_default = uci:get("travelmate", login_section, "command_args")
|
||||
cmd_list = m:field(ListValue, "cmdlist", translate("Auto Login Script"),
|
||||
translate("External script reference which will be called for automated captive portal logins."))
|
||||
cmd_args = m:field(Value, "cmdargs", translate("Optional Arguments"),
|
||||
translate("Space separated list of additional arguments passed to the Auto Login Script, i.e. username and password"))
|
||||
for _, z in ipairs(scripts) do
|
||||
cmd_list:value(z)
|
||||
cmd_args:depends("cmdlist", z)
|
||||
end
|
||||
cmd_list:value("none")
|
||||
cmd_list.default = cmd or "none"
|
||||
cmd_args.default = cmd_args_default
|
||||
|
||||
function wssid.write(self, section, value)
|
||||
uci:set("wireless", m.hidden.cfg, "ssid", wssid:formvalue(section))
|
||||
uci:set("wireless", m.hidden.cfg, "bssid", bssid:formvalue(section))
|
||||
if encr then
|
||||
if string.find(encr:formvalue(section), '^wep') then
|
||||
uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section))
|
||||
uci:set("wireless", m.hidden.cfg, "key", wkey:formvalue(section) or "")
|
||||
elseif string.find(encr:formvalue(section), '^wpa') then
|
||||
uci:set("wireless", m.hidden.cfg, "eap_type", eaptype:formvalue(section))
|
||||
uci:set("wireless", m.hidden.cfg, "auth", authentication:formvalue(section))
|
||||
uci:set("wireless", m.hidden.cfg, "identity", ident:formvalue(section) or "")
|
||||
uci:set("wireless", m.hidden.cfg, "password", wkey:formvalue(section) or "")
|
||||
uci:set("wireless", m.hidden.cfg, "ca_cert", cacert:formvalue(section) or "")
|
||||
uci:set("wireless", m.hidden.cfg, "client_cert", clientcert:formvalue(section) or "")
|
||||
uci:set("wireless", m.hidden.cfg, "priv_key", privkey:formvalue(section) or "")
|
||||
uci:set("wireless", m.hidden.cfg, "priv_key_pwd", privkeypwd:formvalue(section) or "")
|
||||
elseif encr:formvalue(section) ~= "owe" then
|
||||
uci:set("wireless", m.hidden.cfg, "key", wkey:formvalue(section) or "")
|
||||
end
|
||||
if ciph and ciph:formvalue(section) and ciph:formvalue(section) ~= "auto" then
|
||||
uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section) .. "+" .. ciph:formvalue(section))
|
||||
else
|
||||
uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section))
|
||||
end
|
||||
end
|
||||
|
||||
if not uci:get("travelmate", login_section) and cmd_list:formvalue(section) ~= "none" then
|
||||
uci:set("travelmate", login_section, "login")
|
||||
end
|
||||
if uci:get("travelmate", login_section) then
|
||||
uci:set("travelmate", login_section, "command", cmd_list:formvalue(section))
|
||||
uci:set("travelmate", login_section, "command_args", cmd_args:formvalue(section))
|
||||
uci:save("travelmate")
|
||||
uci:commit("travelmate")
|
||||
end
|
||||
uci:save("wireless")
|
||||
uci:commit("wireless")
|
||||
luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
|
||||
m.on_cancel()
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,36 +0,0 @@
|
|||
-- Copyright 2017 Dirk Brenken (dev@brenken.org)
|
||||
-- This is free software, licensed under the Apache License, Version 2.0
|
||||
|
||||
local http = require("luci.http")
|
||||
local cfg = http.formvalue("cfg")
|
||||
local dir = http.formvalue("dir")
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan"
|
||||
|
||||
if cfg ~= nil then
|
||||
local section = ""
|
||||
local idx = ""
|
||||
local idx_change = ""
|
||||
local changed = ""
|
||||
uci:foreach("wireless", "wifi-iface", function(s)
|
||||
local iface = s.network or ""
|
||||
if iface == trmiface then
|
||||
section = s['.name']
|
||||
if cfg == section then
|
||||
idx = s['.index']
|
||||
else
|
||||
idx_change = s['.index']
|
||||
end
|
||||
if (dir == "up" and idx ~= "" and idx_change ~= "" and idx_change < idx) or
|
||||
(dir == "down" and idx ~= "" and idx_change ~= "" and idx_change > idx) then
|
||||
changed = uci:reorder("wireless", cfg, idx_change)
|
||||
idx = ""
|
||||
end
|
||||
end
|
||||
end)
|
||||
if changed ~= "" then
|
||||
uci:save("wireless")
|
||||
uci:commit("wireless")
|
||||
end
|
||||
end
|
||||
http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
|
|
@ -1,36 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
|
||||
This is free software, licensed under the Apache License, Version 2.0
|
||||
-%>
|
||||
|
||||
<%+header%>
|
||||
<%+travelmate/travelmate_css%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function log_update()
|
||||
{
|
||||
XHR.poll(-1, '<%=luci.dispatcher.build_url("admin", "services", "travelmate", "logread")%>', null,
|
||||
function(x)
|
||||
{
|
||||
if (!x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var view = document.getElementById("view_id");
|
||||
view.value = x.responseText;
|
||||
view.scrollTop = view.scrollHeight;
|
||||
});
|
||||
}
|
||||
window.onload = log_update();
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-map">
|
||||
<div class="cbi-section">
|
||||
<div class="cbi-section-descr"><%:The syslog output, pre-filtered for travelmate related messages only.%></div>
|
||||
<textarea id="view_id" readonly="readonly" wrap="off" value=""></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%+footer%>
|
|
@ -1,223 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2019 Dirk Brenken (dev@brenken.org)
|
||||
This is free software, licensed under the Apache License, Version 2.0
|
||||
-%>
|
||||
|
||||
<%+travelmate/travelmate_css%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function status_update(json)
|
||||
{
|
||||
var btn1 = document.getElementById("btn1");
|
||||
var view = document.getElementById("value_1");
|
||||
var input = json.data.travelmate_status;
|
||||
|
||||
btn1.value = "<%:Restart%>";
|
||||
btn1.name = "do_restart";
|
||||
view.innerHTML = input || "-";
|
||||
view = document.getElementById("value_2");
|
||||
input = json.data.travelmate_version;
|
||||
view.innerHTML = input || "-";
|
||||
view = document.getElementById("value_3");
|
||||
input = json.data.station_id;
|
||||
view.innerHTML = input || "-";
|
||||
view = document.getElementById("value_4");
|
||||
input = json.data.station_interface;
|
||||
view.innerHTML = input || "-";
|
||||
view = document.getElementById("value_5");
|
||||
input = json.data.faulty_stations;
|
||||
view.innerHTML = input || "-";
|
||||
view = document.getElementById("value_6");
|
||||
input = json.data.wpa_capabilities;
|
||||
view.innerHTML = input || "-";
|
||||
view = document.getElementById("value_7");
|
||||
input = json.data.last_rundate;
|
||||
view.innerHTML = input || "-";
|
||||
}
|
||||
|
||||
function btn_action(action)
|
||||
{
|
||||
var btn1 = document.getElementById("btn1");
|
||||
var btn1_running = document.getElementById("btn1_running");
|
||||
|
||||
btn1.disabled = true;
|
||||
running(btn1_running, 1);
|
||||
|
||||
new XHR.get('<%=luci.dispatcher.build_url("admin", "services", "travelmate")%>/action/' + action.name, null,
|
||||
function(x)
|
||||
{
|
||||
if (!x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
btn1.disabled = false;
|
||||
running(btn1_running, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function running(element, state)
|
||||
{
|
||||
if (state === 1)
|
||||
{
|
||||
var running_html = '<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" width="16" height="16" style="vertical-align:middle" />';
|
||||
element.innerHTML = running_html;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_qrcode() {
|
||||
var view = document.getElementById("qrcode");
|
||||
if (view.style.display === "none") {
|
||||
view.style.display = "block";
|
||||
} else {
|
||||
view.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "travelmate", "status")%>', null,
|
||||
function(x, json_info)
|
||||
{
|
||||
if (!x || !json_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
status_update(json_info)
|
||||
});
|
||||
|
||||
XHR.poll(-1, '<%=luci.dispatcher.build_url("admin", "services", "travelmate", "status")%>', null,
|
||||
function(x, json_info)
|
||||
{
|
||||
if (!x || !json_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
status_update(json_info)
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<h3><%:Runtime Information%></h3>
|
||||
<div class="cbi-value" id="status_1">
|
||||
<label class="cbi-value-title" for="status_1"><%:Travelmate Status (Quality)%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_1">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="status_2">
|
||||
<label class="cbi-value-title" for="status_2"><%:Travelmate Version%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_2">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="status_3">
|
||||
<label class="cbi-value-title" for="status_3"><%:Station ID (RADIO/SSID/BSSID)%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_3">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="status_4">
|
||||
<label class="cbi-value-title" for="status_4"><%:Station Interface%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_4">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="status_5">
|
||||
<label class="cbi-value-title" for="status_5"><%:Faulty Stations%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_5">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="status_6">
|
||||
<label class="cbi-value-title" for="status_6"><%:WPA Capabilities%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_6">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="status_7">
|
||||
<label class="cbi-value-title" for="status_7"><%:Last Run%></label>
|
||||
<div class="cbi-value-field">
|
||||
<span class="runtime" id="value_7">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="cbi-value" id="button_1">
|
||||
<label class="cbi-value-title" for="button_1"><%:Restart Travelmate%></label>
|
||||
<div class="cbi-value-field">
|
||||
<input class="cbi-button cbi-button-reset" id="btn1" type="button" name="do_restart" value="<%:Restart%>" onclick="btn_action(this)" />
|
||||
<span id="btn1_running" class="btn_running"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" id="button_2">
|
||||
<label class="cbi-value-title" for="button_2"><%:View AP QR-Codes%></label>
|
||||
<div class="cbi-value-field">
|
||||
<input class="cbi-button cbi-button-apply" type="button" value="<%:Show/Hide QR-Codes%>" onclick="toggle_qrcode()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value" style="margin-bottom: 0px">
|
||||
<span class="cbi-value" style="display: none" id="qrcode">
|
||||
<%-
|
||||
local fs = require("nixio.fs")
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local qrcode
|
||||
|
||||
uci:foreach("wireless", "wifi-iface", function(s)
|
||||
local device = s.device or ""
|
||||
local mode = s.mode or ""
|
||||
local ssid = s.ssid or ""
|
||||
local enc = s.encryption or ""
|
||||
local key = s.key or ""
|
||||
local hidden = s.hidden or "false"
|
||||
local disabled = s.disabled or ""
|
||||
local wep_slots = {s.key1 or "", s.key2 or "", s.key3 or "", s.key4 or ""}
|
||||
|
||||
if device and mode == "ap" and disabled ~= "1" then
|
||||
if string.match(enc, '^psk') then
|
||||
enc = "WPA"
|
||||
elseif string.match(enc, '^wep') then
|
||||
enc = "WEP"
|
||||
if tonumber(key) then
|
||||
key = wep_slots[tonumber(key)]
|
||||
end
|
||||
elseif enc == "none" then
|
||||
enc = "nopass"
|
||||
key = "nokey"
|
||||
else
|
||||
enc = ""
|
||||
end
|
||||
|
||||
if hidden == "1" then
|
||||
hidden = "true"
|
||||
end
|
||||
|
||||
if ssid and enc and key then
|
||||
local e_ssid = string.gsub(ssid,"[\"\\';:,()&`|<> ]",[[\\\%1]])
|
||||
local e_key = string.gsub(key,"[\"\\';:,()&`|<> ]",[[\\\%1]])
|
||||
|
||||
if fs.access("/usr/bin/qrencode") then
|
||||
qrcode = luci.sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- 'WIFI:S:\"'" .. e_ssid .. "'\";T:'" .. enc .. "';P:\"'" .. e_key .. "'\";H:'" .. hidden .. "';'")
|
||||
-%>
|
||||
<div class="qr-code">
|
||||
<%=qrcode%>
|
||||
</div>
|
||||
<div class="qr-code">
|
||||
<em><%:AP on %><%=device%><%: with SSID %>"<%=ssid%>"</em>
|
||||
<hr />
|
||||
</div>
|
||||
<%-
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not qrcode then
|
||||
-%>
|
||||
<div class="qr-code">
|
||||
<em><%:For QR-Code support please install package 'qrencode'!%></em>
|
||||
</div>
|
||||
<%-
|
||||
end
|
||||
-%>
|
||||
</span>
|
||||
</div>
|
|
@ -1,154 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2019 Dirk Brenken (dev@brenken.org)
|
||||
This is free software, licensed under the Apache License, Version 2.0
|
||||
-%>
|
||||
|
||||
<%-
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan"
|
||||
-%>
|
||||
|
||||
<%+header%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function status_update(json)
|
||||
{
|
||||
var i;
|
||||
var j;
|
||||
var search;
|
||||
var view;
|
||||
var list;
|
||||
var status = json.data.travelmate_status;
|
||||
var faulty = json.data.faulty_stations;
|
||||
|
||||
if (faulty)
|
||||
{
|
||||
var faulty_array = faulty.split(' ');
|
||||
for (i = 0; i < faulty_array.length; i++)
|
||||
{
|
||||
for (j = 1; j <= 5; j++)
|
||||
{
|
||||
search = j + "_" + faulty_array[i];
|
||||
view = document.getElementById(search);
|
||||
if (view)
|
||||
{
|
||||
view.setAttribute("name", "station_nok");
|
||||
view.setAttribute("style", "text-align: left !important; color: #a22; font-weight: bold");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list = document.getElementsByName("station_nok");
|
||||
if (list.length > 0)
|
||||
{
|
||||
for (i = 0; i < list.length; i++)
|
||||
{
|
||||
list[i].removeAttribute("style");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status.startsWith("connected"))
|
||||
{
|
||||
for (i = 1; i <= 5; i++)
|
||||
{
|
||||
search = i + "_" + json.data.station_id;
|
||||
view = document.getElementById(search);
|
||||
if (view)
|
||||
{
|
||||
view.setAttribute("style", "text-align: left !important; color: #37c; font-weight: bold");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list = document.getElementsByName("station_ok");
|
||||
if (list.length > 0)
|
||||
{
|
||||
for (i = 0; i < list.length; i++)
|
||||
{
|
||||
list[i].removeAttribute("style");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "travelmate", "status")%>', null,
|
||||
function(x, json_info)
|
||||
{
|
||||
if (!x || !json_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
status_update(json_info)
|
||||
});
|
||||
|
||||
XHR.poll(-1, '<%=luci.dispatcher.build_url("admin", "services", "travelmate", "status")%>', null,
|
||||
function(x, json_info)
|
||||
{
|
||||
if (!x || !json_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
status_update(json_info)
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-map">
|
||||
<div class="cbi-map-descr">
|
||||
<%=translatef("Provides an overview of all configured uplinks for the travelmate interface (%s). You can edit, remove or re-order/prioritize existing uplinks or scan for new ones. The currently used uplink is emphasized in blue, faulty stations in red.", trmiface)%>
|
||||
</div>
|
||||
|
||||
<div class="cbi-section">
|
||||
<div class="table cbi-section-table">
|
||||
<div class="tr cbi-section-table-titles">
|
||||
<div class="th left"><%:Device%></div>
|
||||
<div class="th left"><%:SSID%></div>
|
||||
<div class="th left"><%:BSSID%></div>
|
||||
<div class="th left"><%:Encryption%></div>
|
||||
<div class="th center"><%:Action%></div>
|
||||
</div>
|
||||
<%- uci:foreach("wireless", "wifi-iface", function(s)
|
||||
local iface = s.network or ""
|
||||
if iface == trmiface then
|
||||
local section = s['.name'] or ""
|
||||
local device = s.device or "-"
|
||||
local ssid = s.ssid or "-"
|
||||
local bssid = s.bssid or "-"
|
||||
local encr = s.encryption or "-"
|
||||
-%>
|
||||
<div class="tr cbi-section-table-row cbi-rowstyle-1" name="station_ok" id="1_<%=device%>/<%=ssid%>/<%=bssid%>">
|
||||
<div class="td left" style="text-align: left !important" name="station_ok" id="2_<%=device%>/<%=ssid%>/<%=bssid%>"><%=device%></div>
|
||||
<div class="td left" style="text-align: left !important" name="station_ok" id="3_<%=device%>/<%=ssid%>/<%=bssid%>"><%=ssid%></div>
|
||||
<div class="td left" style="text-align: left !important" name="station_ok" id="4_<%=device%>/<%=ssid%>/<%=bssid%>"><%=bssid%></div>
|
||||
<div class="td left" style="text-align: left !important" name="station_ok" id="5_<%=device%>/<%=ssid%>/<%=bssid%>"><%=encr%></div>
|
||||
<div class="td middle cbi-section-actions">
|
||||
<div>
|
||||
<input class="cbi-button cbi-button-up" type="button" value="<%:Up%>" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>&dir=up'" alt="<%:Move up%>" title="<%:Move up%>" />
|
||||
<input class="cbi-button cbi-button-down" type="button" value="<%:Down%>" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>&dir=down'" alt="<%:Move down%>" title="<%:Move down%>" />
|
||||
<input class="cbi-button cbi-button-edit" type="button" value="<%:Edit%>" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifiedit')%>?cfg=<%=section%>'" title="<%:Edit this Uplink%>" />
|
||||
<input class="cbi-button cbi-button-remove" type="button" value="<%:Remove%>" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifidelete')%>?cfg=<%=section%>'" title="<%:Remove this Uplink%>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- end; end) -%>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-page-actions right">
|
||||
<%- uci:foreach("wireless", "wifi-device", function(s)
|
||||
local device = s[".name"]
|
||||
local hwmode = s.hwmode or "-" -%>
|
||||
<form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/wifiscan')%>" method="post">
|
||||
<input type="hidden" name="device" value="<%=device%>" />
|
||||
<input type="hidden" name="token" value="<%=token%>" />
|
||||
<input type="submit" class="cbi-button cbi-button-action important" title="<%:Find and join network on%> <%=device%>" value="<%:Scan%> <%=device%> (<%=hwmode%>)" />
|
||||
</form>
|
||||
<%- end) -%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%+footer%>
|
|
@ -1,94 +0,0 @@
|
|||
<style type="text/css">
|
||||
textarea
|
||||
{
|
||||
width: 100% !important;
|
||||
height: 450px !important;
|
||||
border: 1px solid #cccccc;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
resize: none;
|
||||
white-space: pre;
|
||||
overflow-wrap: normal;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
select[readonly],
|
||||
textarea[readonly]
|
||||
{
|
||||
width: 100% !important;
|
||||
height: 450px !important;
|
||||
border: 1px solid #cccccc;
|
||||
padding: 5px;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
resize: none;
|
||||
pointer-events: auto;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.table.cbi-section-table .th,
|
||||
.table.cbi-section-table .td,
|
||||
.cbi-section-table-cell,
|
||||
.cbi-section-table-row,
|
||||
.tr[data-title]::before
|
||||
{
|
||||
text-align: left !important;
|
||||
vertical-align: top;
|
||||
margin-left: 0px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
.table.cbi-section-table .th
|
||||
{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cbi-section-table-row > .cbi-value-field .cbi-input-select,
|
||||
.table.cbi-section-table select
|
||||
{
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.item,
|
||||
.add-item
|
||||
{
|
||||
white-space: nowrap;
|
||||
width: 8.2em;
|
||||
}
|
||||
|
||||
.cbi-input-checkbox
|
||||
{
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.cbi-button
|
||||
{
|
||||
-webkit-appearance: menulist;
|
||||
}
|
||||
|
||||
.runtime
|
||||
{
|
||||
color: #37c;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.qr-code
|
||||
{
|
||||
border-bottom: 0px;
|
||||
margin-bottom: 0px;
|
||||
padding: 0.25em 0.6em;
|
||||
text-align: left
|
||||
}
|
||||
|
||||
.button_running
|
||||
{
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
</style>
|
|
@ -1,95 +0,0 @@
|
|||
<%#
|
||||
Copyright 2017-2020 Dirk Brenken (dev@brenken.org)
|
||||
This is free software, licensed under the Apache License, Version 2.0
|
||||
-%>
|
||||
|
||||
<%-
|
||||
local sys = require("luci.sys")
|
||||
local utl = require("luci.util")
|
||||
local xml = require("luci.xml")
|
||||
local dev = luci.http.formvalue("device")
|
||||
local ifn = utl.trim(sys.exec("/bin/ubus -S call network.wireless status 2>/dev/null | jsonfilter -l1 -e '@." .. dev .. ".interfaces[@.config.mode=\"sta\"].ifname' 2>/dev/null"))
|
||||
local iw
|
||||
|
||||
if ifn ~= "" then
|
||||
iw = sys.wifi.getiwinfo(ifn)
|
||||
else
|
||||
iw = sys.wifi.getiwinfo(dev)
|
||||
end
|
||||
|
||||
if not iw then
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
|
||||
end
|
||||
|
||||
function percent_wifi_signal(info)
|
||||
local qc = info.quality or 0
|
||||
local qm = info.quality_max or 0
|
||||
if info.bssid and qc > 0 and qm > 0 then
|
||||
return math.floor((100 / qm) * qc)
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
-%>
|
||||
|
||||
<%+header%>
|
||||
|
||||
<div class="cbi-map">
|
||||
<h3><%:Wireless Scan%></h3>
|
||||
<div class="cbi-section">
|
||||
<div class="table cbi-section-table">
|
||||
<div class="tr cbi-section-table-titles">
|
||||
<div class="th left"><%:Uplink SSID%></div>
|
||||
<div class="th left"><%:Uplink BSSID%></div>
|
||||
<div class="th left"><%:Encryption%></div>
|
||||
<div class="th left"><%:Signal strength%></div>
|
||||
<div class="th center"><%:Action%></div>
|
||||
</div>
|
||||
<%- for i, net in ipairs(iw.scanlist or { }) do -%>
|
||||
<div class="tr cbi-section-table-row cbi-rowstyle-1">
|
||||
<div class="td left" style="text-align: left !important">
|
||||
<%=net.ssid and xml.pcdata(net.ssid) or "<em>%s</em>" % translate("hidden")%>
|
||||
</div>
|
||||
<div class="td left" style="text-align: left !important">
|
||||
<%=net.bssid and xml.pcdata(net.bssid)%>
|
||||
</div>
|
||||
<div class="td left" style="text-align: left !important">
|
||||
<%=net.encryption.description%>
|
||||
</div>
|
||||
<div class="td left" style="text-align: left !important">
|
||||
<%=percent_wifi_signal(net)%> %
|
||||
</div>
|
||||
<div class="td cbi-section-actions">
|
||||
<form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/wifiadd')%>" method="post">
|
||||
<input type="hidden" name="token" value="<%=token%>"/>
|
||||
<input type="hidden" name="device" value="<%=xml.pcdata(dev)%>"/>
|
||||
<input type="hidden" name="ssid" value="<%=xml.pcdata(net.ssid)%>"/>
|
||||
<input type="hidden" name="bssid" value="<%=xml.pcdata(net.bssid)%>"/>
|
||||
<input type="hidden" name="description" value="<%=net.encryption.description%>"/>
|
||||
<input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>"/>
|
||||
<%- if net.encryption.wpa then -%>
|
||||
<input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>"/>
|
||||
<%- for _, v in ipairs(net.encryption.auth_suites) do -%>
|
||||
<input type="hidden" name="wpa_suites" value="<%=v%>"/>
|
||||
<%- end -%>
|
||||
<%- end -%>
|
||||
<input class="cbi-button cbi-button-apply" type="submit" value="<%:Add Uplink%>"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<%- end -%>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-page-actions right">
|
||||
<form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/stations')%>" method="get">
|
||||
<input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>"/>
|
||||
</form>
|
||||
<form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/wifiscan')%>" method="post">
|
||||
<input type="hidden" name="token" value="<%=token%>"/>
|
||||
<input type="hidden" name="device" value="<%=xml.pcdata(dev)%>"/>
|
||||
<input class="cbi-button cbi-input-find" type="submit" value="<%:Repeat scan%>"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%+footer%>
|
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
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"admin/services/travelmate": {
|
||||
"title": "Travelmate",
|
||||
"order": "60",
|
||||
"action": {
|
||||
"type": "alias",
|
||||
"path": "admin/services/travelmate/overview"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-travelmate" ],
|
||||
"fs": {
|
||||
"/usr/bin/travelmate.sh": "executable",
|
||||
"/etc/init.d/travelmate": "executable"
|
||||
},
|
||||
"uci": { "travelmate": true }
|
||||
}
|
||||
},
|
||||
"admin/services/travelmate/overview": {
|
||||
"title": "Overview",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "travelmate/overview"
|
||||
}
|
||||
},
|
||||
"admin/services/travelmate/stations": {
|
||||
"title": "Wireless Stations",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "travelmate/stations"
|
||||
}
|
||||
},
|
||||
"admin/services/travelmate/logread": {
|
||||
"title": "Log View",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "travelmate/logread"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,28 @@
|
|||
{
|
||||
"luci-app-travelmate": {
|
||||
"description": "Grant UCI access for luci-app-travelmate",
|
||||
"read": {
|
||||
"description": "Grant access to LuCI app travelmate",
|
||||
"write": {
|
||||
"file": {
|
||||
"/var/run/travelmate.refresh": [ "write" ]
|
||||
},
|
||||
"uci": [ "travelmate" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "travelmate" ]
|
||||
"read": {
|
||||
"cgi-io": [ "exec" ],
|
||||
"file": {
|
||||
"/etc/travelmate/*.login": [ "list" ],
|
||||
"/var/run/travelmate.pid": [ "read" ],
|
||||
"/var/run/travelmate.refresh": [ "read" ],
|
||||
"/tmp/trm_runtime.json": [ "read" ],
|
||||
"/sbin/logread -e trm-": [ "exec" ],
|
||||
"/usr/sbin/logread -e trm-": [ "exec" ],
|
||||
"/etc/init.d/travelmate reload" : [ "exec" ],
|
||||
"/etc/init.d/travelmate restart" : [ "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" ]
|
||||
},
|
||||
"uci": [ "travelmate", "wireless" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue