luci-app-travelmate: release 2.4.5-1

* sync with base package

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken
2026-05-09 21:42:22 +02:00
parent 39e643f711
commit c346174ed1
5 changed files with 171 additions and 163 deletions
+2 -2
View File
@@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for Travelmate
LUCI_DEPENDS:=+luci-base +luci-lib-uqr +travelmate
PKG_VERSION:=2.4.0
PKG_RELEASE:=2
PKG_VERSION:=2.4.5
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
@@ -12,37 +12,29 @@ function Logview(logtag, name) {
return L.view.extend({
load: () => Promise.resolve(),
render: () => {
L.Poll.add(() => {
render: function () {
const pollFn = () => {
return callLogRead(1000, false, true).then(res => {
const logEl = document.getElementById('logfile');
if (!logEl) return;
const filtered = (res?.log ?? [])
.filter(entry => !logtag || entry.msg.includes(logtag))
.map(entry => {
const d = new Date(entry.time);
const date = d.toLocaleDateString([], {
year: 'numeric',
month: '2-digit',
day: '2-digit'
.filter(entry => !logtag || entry.msg.includes(logtag))
.map(entry => {
const d = new Date(entry.time);
const pad = n => String(n).padStart(2, '0');
const date = `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${d.getFullYear()}`;
const time = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
return `[${date}-${time}] ${entry.msg}`;
});
const time = d.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
return `[${date}-${time}] ${entry.msg}`;
});
if (filtered.length > 0) {
logEl.value = filtered.join('\n');
} else {
logEl.value = _('No %s related logs yet!').format(name);
}
logEl.value = filtered.length > 0
? filtered.join('\n')
: _('No %s related logs yet!').format(name);
logEl.scrollTop = logEl.scrollHeight;
});
});
};
this._pollFn = pollFn;
L.Poll.add(pollFn);
return E('div', { class: 'cbi-map' }, [
E('div', { class: 'cbi-section' }, [
@@ -58,6 +50,13 @@ function Logview(logtag, name) {
]);
},
unload: function () {
if (this._pollFn) {
L.Poll.remove(this._pollFn);
this._pollFn = null;
}
},
handleSaveApply: null,
handleSave: null,
handleReset: null
@@ -192,50 +192,78 @@ return view.extend({
/*
poll runtime information
*/
let parseErrCount = 0;
poll.add(function () {
return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) {
const status = document.getElementById('status');
if (res && res.size > 0) {
L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) {
if (res) {
let info = JSON.parse(res);
if (status && info) {
status.textContent = `${info.data.travelmate_status || '-'} (frontend: ${info.data.frontend_ver || '-'} / backend: ${info.data.backend_ver || '-'})`;
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");
}
}
if (info) {
setText('station_id', info.data.station_id);
setText('station_mac', info.data.station_mac);
setText('station_interfaces', info.data.station_interfaces);
setText('station_subnet', info.data.station_subnet);
setText('run_flags', info.data.run_flags);
setText('ext_hooks', info.data.ext_hooks);
setText('run', info.data.last_run);
setText('sys', info.data.system);
return L.resolveDefault(fs.stat('/var/run/travelmate/travelmate.runtime.json'), null).then(function (res) {
if (!res) {
return;
}
return L.resolveDefault(fs.read_direct('/var/run/travelmate/travelmate.runtime.json'), null).then(function (res) {
const status = document.getElementById('status');
const buttons = document.querySelectorAll('.cbi-page-actions button');
let info = null;
try {
info = JSON.parse(res);
parseErrCount = 0;
if (!poll.active()) {
poll.start();
}
} catch (e) {
info = null;
parseErrCount++;
if (status) {
status.textContent = '-';
buttons.forEach(function (btn) {
btn.disabled = false;
});
status.classList.remove('spinning');
if (parseErrCount >= 5) {
ui.addNotification(null, E('p', _('Unable to parse the travelmate runtime information!')), 'error');
poll.stop();
}
}
});
} else if (status) {
status.textContent = '-';
if (status.classList.contains("spinning")) {
status.classList.remove("spinning");
return;
}
}
if (status && info) {
status.textContent = `${info.data.travelmate_status || '-'} (frontend: ${info.data.frontend_ver || '-'} / backend: ${info.data.backend_ver || '-'})`;
if (info.data.travelmate_status === 'processing') {
buttons.forEach(function (btn) {
btn.disabled = true;
btn.blur();
});
if (!status.classList.contains("spinning")) {
status.classList.add("spinning");
}
} else {
if (status.classList.contains("spinning")) {
status.classList.remove("spinning");
}
buttons.forEach(function (btn) {
btn.disabled = false;
});
}
} else if (status) {
status.textContent = '-';
if (status.classList.contains("spinning")) {
status.classList.remove("spinning");
}
buttons.forEach(function (btn) {
btn.disabled = false;
});
}
if (info) {
setText('station_id', info.data.station_id);
setText('station_mac', info.data.station_mac);
setText('station_interfaces', info.data.station_interfaces);
setText('station_subnet', info.data.station_subnet);
setText('run_flags', info.data.run_flags);
setText('ext_hooks', info.data.ext_hooks);
setText('run', info.data.last_run);
setText('sys', info.data.system);
}
});
});
}, 1);
}, 2);
/*
runtime information and buttons
@@ -357,6 +385,10 @@ return view.extend({
o.default = 0;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_eviltwin', _('Evil Twin Protection'), _('Detect and skip access points with locally administered (LAA) BSSIDs to mitigate evil twin attacks.'));
o.default = 0;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'trm_autoadd', _('AutoAdd Open Uplinks'), _('Automatically add open uplinks like hotel captive portals to your wireless config.'));
o.default = 0;
o.rmempty = false;
@@ -400,9 +432,9 @@ return view.extend({
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 = s.taboption('additional', form.Value, 'trm_maxretry', _('Connection Limit'), _('Retry limit to connect to an uplink. Use \'0\' for unlimited retries.'));
o.placeholder = '3';
o.datatype = 'range(1,10)';
o.datatype = 'range(0,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.'));
@@ -121,8 +121,6 @@ function handleSectionsAdd(iface) {
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');
if (vpn_stdservice && vpn_stdiface) {
uci.set('travelmate', sid, 'vpn', '1');
uci.set('travelmate', sid, 'vpnservice', vpn_stdservice);
@@ -136,7 +134,7 @@ function handleSectionsAdd(iface) {
update travelmate sections
*/
function handleSectionsVal(action, section_id, option, value) {
let date, oldValue, w_device, w_ssid, w_bssid, t_sections;
let w_device, w_ssid, w_bssid, t_sections;
w_device = uci.get('wireless', section_id, 'device');
w_ssid = uci.get('wireless', section_id, 'ssid');
@@ -148,15 +146,6 @@ function handleSectionsVal(action, section_id, option, value) {
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().substring(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);
@@ -169,11 +158,12 @@ function handleSectionsVal(action, section_id, option, value) {
update travelmate status
*/
function handleStatus() {
let parseErrCount = 0;
poll.add(function () {
L.resolveDefault(fs.stat('/var/state/travelmate.refresh'), null).then(function (res) {
L.resolveDefault(fs.stat('/var/run/travelmate/travelmate.refresh'), null).then(function (res) {
if (res) {
return L.resolveDefault(fs.read_direct('/var/state/travelmate.refresh'), null).then(async function (res) {
fs.remove('/var/state/travelmate.refresh');
return L.resolveDefault(fs.read_direct('/var/run/travelmate/travelmate.refresh'), null).then(async function (res) {
fs.remove('/var/run/travelmate/travelmate.refresh');
if (res && res === 'ui_reload') {
location.reload();
} else if (res && res === 'cfg_reload') {
@@ -196,17 +186,29 @@ function handleStatus() {
});
}
});
return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) {
return L.resolveDefault(fs.stat('/var/run/travelmate/travelmate.runtime.json'), null).then(function (res) {
if (res) {
return L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) {
return L.resolveDefault(fs.read_direct('/var/run/travelmate/travelmate.runtime.json'), null).then(function (res) {
if (res) {
let info = JSON.parse(res);
let info = null;
try {
info = JSON.parse(res);
parseErrCount = 0;
} catch (e) {
parseErrCount++;
if (parseErrCount >= 5) {
ui.addNotification(null, E('p', _('Unable to parse the travelmate runtime information!')), 'error');
poll.stop();
}
return;
}
if (info) {
const vpnMatch = (info.data.ext_hooks || '').match(/vpn:\s*(.)/);
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);
vpnStatus = vpnMatch ? vpnMatch[1] : '✘';
t_device = uplinkId[0];
t_bssid = uplinkId[uplinkId.length - 1];
for (let i = 1; i < uplinkId.length - 1; i++) {
@@ -552,28 +554,6 @@ return view.extend({
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.Flag, '_opensta', _('Auto Added Open Uplink'),
_('This option is selected by default if this uplink was added automatically and counts as \'Open Uplink\'.'));
o.rmempty = true;
@@ -618,42 +598,6 @@ return view.extend({
return handleSectionsVal('set', section_id, 'macaddr', value);
}
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';
@@ -823,7 +767,7 @@ return view.extend({
return L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['scan', radio]))
.then(L.bind(function () {
return L.resolveDefault(fs.read_direct('/var/run/travelmate.scan'), '')
return L.resolveDefault(fs.read_direct('/var/run/travelmate/travelmate.scan'), '')
.then(L.bind(function (res) {
let lines, strength, channel, bssid, wpa, cipher, auth, tbl_ssid, ssid, rows = [];
@@ -1213,4 +1157,4 @@ return view.extend({
return m.render();
},
handleReset: null
});
});
@@ -3,27 +3,60 @@
"description": "Grant access to LuCI app travelmate",
"write": {
"file": {
"/var/state/travelmate.refresh": [ "write" ]
"/var/run/travelmate/travelmate.refresh": [
"write"
]
},
"uci": [ "travelmate" ]
"uci": [
"travelmate"
]
},
"read": {
"cgi-io": [ "exec" ],
"cgi-io": [
"exec"
],
"file": {
"/etc/travelmate/*.login": [ "list" ],
"/var/run/travelmate.pid": [ "read" ],
"/var/run/travelmate.scan": [ "read" ],
"/var/state/travelmate.refresh": [ "read" ],
"/tmp/trm_runtime.json": [ "read" ],
"/sbin/ifup *": [ "exec" ],
"/etc/init.d/travelmate start" : [ "exec" ],
"/etc/init.d/travelmate restart" : [ "exec" ],
"/etc/init.d/travelmate stop" : [ "exec" ],
"/etc/init.d/travelmate setup [0-9a-z_]* [0-9a-z_]* [0-9]*" : [ "exec" ],
"/etc/init.d/travelmate scan radio[0-9]" : [ "exec" ]
"/etc/travelmate/*.login": [
"list"
],
"/var/run/travelmate/travelmate.pid": [
"read"
],
"/var/run/travelmate/travelmate.scan": [
"read"
],
"/var/run/travelmate/travelmate.refresh": [
"read"
],
"/var/run/travelmate/travelmate.runtime.json": [
"read"
],
"/sbin/ifup *": [
"exec"
],
"/etc/init.d/travelmate start": [
"exec"
],
"/etc/init.d/travelmate restart": [
"exec"
],
"/etc/init.d/travelmate stop": [
"exec"
],
"/etc/init.d/travelmate setup *": [
"exec"
],
"/etc/init.d/travelmate scan *": [
"exec"
]
},
"uci": [ "travelmate", "wireless" ],
"log": [ "read" ]
"uci": [
"travelmate",
"wireless"
],
"log": [
"read"
]
}
}
}
}