'require uci';
'require form';
'require tools.widgets as widgets';
+'require uqr';
/*
button handling
*/
function handleAction(ev) {
- var ifaceValue;
+ let ifaceValue;
if (ev === 'restart') {
ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan');
return fs.exec('/etc/init.d/travelmate', ['stop'])
]),
E('div', { 'class': 'right' }, [
E('button', {
- 'class': 'btn',
+ 'class': 'cbi-button',
'click': L.hideModal
}, _('Dismiss')),
' ',
E('button', {
'class': 'cbi-button cbi-button-positive important',
'click': ui.createHandlerFn(this, function (ev) {
- var iface = document.getElementById('iface').value || 'trm_wwan',
+ let iface = document.getElementById('iface').value || 'trm_wwan',
zone = document.getElementById('zone').value || 'wan',
metric = document.getElementById('metric').value || '100';
- L.resolveDefault(fs.exec('/etc/init.d/travelmate', ['setup', iface, zone, metric]))
- .then(function (res) {
- if (res) {
- ui.addNotification(null, E('p', res.trim() + '.'), 'error');
- } else {
- ui.addNotification(null, E('p', _('The uplink interface has been updated.')), 'info');
- }
- });
- L.hideModal();
+ fs.exec('/etc/init.d/travelmate', ['setup', iface, zone, metric]).then(function (rc) {
+ L.hideModal();
+ if (rc.code == 1) {
+ ui.addNotification(null, E('p', _('Setup failed, the interface already exists!')), 'error');
+ } else {
+ location.reload();
+ }
+ });
})
}, _('Save'))
])
return Promise.all([
uci.load('wireless')
]).then(function () {
- var w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result,
+ let w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result,
w_sections = uci.sections('wireless', 'wifi-iface'),
optionsAP = [E('option', { value: '' }, [_('-- AP Selection --')])];
- for (var i = 0; i < w_sections.length; i++) {
+ for (let i = 0; i < w_sections.length; i++) {
if (w_sections[i].mode === 'ap' && w_sections[i].disabled !== '1') {
w_sid = i;
w_device = w_sections[i].device;
optionsAP.push(E('option', { value: w_sid }, w_device + ', ' + w_ssid));
}
}
- var selectAP = E('select', {
+ let selectAP = E('select', {
id: 'selectID',
class: 'cbi-input-select',
change: function (ev) {
} else {
w_enc = 'WPA';
}
- L.resolveDefault(fs.exec_direct('/usr/bin/qrencode', ['--inline', '--8bit', '--type=SVG', '--output=-', 'WIFI:S:' + w_ssid + ';T:' + w_enc + ';P:' + w_key + ';H:' + w_hidden + ';']), null).then(function (res) {
- if (res) {
- result.innerHTML = res.trim();
- }
- else {
- result.textContent = _('The QR-Code could not be generated!');
- }
- });
+ let data = `WIFI:S: ${w_ssid};T: ${w_enc};P: ${w_key};H: ${w_hidden};;`;
+ const options = {
+ pixelSize: 4,
+ whiteColor: 'white',
+ blackColor: 'black'
+ };
+ let svg = uqr.renderSVG(data, options);
+ result.innerHTML = svg.trim();
}
else {
result.textContent = '';
}),
E('div', { 'class': 'right' }, [
E('button', {
- 'class': 'btn',
+ 'class': 'cbi-button',
'click': L.hideModal
}, _('Dismiss'))
])
m = new form.Map('travelmate', 'Travelmate', _('Configuration of the travelmate package 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.'));
+ <b><em>Please note:</em></b> On first start please call the \'Interface Wizard\' once, to make the necessary network- and firewall settings.'));
/*
poll runtime information
*/
pollData: poll.add(function () {
return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) {
- var status = document.getElementById('status');
+ let status = document.getElementById('status');
if (res && res.size > 0) {
L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) {
if (res) {
- var info = JSON.parse(res);
+ let info = JSON.parse(res);
if (status && info) {
status.textContent = (info.data.travelmate_status || '-') + ' / ' + (info.data.travelmate_version || '-');
if (info.data.travelmate_status.startsWith('running')) {
status.classList.remove("spinning");
}
}
- var station_id = document.getElementById('station_id');
+ let station_id = document.getElementById('station_id');
if (station_id && info) {
station_id.textContent = info.data.station_id || '-';
}
- var station_mac = document.getElementById('station_mac');
+ let station_mac = document.getElementById('station_mac');
if (station_mac && info) {
station_mac.textContent = info.data.station_mac || '-';
}
- var station_interfaces = document.getElementById('station_interfaces');
+ let station_interfaces = document.getElementById('station_interfaces');
if (station_interfaces && info) {
station_interfaces.textContent = info.data.station_interfaces || '-';
}
- var wpa_flags = document.getElementById('wpa_flags');
- if (wpa_flags && info) {
- wpa_flags.textContent = info.data.wpa_flags || '-';
- }
- var run_flags = document.getElementById('run_flags');
+ let run_flags = document.getElementById('run_flags');
if (run_flags && info) {
run_flags.textContent = info.data.run_flags || '-';
}
- var ext_hooks = document.getElementById('ext_hooks');
+ let ext_hooks = document.getElementById('ext_hooks');
if (ext_hooks && info) {
ext_hooks.textContent = info.data.ext_hooks || '-';
}
- var run = document.getElementById('run');
+ let run = document.getElementById('run');
if (run && info) {
run.textContent = info.data.last_run || '-';
}
return E('div', { 'class': 'cbi-section' }, [
E('h3', _('Information')),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')),
- E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'color:#37c' }, '\xa0')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Status / Version')),
+ E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'margin-bottom:-5px;color:#37c;' }, '\xa0')
]),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')),
- E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'color:#37c' }, '-')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Station ID')),
+ E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station MAC')),
- E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'color:#37c' }, '-')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Station MAC')),
+ E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interfaces')),
- E('div', { 'class': 'cbi-value-field', 'id': 'station_interfaces', 'style': 'color:#37c' }, '-')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Station Interfaces')),
+ E('div', { 'class': 'cbi-value-field', 'id': 'station_interfaces', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')),
- E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'color:#37c' }, '-')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Run Flags')),
+ E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')),
- E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'color:#37c' }, '-')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Ext. Hooks')),
+ E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Ext. Hooks')),
- E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'color:#37c' }, '-')
- ]),
- E('div', { 'class': 'cbi-value' }, [
- E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')),
- E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'color:#37c' }, '-')
+ E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Last Run')),
+ E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { class: 'right' }, [
E('button', {
'class': 'cbi-button cbi-button-apply',
+ 'style': 'float:none;margin-right:.4em;',
'id': 'btn_suspend',
'click': ui.createHandlerFn(this, function () {
- L.resolveDefault(fs.stat('/usr/bin/qrencode'), null).then(function (res) {
- if (res) {
- return handleAction('qrcode');
- }
- return ui.addNotification(null, E('p', _('Please install the separate \'qrencode\' package.')), 'info');
- })
+ return handleAction('qrcode');
})
}, [_('AP QR-Codes...')]),
- '\xa0',
E('button', {
'class': 'cbi-button cbi-button-negative',
+ 'style': 'float:none;margin-right:.4em;',
'click': ui.createHandlerFn(this, function () {
return handleAction('restart');
})
}, [_('Restart Interface')]),
- '\xa0',
E('button', {
'class': 'cbi-button cbi-button-negative',
+ 'style': 'float:none;',
'click': ui.createHandlerFn(this, function () {
return handleAction('setup');
})
s.addremove = false;
s.tab('general', _('General Settings'));
s.tab('additional', _('Additional Settings'));
- s.tab('adv_email', _('E-Mail Settings'), _('Please note: E-Mail notifications require the separate setup of the <em>msmtp</em> package.<br /><p> </p>'));
+ s.tab('adv_email', _('E-Mail Settings'));
/*
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.'));
+ o = s.taboption('general', form.ListValue, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order.'));
o.value('radio0', _('use the first radio only (radio0)'));
o.value('radio1', _('use the second radio only (radio1)'));
o.value('radio0 radio1', _('use both radios, normal sort order (radio0 radio1)'));
o.value('radio1 radio0', _('use both radios, reverse sort order (radio1 radio0)'));
+ o.placeholder = _('-- default --');
+ o.optional = true;
+ o.rmempty = true;
+
+ o = s.taboption('general', form.ListValue, 'trm_scanmode', _('WLAN Scan Mode'), _('Send active probe requests or passively listen for beacon frames that are regularly sent by access points.'));
+ o.value('active', _('active'));
+ o.value('passive', _('passive'));
+ o.placeholder = _('-- default --');
+ o.optional = true;
o.rmempty = true;
o = s.taboption('general', form.Flag, 'trm_captive', _('Captive Portal Detection'), _('Check the internet availability, handle captive portal redirections and keep the uplink connection \'alive\'.'));
o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_proactive', _('ProActive Uplink Switch'), _('Proactively scan and switch to a higher prioritized uplink, despite of an already existing connection.'));
- o.default = 1;
+ o.default = 0;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_randomize', _('Randomize MAC Addresses'), _('Generate a random unicast MAC address for each uplink connection.'));
/*
additional settings tab
*/
+ o = s.taboption('additional', form.Flag, 'trm_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.'));
+ o.rmempty = false;
+
+ o = s.taboption('additional', form.ListValue, 'trm_nice', _('Service Priority'), _('The selected priority will be used for travelmate processes.'));
+ o.value('-20', _('Highest Priority'));
+ o.value('-10', _('High Priority'));
+ o.value('0', _('Normal Priority'));
+ o.value('10', _('Less Priority'));
+ o.value('19', _('Least Priority'));
+ o.placeholder = _('-- default --');
+ o.optional = true;
+ o.rmempty = true;
+
o = s.taboption('additional', form.Value, 'trm_triggerdelay', _('Trigger Delay'), _('Additional trigger delay in seconds before travelmate processing begins.'));
o.placeholder = '2';
o.datatype = 'range(1,60)';
o.value('http://captive.apple.com', 'Apple');
o.value('http://connectivitycheck.android.com/generate_204', 'Google');
o.value('http://www.msftncsi.com/ncsi.txt', 'Microsoft');
+ o.placeholder = _('-- default --');
o.optional = true;
o.rmempty = true;
o = s.taboption('additional', form.ListValue, 'trm_useragent', _('User Agent'), _('The selected user agent will be used for connectivity- and captive portal checks.'));
- o.value('Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0', 'Firefox (default)');
- o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Chromium');
- o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Safari');
- o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61', 'Edge');
- o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 OPR/103.0.0.0', 'Opera');
- o.optional = true;
- o.rmempty = true;
-
- o = s.taboption('additional', form.ListValue, 'trm_nice', _('Service Priority'), _('The selected priority will be used for travelmate processes.'));
- o.value('-20', 'Highest Priority');
- o.value('-10', 'High Priority');
- o.value('0', 'Normal Priority (default)');
- o.value('10', 'Less Priority');
- o.value('19', 'Least Priority');
+ o.value('Mozilla/5.0 (X11; Linux x86_64; rv:144.0) Gecko/20100101 Firefox/144.0', 'Firefox (default)');
+ o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36', 'Chromium');
+ o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15', 'Safari');
+ o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.3537.71', 'Edge');
+ o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 OPR/122.0.0.0', 'Opera');
+ o.placeholder = _('-- default --');
o.optional = true;
o.rmempty = true;
/*
advanced email settings tab
*/
+ o = s.taboption('adv_email', form.DummyValue, '_sub');
+ o.rawhtml = true;
+ o.default = '<em style="color:#37c;font-weight:bold;">' + _('E-Mail notifications require the separate setup of the <em>msmtp</em> package.') + '</em>'
+ + '<hr style="width: 200px; height: 1px;" />'
+
o = s.taboption('adv_email', form.Flag, 'trm_mail', _('E-Mail Hook'), _('Sends notification E-Mails after every succesful uplink connect.'));
o.rmempty = false;
'require network';
'require tools.widgets as widgets';
+/*
+ Cipher helper function
+*/
+function resolveCipher(cipherRaw) {
+ const cipherMap = {
+ '2': 'TKIP',
+ '4': 'CCMP-128',
+ '6': 'BIP',
+ '8': 'GCMP-128',
+ '9': 'GCMP-256',
+ '10': 'CCMP-256',
+ '11': 'BIP-GMAC-128',
+ '12': 'BIP-GMAC-256',
+ '13': 'BIP-CMAC-256'
+ };
+ if (!cipherRaw) return "unknown";
+ if (!cipherRaw.includes(':')) return cipherRaw;
+ let id = cipherRaw.split(':').pop();
+ return cipherMap[id] || `Unknown (${cipherRaw})`;
+}
+
/*
change the status of travelmate stations
*/
function handleToggle(sid) {
- var w_device, w_ssid, w_bssid, t_sections, row, element, value, enabled;
+ let w_device, w_ssid, w_bssid, t_sections, row, element, value, enabled;
w_device = uci.get('wireless', sid, 'device');
w_ssid = uci.get('wireless', sid, 'ssid');
w_bssid = uci.get('wireless', sid, 'bssid');
t_sections = uci.sections('travelmate', 'uplink');
- for (var i = 0; i < t_sections.length; i++) {
+ for (let i = 0; i < t_sections.length; i++) {
if (t_sections[i].device === w_device && t_sections[i].ssid === w_ssid && t_sections[i].bssid === w_bssid) {
value = t_sections[i]['enabled'];
value = (value == 0 ? 1 : 0);
remove wireless and stale travelmate sections
*/
function handleRemove(sid) {
- var w_sections, t_sections, match, row;
+ let w_sections, t_sections, match, row;
uci.remove('wireless', sid);
w_sections = uci.sections('wireless', 'wifi-iface');
t_sections = uci.sections('travelmate', 'uplink');
- for (var i = 0; i < t_sections.length; i++) {
+ for (let i = 0; i < t_sections.length; i++) {
match = false;
- for (var j = 0; j < w_sections.length; j++) {
+ for (let j = 0; j < w_sections.length; j++) {
if (t_sections[i].device === w_sections[j].device && t_sections[i].ssid === w_sections[j].ssid && t_sections[i].bssid === w_sections[j].bssid) {
match = true;
break;
add missing travelmate sections
*/
function handleSectionsAdd(iface) {
- var w_sections, t_sections, match;
+ let w_sections, t_sections, match;
w_sections = uci.sections('wireless', 'wifi-iface');
t_sections = uci.sections('travelmate', 'uplink');
- for (var i = 0; i < w_sections.length; i++) {
+ for (let i = 0; i < w_sections.length; i++) {
if (w_sections[i].mode !== 'sta' || w_sections[i].network !== iface) {
continue;
}
match = false;
- for (var j = 0; j < t_sections.length; j++) {
+ for (let j = 0; j < t_sections.length; j++) {
if (w_sections[i].device === t_sections[j].device && w_sections[i].ssid === t_sections[j].ssid && w_sections[i].bssid === t_sections[j].bssid) {
match = true;
break;
}
}
if (match === false) {
- var vpn_stdservice = uci.get('travelmate', 'global', 'trm_stdvpnservice');
- var vpn_stdiface = uci.get('travelmate', 'global', 'trm_stdvpniface');
- var sid = uci.add('travelmate', 'uplink');
+ let vpn_stdservice = uci.get('travelmate', 'global', 'trm_stdvpnservice');
+ let vpn_stdiface = uci.get('travelmate', 'global', 'trm_stdvpniface');
+ let sid = uci.add('travelmate', 'uplink');
uci.set('travelmate', sid, 'enabled', '1');
uci.set('travelmate', sid, 'device', w_sections[i].device);
update travelmate sections
*/
function handleSectionsVal(action, section_id, option, value) {
- var date, oldValue, w_device, w_ssid, w_bssid, t_sections;
+ let date, oldValue, w_device, w_ssid, w_bssid, t_sections;
w_device = uci.get('wireless', section_id, 'device');
w_ssid = uci.get('wireless', section_id, 'ssid');
w_bssid = uci.get('wireless', section_id, 'bssid');
t_sections = uci.sections('travelmate', 'uplink');
- for (var i = 0; i < t_sections.length; i++) {
+ for (let i = 0; i < t_sections.length; i++) {
if (t_sections[i].device === w_device && t_sections[i].ssid === w_ssid && t_sections[i].bssid === w_bssid) {
if (action === 'get') {
return t_sections[i][option];
uci.load('wireless'),
uci.load('travelmate')
]);
- var rows, item, value;
+ let rows, item, value;
rows = document.querySelectorAll('.cbi-section-table-row[data-sid]');
- for (var i = 0; i < rows.length; i++) {
+ for (let i = 0; i < rows.length; i++) {
item = rows[i].querySelector('.cbi-value-field[data-title="Enabled"]');
value = handleSectionsVal('get', rows[i].getAttribute('data-sid'), 'enabled');
item.textContent = (value == 0 ? 'No' : 'Yes');
if (res) {
L.resolveDefault(fs.read('/tmp/trm_runtime.json'), null).then(function (res) {
if (res) {
- var info = JSON.parse(res);
+ let info = JSON.parse(res);
if (info) {
- var t_device, t_ssid, t_bssid, oldUplinkView, newUplinkView, uplinkColor,
+ let t_device, t_ssid, t_bssid, newUplinkView, uplinkColor,
uplinkId = info.data.station_id.trim().split('/'),
oldUplinkView = document.getElementsByName('uplinkStation'),
w_sections = uci.sections('wireless', 'wifi-iface'),
vpnStatus = info.data.ext_hooks.substr(13, 1);
t_device = uplinkId[0];
t_bssid = uplinkId[uplinkId.length - 1];
- for (var i = 1; i < uplinkId.length - 1; i++) {
+ for (let i = 1; i < uplinkId.length - 1; i++) {
if (!t_ssid) {
t_ssid = uplinkId[i];
}
}
else {
uplinkColor = (vpnStatus === "✔" ? 'rgb(68, 170, 68)' : 'rgb(51, 119, 204)');
- for (var i = 0; i < w_sections.length; i++) {
+ for (let i = 0; i < w_sections.length; i++) {
newUplinkView = document.getElementById('cbi-wireless-' + w_sections[i]['.name']);
if (t_device === w_sections[i].device && t_ssid === w_sections[i].ssid && t_bssid === (w_sections[i].bssid || '-')) {
if (oldUplinkView.length === 0 && newUplinkView) {
return view.extend({
load: function () {
return Promise.all([
- L.resolveDefault(fs.exec('/etc/init.d/travelmate', ['assoc']), null),
uci.load('wireless'),
uci.load('travelmate')
]);
},
render: function (result) {
- var m, s, o,
- iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan';
+ var m, s, o
+ let iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan';
m = new form.Map('wireless');
m.chain('travelmate');
s.tab('travelmate', _('Travelmate Settings'));
s.tab('vpn', _('VPN Settings'));
s.renderRowActions = function (section_id) {
- var btns;
- btns = [
+ let btns = [
E('button', {
- 'class': 'btn cbi-button drag-handle center',
+ 'class': 'btn cbi-button drag-handle right',
+ 'style': 'float:none;margin-right:.4em;',
'title': _('Drag to reorder'),
'style': 'cursor:move',
'disabled': this.map.readonly || null
}, '☰'),
E('button', {
'class': 'cbi-button cbi-button-action important',
+ 'style': 'float:none;margin-right:.4em;',
'title': _('Edit this network'),
'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id)
}, _('Edit')),
E('button', {
'class': 'cbi-button cbi-button-apply',
+ 'style': 'float:none;margin-right:.4em;',
'title': _('Enable/Disable this network'),
'click': ui.createHandlerFn(this, handleToggle, section_id)
}, _('On/Off')),
o.readonly = true;
o = s.taboption('wireless', form.ListValue, 'encryption', _('Encryption'));
- o.value('sae', _('WPA3 Pers. (SAE)'));
- o.value('sae-mixed', _('WPA2/WPA3 Pers. (CCMP)'));
- o.value('psk2', _('WPA2 Pers.'));
- o.value('psk2+ccmp', _('WPA2 Pers. (CCMP)'));
- o.value('psk2+tkip', _('WPA2 Pers. (TKIP)'));
- o.value('psk', _('WPA Pers.'));
- o.value('psk+ccmp', _('WPA Pers. (CCMP)'));
- o.value('psk+tkip', _('WPA Pers. (TKIP)'));
- o.value('psk-mixed+ccmp', _('WPA/WPA2 Pers. (CCMP)'));
- o.value('psk-mixed+tkip', _('WPA/WPA2 Pers. (TKIP)'));
- o.value('wpa3', _('WPA3 Ent. (CCMP)'));
- o.value('wpa3-mixed', _('WPA2/WPA3 Ent. (CCMP)'));
- o.value('wpa2', _('WPA2 Ent.'));
- o.value('wpa2+ccmp', _('WPA2 Ent. (CCMP)'));
- o.value('wpa2+tkip', _('WPA2 Ent. (TKIP)'));
- o.value('wpa+ccmp', _('WPA Ent. (CCMP)'));
- o.value('wpa+tkip', _('WPA Ent. (TKIP)'));
- o.value('wpa-mixed+ccmp', _('WPA/WPA2 Ent. (CCMP)'));
- o.value('wpa-mixed+tkip', _('WPA/WPA2 Ent. (TKIP)'));
- o.value('owe', _('OWE'));
- o.value('none', _('none'));
+ o.value('sae', _('WPA3 PSK (SAE)'));
+ o.value('sae-mixed', _('Mixed WPA2/WPA3 PSK (CCMP)'));
+ o.value('psk2+ccmp', _('WPA2 PSK (CCMP)'));
+ o.value('psk2+tkip', _('WPA2 PSK (TKIP)'));
+ o.value('psk+ccmp', _('WPA PSK (CCMP)'));
+ o.value('psk+tkip', _('WPA PSK (TKIP)'));
+ o.value('psk-mixed+ccmp', _('Mixed WPA/WPA2 PSK (CCMP)'));
+ o.value('psk-mixed+tkip', _('Mixed WPA/WPA2 PSK (TKIP)'));
+ o.value('wpa3', _('WPA3 802.1X'));
+ o.value('wpa3-mixed', _('Mixed WPA2/WPA3 802.1X'));
+ o.value('wpa2+ccmp', _('WPA2 802.1X (CCMP)'));
+ o.value('wpa2+tkip', _('WPA2 802.1X (TKIP)'));
+ o.value('wpa+ccmp', _('WPA 802.1X (CCMP)'));
+ o.value('wpa+tkip', _('WPA 802.1X (TKIP)'));
+ o.value('wpa-mixed+ccmp', _('Mixed WPA/WPA2 802.1X (CCMP)'));
+ o.value('wpa-mixed+tkip', _('Mixed WPA/WPA2 802.1X (TKIP)'));
+ o.value('owe', _('WPA3 OWE'));
+ o.value('none', _('Open'));
o.default = 'none';
o.textvalue = function (section_id) {
- var cfgvalue = this.map.data.get('wireless', section_id, 'encryption');
+ let cfgvalue = this.map.data.get('wireless', section_id, 'encryption');
switch (cfgvalue) {
case 'sae':
- cfgvalue = 'WPA3 Pers. (SAE)';
+ cfgvalue = 'WPA3 PSK (SAE)';
break;
case 'sae-mixed':
- cfgvalue = 'WPA2/WPA3 Pers. (CCMP)';
- break;
- case 'psk2':
- cfgvalue = 'WPA2 Pers.';
+ cfgvalue = 'Mixed WPA2/WPA3 PSK (CCMP)';
break;
case 'psk2+ccmp':
- cfgvalue = 'WPA2 Pers. (CCMP)';
+ cfgvalue = 'WPA2 PSK (CCMP)';
break;
case 'psk2+tkip':
- cfgvalue = 'WPA2 Pers. (TKIP)';
+ cfgvalue = 'WPA2 PSK (TKIP)';
+ break;
+ case 'psk+ccmp':
+ cfgvalue = 'WPA PSK (CCMP)';
break;
- case 'psk':
- cfgvalue = 'WPA Pers.';
+ case 'psk+tkip':
+ cfgvalue = 'WPA PSK (TKIP)';
break;
- case 'psk-mixed+ccmp':
- cfgvalue = 'WPA/WPA2 Pers. (CCMP)';
+ case 'psk-mixed+ccmp':
+ cfgvalue = 'Mixed WPA/WPA2 PSK (CCMP)';
break;
case 'psk-mixed+tkip':
- cfgvalue = 'WPA/WPA2 Pers. (TKIP)';
+ cfgvalue = 'Mixed WPA/WPA2 PSK (TKIP)';
break;
case 'wpa3':
- cfgvalue = 'WPA3 Ent. (CCMP)';
+ cfgvalue = 'WPA3 802.1X';
break;
case 'wpa3-mixed':
- cfgvalue = 'WPA2/WPA3 Ent. (CCMP)';
- break;
- case 'wpa2':
- cfgvalue = 'WPA2 Ent.';
+ cfgvalue = 'Mixed WPA2/WPA3 802.1X';
break;
case 'wpa2+ccmp':
- cfgvalue = 'WPA2 Ent. (CCMP)';
+ cfgvalue = 'WPA2 802.1X (CCMP)';
break;
case 'wpa2+tkip':
- cfgvalue = 'WPA2 Ent. (TKIP)';
+ cfgvalue = 'WPA2 802.1X (TKIP)';
break;
case 'wpa+ccmp':
- cfgvalue = 'WPA Ent. (CCMP)';
+ cfgvalue = 'WPA 802.1X (CCMP)';
break;
case 'wpa+tkip':
- cfgvalue = 'WPA Ent. (TKIP)';
+ cfgvalue = 'WPA 802.1X (TKIP)';
break;
case 'wpa-mixed+ccmp':
- cfgvalue = 'WPA/WPA2 Ent. (CCMP)';
+ cfgvalue = 'Mixed WPA/WPA2 802.1X (CCMP)';
break;
case 'wpa-mixed+tkip':
- cfgvalue = 'WPA/WPA2 Ent. (TKIP)';
+ cfgvalue = 'Mixed WPA/WPA2 802.1X (TKIP)';
break;
case 'owe':
cfgvalue = 'WPA3 OWE (CCMP)';
/*
modal travelmate tab
*/
- var mac, mac_array = [];
- if (result[0] && result[0].code === 0) {
- mac_array = result[0].stdout.trim().split('\n');
- }
-
o = s.taboption('travelmate', form.Value, '_ssid', _('SSID'));
o.modalonly = true;
o.uciconfig = 'travelmate';
o = s.taboption('travelmate', form.Value, '_macaddr', _('MAC Address'),
_('Use the specified MAC address for this uplink.'));
- for (var i = 0; i < mac_array.length; i++) {
- if (mac_array[i].match(/^\s+([0-9A-Fa-f]{2}[:]?){5}[0-9A-Fa-f]{2}/)) {
- mac = mac_array[i].slice(4).trim();
- o.value(mac);
- }
- }
o.modalonly = true;
o.uciconfig = 'travelmate';
o.ucisection = 'uplink';
o.ucisection = 'uplink';
o.ucioption = 'script';
o.renderWidget = function (section_id, option_index, cfgvalue) {
- var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, {
+ let browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, {
id: this.cbid(section_id),
name: this.cbid(section_id),
show_hidden: this.show_hidden,
s.addremove = false;
s.render = function () {
return network.getWifiDevices().then(L.bind(function (radios) {
- var radio, ifname, btns = [];
- for (var i = 0; i < radios.length; i++) {
+ let radio, ifname, btns = [];
+ for (let i = 0; i < radios.length; i++) {
radio = radios[i].sid;
if (radio) {
btns.push(E('button', {
'class': 'cbi-button cbi-button-apply',
+ 'style': 'float:none;margin-right:.4em;',
'id': radio,
'click': ui.createHandlerFn(this, 'handleScan', radio)
- }, [_('Scan on ' + radio + '...')]),
- '\xa0')
+ }, [_('Scan on ' + radio + '...')]))
}
}
return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns));
*/
s.handleScan = function (radio) {
poll.stop();
- var table = E('table', { 'class': 'table' }, [
+ let table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th col-1 middle left' }, _('Strength')),
E('th', { 'class': 'th col-1 middle left hide-xs' }, _('Channel')),
]);
cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan on \'' + radio + '\'...')));
- var md = ui.showModal(_('Wireless Scan'), [
+ let md = ui.showModal(_('Wireless Scan'), [
table,
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
+ 'style': 'float:none;margin-right:.4em;',
'click': ui.hideModal
}, _('Dismiss')),
- '\xa0',
E('button', {
'class': 'cbi-button cbi-button-positive important',
'click': L.bind(this.handleScan, this, radio)
.then(L.bind(function () {
return L.resolveDefault(fs.read('/var/run/travelmate.scan'), '')
.then(L.bind(function (res) {
- var lines, strength, channel, encryption, tbl_encryption, bssid, ssid, tbl_ssid, rows = [];
+ let lines, strength, channel, bssid, wpa, rsn, cipher, auth = [], ssid, rows = [];
if (res) {
lines = res.split('\n');
- for (var i = 0; i < lines.length; i++) {
+ for (let i = 0; i < lines.length; i++) {
if (lines[i].match(/^\s+[0-9]/)) {
- encryption = lines[i].slice(80).trim();
- if (!encryption.includes('WEP')) {
- strength = lines[i].slice(4, 7).trim();
- channel = lines[i].slice(15, 18).trim();
- bssid = lines[i].slice(60, 77).trim();
- ssid = lines[i].slice(25, 59).trim();
- if (ssid.startsWith('"')) {
- ssid = ssid.slice(1, ssid.length - 1);
- tbl_ssid = ssid;
- }
- else {
- ssid = "hidden";
- tbl_ssid = "<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 'WPA3 802.1X (CCMP)':
- encryption = 'wpa3';
- tbl_encryption = 'WPA3 Ent. (CCMP)';
- break;
- case 'mixed WPA2/WPA3 802.1X (CCMP)':
- encryption = 'wpa3-mixed';
- tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)';
- break;
- case 'WPA2 802.1X':
- encryption = 'wpa2';
- tbl_encryption = 'WPA2 Ent.';
- break;
- case 'WPA2 802.1X (CCMP)':
- encryption = 'wpa2+ccmp';
- tbl_encryption = 'WPA2 Ent. (CCMP)';
- break;
- case 'WPA3 OWE (CCMP)':
- encryption = 'owe';
- tbl_encryption = 'WPA3 OWE (CCMP)';
- break;
- case 'none':
- encryption = 'none';
- tbl_encryption = 'none';
- break;
- }
- rows.push([
- strength,
- channel,
- tbl_ssid,
- bssid,
- tbl_encryption,
- E('div', { 'class': 'right' }, E('button', {
+ strength = lines[i].slice(0,3).trim();
+ channel = lines[i].slice(3,7).trim();
+ bssid = lines[i].slice(7,25).trim();
+ rsn = lines[i].slice(26,27).trim();
+ wpa = lines[i].slice(28,29).trim();
+ cipher = lines[i].slice(29,40).trim();
+ auth = lines[i].slice(40,71).trim().split(',');
+ ssid = lines[i].slice(71).trim();
+ let encryption = 'Open';
+ let tbl_encryption = '';
+ let hasWPA = wpa === '+';
+ let hasRSN = rsn === '+';
+ let hasPSK = auth.some(a => a.includes("PSK"));
+ let hasSAE = auth.includes("SAE") || auth.some(a => a.includes("SHA-256"));
+ let has8021x = auth.some(a => a.includes("802.1X"));
+ let hasSuiteB = auth.some(a => a.includes("SUITE-B"));
+ let hasOWE = auth.includes("OWE");
+ let resCipher = resolveCipher(cipher);
+ if (cipher === '-' && !hasWPA && !hasRSN) {
+ tbl_encryption = 'Open';
+ encryption = 'none';
+ } else if (hasOWE) {
+ tbl_encryption = `WPA3 OWE (${resCipher})`;
+ encryption = 'owe';
+ } else if (hasSuiteB) {
+ tbl_encryption = `WPA3 Enterprise (${resCipher})`;
+ encryption = 'wpa3';
+ } else if (hasSAE && hasPSK && !has8021x) {
+ tbl_encryption = `Mixed WPA2/WPA3 PSK (${resCipher})`;
+ encryption = 'sae-mixed';
+ } else if (hasSAE && has8021x) {
+ tbl_encryption = `Mixed WPA2/WPA3 802.1X (${resCipher})`;
+ encryption = 'wpa3-mixed';
+ } else if (hasSAE && !hasPSK && !has8021x) {
+ tbl_encryption = `WPA3 PSK (${resCipher})`;
+ encryption = 'sae';
+ } else if (hasSAE && !hasPSK && has8021x) {
+ tbl_encryption = `WPA3 802.1X (${resCipher})`;
+ encryption = 'wpa3';
+ } else if (has8021x && hasRSN && hasWPA) {
+ tbl_encryption = `Mixed WPA/WPA2 802.1X (${resCipher})`;
+ encryption = (resCipher === 'CCMP') ? 'wpa-mixed+ccmp' : 'wpa-mixed+tkip';
+ } else if (has8021x && hasRSN) {
+ tbl_encryption = `WPA2 802.1X (${resCipher})`;
+ encryption = (resCipher === 'CCMP' || resCipher === 'GCMP-256') ? 'wpa2+ccmp' : 'wpa2+tkip';
+ } else if (has8021x) {
+ tbl_encryption = `WPA 802.1X (${resCipher})`;
+ encryption = (resCipher === 'CCMP') ? 'wpa+ccmp' : 'wpa+tkip';
+ } else if (hasPSK && hasRSN && hasWPA) {
+ tbl_encryption = `Mixed WPA/WPA2 PSK (${resCipher})`;
+ encryption = (resCipher === 'CCMP') ? 'psk-mixed+ccmp' : 'psk-mixed+tkip';
+ } else if (hasPSK && hasRSN) {
+ tbl_encryption = `WPA2 PSK (${resCipher})`;
+ encryption = (resCipher === 'CCMP' || resCipher === 'GCMP-256') ? 'psk2+ccmp' : 'psk2+tkip';
+ } else if (hasPSK && hasWPA) {
+ tbl_encryption = `WPA PSK (${resCipher})`;
+ encryption = (resCipher === 'CCMP') ? 'psk+ccmp' : 'psk+tkip';
+ } else {
+ tbl_encryption = 'Unknown';
+ encryption = 'none';
+ }
+ rows.push([
+ strength,
+ channel,
+ ssid,
+ bssid,
+ tbl_encryption,
+ E('div', { 'class': 'right' },
+ E('button', {
'class': 'cbi-button cbi-button-action',
'click': ui.createHandlerFn(this, 'handleAdd', radio, iface, ssid, bssid, encryption)
}, _('Add Uplink...')))
]);
- }
}
}
}
o2.default = bssid;
o2 = s2.option(form.ListValue, 'encryption', _('Encryption'));
- o2.value('sae', _('WPA3 Pers. (SAE)'));
- o2.value('sae-mixed', _('WPA2/WPA3 Pers. (CCMP)'));
- o2.value('psk2', _('WPA2 Pers.'));
- o2.value('psk2+ccmp', _('WPA2 Pers. (CCMP)'));
- o2.value('psk2+tkip', _('WPA2 Pers. (TKIP)'));
- o2.value('psk', _('WPA Pers.'));
- o2.value('psk+ccmp', _('WPA Pers. (CCMP)'));
- o2.value('psk+tkip', _('WPA Pers. (TKIP)'));
- o2.value('psk-mixed+ccmp', _('WPA/WPA2 Pers. (CCMP)'));
- o2.value('psk-mixed+tkip', _('WPA/WPA2 Pers. (TKIP)'));
- o2.value('wpa3', _('WPA3 Ent.'));
- o2.value('wpa3-mixed', _('WPA2/WPA3 Ent.'));
- o2.value('wpa2', _('WPA2 Ent.'));
- o2.value('wpa2+ccmp', _('WPA2 Ent. (CCMP)'));
- o2.value('wpa2+tkip', _('WPA2 Ent. (TKIP)'));
- o2.value('wpa+ccmp', _('WPA Ent. (CCMP)'));
- o2.value('wpa+tkip', _('WPA Ent. (TKIP)'));
- o2.value('wpa-mixed+ccmp', _('WPA/WPA2 Ent. (CCMP)'));
- o2.value('wpa-mixed+tkip', _('WPA/WPA2 Ent. (TKIP)'));
- o2.value('owe', _('WPA3 OWE (CCMP)'));
- o2.value('none', _('none'));
+ o2.value('sae', _('WPA3 PSK (SAE)'));
+ o2.value('sae-mixed', _('Mixed WPA2/WPA3 PSK (CCMP)'));
+ o2.value('psk2+ccmp', _('WPA2 PSK (CCMP)'));
+ o2.value('psk2+tkip', _('WPA2 PSK (TKIP)'));
+ o2.value('psk+ccmp', _('WPA PSK (CCMP)'));
+ o2.value('psk+tkip', _('WPA PSK (TKIP)'));
+ o2.value('psk-mixed+ccmp', _('Mixed WPA/WPA2 PSK (CCMP)'));
+ o2.value('psk-mixed+tkip', _('Mixed WPA/WPA2 PSK (TKIP)'));
+ o2.value('wpa3', _('WPA3 802.1X'));
+ o2.value('wpa3-mixed', _('Mixed WPA2/WPA3 802.1X'));
+ o2.value('wpa2+ccmp', _('WPA2 802.1X (CCMP)'));
+ o2.value('wpa2+tkip', _('WPA2 802.1X (TKIP)'));
+ o2.value('wpa+ccmp', _('WPA 802.1X (CCMP)'));
+ o2.value('wpa+tkip', _('WPA 802.1X (TKIP)'));
+ o2.value('wpa-mixed+ccmp', _('Mixed WPA/WPA2 802.1X (CCMP)'));
+ o2.value('wpa-mixed+tkip', _('Mixed WPA/WPA2 802.1X (TKIP)'));
+ o2.value('owe', _('WPA3 OWE'));
+ o2.value('none', _('Open'));
o2.default = encryption;
o2 = s2.option(form.Value, 'key', _('Password'));
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
+ 'style': 'float:none;margin-right:.4em;',
'click': ui.hideModal
}, _('Dismiss')),
- '\xa0',
E('button', {
'class': 'cbi-button cbi-button-positive important',
'click': ui.createHandlerFn(this, 'handleCommit', m2)
}
return ui.hideModal();
}
- for (var i = 0; i < w_sections.length; i++) {
+ for (let i = 0; i < w_sections.length; i++) {
if (w_sections[i].device === device && w_sections[i].ssid === ssid) {
if (ignore_bssid === '1' || (ignore_bssid === '0' && w_sections[i].bssid === bssid)) {
ui.addNotification(null, E('p', 'Duplicate wireless entry, the uplink station could not be saved.'), 'error');
.then(L.bind(this.map.load, this.map))
.then(L.bind(this.map.reset, this.map))
.then(function () {
- var row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(new_sid));
+ let row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(new_sid));
row.setAttribute('style', 'opacity: 0.5; color: #4a4 !important;');
})
.then(ui.hideModal)