9 'require tools.widgets as widgets';
12 change the status of travelmate stations
14 function handleToggle(sid
) {
15 var w_device
, w_ssid
, w_bssid
, t_sections
, row
, element
, value
, enabled
;
17 w_device
= uci
.get('wireless', sid
, 'device');
18 w_ssid
= uci
.get('wireless', sid
, 'ssid');
19 w_bssid
= uci
.get('wireless', sid
, 'bssid');
20 t_sections
= uci
.sections('travelmate', 'uplink');
22 for (var i
= 0; i
< t_sections
.length
; i
++) {
23 if (t_sections
[i
].device
=== w_device
&& t_sections
[i
].ssid
=== w_ssid
&& t_sections
[i
].bssid
=== w_bssid
) {
24 value
= t_sections
[i
]['enabled'];
25 value
= (value
== 0 ? 1 : 0);
26 enabled
= (value
== 0 ? 'No' : 'Yes');
27 uci
.set('travelmate', t_sections
[i
]['.name'], 'enabled', value
);
28 uci
.save().then(function () {
29 row
= document
.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid
));
30 element
= row
.querySelector('.cbi-value-field');
31 element
.textContent
= enabled
;
32 row
.setAttribute('style', 'opacity: 0.5; color: #37c !important;');
39 remove wireless and stale travelmate sections
41 function handleRemove(sid
) {
42 var w_sections
, t_sections
, match
, row
;
44 uci
.remove('wireless', sid
);
45 w_sections
= uci
.sections('wireless', 'wifi-iface');
46 t_sections
= uci
.sections('travelmate', 'uplink');
47 for (var i
= 0; i
< t_sections
.length
; i
++) {
49 for (var j
= 0; j
< w_sections
.length
; j
++) {
50 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
) {
55 if (match
=== false) {
56 uci
.remove('travelmate', t_sections
[i
]['.name']);
59 return uci
.save().then(function () {
60 row
= document
.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid
));
61 row
.setAttribute('style', 'opacity: 0.5; color: #a22 !important;');
66 add missing travelmate sections
68 function handleSectionsAdd(iface
) {
69 var w_sections
, t_sections
, match
;
71 w_sections
= uci
.sections('wireless', 'wifi-iface');
72 t_sections
= uci
.sections('travelmate', 'uplink');
73 for (var i
= 0; i
< w_sections
.length
; i
++) {
74 if (w_sections
[i
].mode
!== 'sta' || w_sections
[i
].network
!== iface
) {
78 for (var j
= 0; j
< t_sections
.length
; j
++) {
79 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
) {
84 if (match
=== false) {
85 var sid
= uci
.add('travelmate', 'uplink');
86 uci
.set('travelmate', sid
, 'enabled', '1');
87 uci
.set('travelmate', sid
, 'device', w_sections
[i
].device
);
88 uci
.set('travelmate', sid
, 'ssid', w_sections
[i
].ssid
);
89 uci
.set('travelmate', sid
, 'bssid', w_sections
[i
].bssid
);
90 uci
.set('travelmate', sid
, 'con_start_expiry', '0');
91 uci
.set('travelmate', sid
, 'con_end_expiry', '0');
97 update travelmate sections
99 function handleSectionsVal(action
, section_id
, option
, value
) {
100 var date
, oldValue
, w_device
, w_ssid
, w_bssid
, t_sections
;
102 w_device
= uci
.get('wireless', section_id
, 'device');
103 w_ssid
= uci
.get('wireless', section_id
, 'ssid');
104 w_bssid
= uci
.get('wireless', section_id
, 'bssid');
105 t_sections
= uci
.sections('travelmate', 'uplink');
107 for (var i
= 0; i
< t_sections
.length
; i
++) {
108 if (t_sections
[i
].device
=== w_device
&& t_sections
[i
].ssid
=== w_ssid
&& t_sections
[i
].bssid
=== w_bssid
) {
109 if (action
=== 'get') {
110 return t_sections
[i
][option
];
112 else if (action
=== 'set') {
113 if (option
=== 'enabled') {
114 oldValue
= t_sections
[i
][option
];
115 if (oldValue
!== value
&& value
=== '0') {
116 date
= new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60 * 1000).toISOString().substr(0, 19).replace(/-/g
, '.').replace('T', '-');
117 uci
.set('travelmate', t_sections
[i
]['.name'], 'con_end', date
);
119 else if (oldValue
!== value
&& value
=== '1') {
120 uci
.unset('travelmate', t_sections
[i
]['.name'], 'con_end');
123 return uci
.set('travelmate', t_sections
[i
]['.name'], option
, value
);
125 else if (action
=== 'del') {
126 return uci
.unset('travelmate', t_sections
[i
]['.name'], option
);
133 update travelmate status
135 function handleStatus() {
136 poll
.add(function () {
137 L
.resolveDefault(fs
.stat('/var/state/travelmate.refresh'), null).then(function (res
) {
139 L
.resolveDefault(fs
.read_direct('/var/state/travelmate.refresh'), null).then(async
function (res
) {
140 fs
.remove('/var/state/travelmate.refresh');
141 if (res
&& res
=== 'ui_reload') {
144 else if (res
&& res
=== 'cfg_reload') {
145 if (document
.readyState
=== 'complete') {
146 uci
.unload('wireless');
147 uci
.unload('travelmate');
150 uci
.load('wireless'),
151 uci
.load('travelmate')
153 var rows
, item
, value
;
154 rows
= document
.querySelectorAll('.cbi-section-table-row[data-sid]');
155 for (var i
= 0; i
< rows
.length
; i
++) {
156 item
= rows
[i
].querySelector('.cbi-value-field[data-title="Enabled"]');
157 value
= handleSectionsVal('get', rows
[i
].getAttribute('data-sid'), 'enabled');
158 item
.textContent
= (value
== 0 ? 'No' : 'Yes');
164 return L
.resolveDefault(fs
.stat('/tmp/trm_runtime.json'), null).then(function (res
) {
166 L
.resolveDefault(fs
.read_direct('/tmp/trm_runtime.json'), null).then(function (res
) {
168 var info
= JSON
.parse(res
);
170 var t_device
, t_ssid
, t_bssid
, oldUplinkView
, newUplinkView
, uplinkColor
,
171 uplinkId
= info
.data
.station_id
.trim().split('/'),
172 oldUplinkView
= document
.getElementsByName('uplinkStation'),
173 w_sections
= uci
.sections('wireless', 'wifi-iface'),
174 vpnStatus
= info
.data
.ext_hooks
.substr(13, 1);
175 t_device
= uplinkId
[0];
176 t_bssid
= uplinkId
[uplinkId
.length
- 1];
177 for (var i
= 1; i
< uplinkId
.length
- 1; i
++) {
179 t_ssid
= uplinkId
[i
];
182 t_ssid
= t_ssid
+ '/' + uplinkId
[i
];
185 if (t_ssid
=== '-') {
186 if (oldUplinkView
.length
> 0) {
187 oldUplinkView
[0].removeAttribute('style');
188 oldUplinkView
[0].removeAttribute('name', 'uplinkStation');
192 uplinkColor
= (vpnStatus
=== "✔" ? 'rgb(68, 170, 68)' : 'rgb(51, 119, 204)');
193 for (var i
= 0; i
< w_sections
.length
; i
++) {
194 newUplinkView
= document
.getElementById('cbi-wireless-' + w_sections
[i
]['.name']);
195 if (t_device
=== w_sections
[i
].device
&& t_ssid
=== w_sections
[i
].ssid
&& t_bssid
=== (w_sections
[i
].bssid
|| '-')) {
196 if (oldUplinkView
.length
=== 0 && newUplinkView
) {
197 newUplinkView
.setAttribute('name', 'uplinkStation');
198 newUplinkView
.setAttribute('style', 'text-align: left !important; color: ' + uplinkColor
+ ' !important;font-weight: bold !important;');
200 else if (oldUplinkView
.length
> 0 && newUplinkView
&& oldUplinkView
[0].getAttribute('id') !== newUplinkView
.getAttribute('id')) {
201 oldUplinkView
[0].removeAttribute('style');
202 oldUplinkView
[0].removeAttribute('name', 'uplinkStation');
203 newUplinkView
.setAttribute('name', 'uplinkStation');
204 newUplinkView
.setAttribute('style', 'text-align: left !important; color: ' + uplinkColor
+ ' !important;font-weight: bold !important;');
206 else if (newUplinkView
&& newUplinkView
.style
.color
!= uplinkColor
) {
207 newUplinkView
.setAttribute('style', 'text-align: left !important; color: ' + uplinkColor
+ ' !important;font-weight: bold !important;');
223 L
.resolveDefault(fs
.exec_direct('/etc/init.d/travelmate', ['assoc']), {}),
224 uci
.load('wireless'),
225 uci
.load('travelmate')
229 render: function (result
) {
231 iface
= uci
.get('travelmate', 'global', 'trm_iface') || 'trm_wwan';
233 m
= new form
.Map('wireless');
234 m
.chain('travelmate');
235 s
= m
.section(form
.GridSection
, 'wifi-iface', null, _('Overview of all configured uplinks for travelmate. \
236 You can edit, remove or prioritize existing uplinks by drag \& drop and scan for new ones.<br /> \
237 The currently used uplink connection is emphasized in <span style="color:rgb(51, 119, 204);font-weight:bold">blue</span>, \
238 an encrypted VPN uplink connection is emphasized in <span style="color:rgb(68, 170, 68);font-weight:bold">green</span>.'));
241 s
.filter = function (section_id
) {
242 return (uci
.get('wireless', section_id
, 'network') == iface
&& uci
.get('wireless', section_id
, 'mode') == 'sta');
244 s
.tab('wireless', _('Wireless Settings'));
245 s
.tab('travelmate', _('Travelmate Settings'));
246 s
.tab('vpn', _('VPN Settings'));
247 s
.renderRowActions = function (section_id
) {
251 'class': 'btn cbi-button drag-handle center',
252 'title': _('Drag to reorder'),
253 'style': 'cursor:move',
254 'disabled': this.map
.readonly
|| null
257 'class': 'cbi-button cbi-button-action important',
258 'title': _('Edit this network'),
259 'click': ui
.createHandlerFn(this, 'renderMoreOptionsModal', section_id
)
262 'class': 'cbi-button cbi-button-apply',
263 'title': _('Enable/Disable this network'),
264 'click': ui
.createHandlerFn(this, handleToggle
, section_id
)
267 'class': 'cbi-button cbi-button-negative remove',
268 'title': _('Remove this network'),
269 'click': ui
.createHandlerFn(this, handleRemove
, section_id
)
272 return E('td', { 'class': 'td middle cbi-section-actions' }, E('div', btns
));
275 o
= s
.taboption('travelmate', form
.Flag
, '_enabled', _('Enabled'));
276 o
.uciconfig
= 'travelmate';
277 o
.ucisection
= 'uplink';
278 o
.ucioption
= 'enabled';
280 o
.cfgvalue = function (section_id
) {
281 return handleSectionsVal('get', section_id
, 'enabled');
283 o
.write = function (section_id
, value
) {
284 return handleSectionsVal('set', section_id
, 'enabled', value
);
287 o
= s
.taboption('wireless', form
.Value
, 'device', _('Device'));
290 o
= s
.taboption('wireless', form
.Value
, 'ssid', _('SSID'));
291 o
.datatype
= 'maxlength(32)';
294 o
= s
.taboption('wireless', form
.Value
, 'bssid', _('BSSID'));
295 o
.datatype
= 'macaddr';
298 o
= s
.taboption('wireless', form
.ListValue
, 'encryption', _('Encryption'));
299 o
.value('sae', _('WPA3 Pers. (SAE)'));
300 o
.value('sae-mixed', _('WPA2/WPA3 Pers. (CCMP)'));
301 o
.value('psk2', _('WPA2 Pers.'));
302 o
.value('psk2+ccmp', _('WPA2 Pers. (CCMP)'));
303 o
.value('psk2+tkip', _('WPA2 Pers. (TKIP)'));
304 o
.value('psk', _('WPA Pers.'));
305 o
.value('psk+ccmp', _('WPA Pers. (CCMP)'));
306 o
.value('psk+tkip', _('WPA Pers. (TKIP)'));
307 o
.value('psk-mixed+ccmp', _('WPA/WPA2 Pers. (CCMP)'));
308 o
.value('psk-mixed+tkip', _('WPA/WPA2 Pers. (TKIP)'));
309 o
.value('wpa3', _('WPA3 Ent. (CCMP)'));
310 o
.value('wpa3-mixed', _('WPA2/WPA3 Ent. (CCMP)'));
311 o
.value('wpa2', _('WPA2 Ent.'));
312 o
.value('wpa2+ccmp', _('WPA2 Ent. (CCMP)'));
313 o
.value('wpa2+tkip', _('WPA2 Ent. (TKIP)'));
314 o
.value('wpa+ccmp', _('WPA Ent. (CCMP)'));
315 o
.value('wpa+tkip', _('WPA Ent. (TKIP)'));
316 o
.value('wpa-mixed+ccmp', _('WPA/WPA2 Ent. (CCMP)'));
317 o
.value('wpa-mixed+tkip', _('WPA/WPA2 Ent. (TKIP)'));
318 o
.value('owe', _('OWE'));
319 o
.value('none', _('none'));
321 o
.textvalue = function (section_id
) {
322 var cfgvalue
= this.map
.data
.get('wireless', section_id
, 'encryption');
325 cfgvalue
= 'WPA3 Pers. (SAE)';
328 cfgvalue
= 'WPA2/WPA3 Pers. (CCMP)';
331 cfgvalue
= 'WPA2 Pers.';
334 cfgvalue
= 'WPA2 Pers. (CCMP)';
337 cfgvalue
= 'WPA2 Ent. (TKIP)';
340 cfgvalue
= 'WPA Pers.';
342 case 'psk-mixed+ccmp':
343 cfgvalue
= 'WPA/WPA2 Pers. (CCMP)';
345 case 'psk-mixed+tkip':
346 cfgvalue
= 'WPA/WPA2 Pers. (TKIP)';
349 cfgvalue
= 'WPA3 Ent. (CCMP)';
352 cfgvalue
= 'WPA2/WPA3 Ent. (CCMP)';
355 cfgvalue
= 'WPA2 Ent.';
358 cfgvalue
= 'WPA2 Ent. (CCMP)';
361 cfgvalue
= 'WPA2 Ent. (TKIP)';
364 cfgvalue
= 'WPA Ent. (CCMP)';
367 cfgvalue
= 'WPA Ent. (TKIP)';
369 case 'wpa-mixed+ccmp':
370 cfgvalue
= 'WPA/WPA2 Ent. (CCMP)';
372 case 'wpa-mixed+tkip':
373 cfgvalue
= 'WPA/WPA2 Ent. (TKIP)';
376 cfgvalue
= 'WPA3 OWE (CCMP)';
389 o
= s
.taboption('wireless', form
.Value
, 'key', _('Password'));
390 o
.datatype
= 'wpakey';
391 o
.depends({ encryption
: 'sae', '!contains': true });
392 o
.depends({ encryption
: 'psk', '!contains': true });
396 o
= s
.taboption('wireless', form
.Value
, 'password', _('Password'));
397 o
.datatype
= 'wpakey';
398 o
.depends({ encryption
: 'wpa', '!contains': true });
402 o
= s
.taboption('wireless', form
.ListValue
, 'eap_type', _('EAP-Method'));
403 o
.depends({ encryption
: 'wpa', '!contains': true });
404 o
.value('tls', _('TLS'));
405 o
.value('ttls', _('TTLS'));
406 o
.value('peap', _('PEAP'));
407 o
.value('fast', _('FAST'));
411 o
= s
.taboption('wireless', form
.ListValue
, 'auth', _('Authentication'));
412 o
.value('PAP', _('PAP'));
413 o
.value('CHAP', _('CHAP'));
414 o
.value('MSCHAP', _('MSCHAP'));
415 o
.value('MSCHAPV2', _('MSCHAPV2'));
416 o
.value('EAP-GTC', _('EAP-GTC'));
417 o
.value('EAP-MD5', _('EAP-MD5'));
418 o
.value('EAP-MSCHAPV2', _('EAP-MSCHAPV2'));
419 o
.value('EAP-TLS', _('EAP-TLS'));
420 o
.value('auth=PAP', _('auth=PAP'));
421 o
.value('auth=MSCHAPV2', _('auth=MSCHAPV2'));
422 o
.default = 'EAP-MSCHAPV2';
423 o
.depends({ encryption
: 'wpa', '!contains': true });
426 o
= s
.taboption('wireless', form
.Value
, 'identity', _('Identity'));
427 o
.depends({ encryption
: 'wpa', '!contains': true });
430 o
= s
.taboption('wireless', form
.Value
, 'anonymous_identity', _('Anonymous Identity'));
431 o
.depends({ encryption
: 'wpa', '!contains': true });
434 o
= s
.taboption('wireless', form
.ListValue
, 'ieee80211w', _('Mgmt. Frame Protection'));
435 o
.depends({ encryption
: 'sae', '!contains': true });
436 o
.depends({ encryption
: 'owe', '!contains': true });
437 o
.depends({ encryption
: 'wpa', '!contains': true });
438 o
.depends({ encryption
: 'psk', '!contains': true });
439 o
.value('', _('Disabled'));
440 o
.value('1', _('Optional'));
441 o
.value('2', _('Required'));
444 '2': [{ encryption
: 'sae' }, { encryption
: 'owe' }, { encryption
: 'wpa3' }, { encryption
: 'wpa3-mixed' }],
445 '1': [{ encryption
: 'sae-mixed' }],
449 o
= s
.taboption('wireless', form
.Flag
, 'ca_cert_usesystem', _('Use system certificates'), _("Validate server certificate using built-in system CA bundle"));
450 o
.depends({ encryption
: 'wpa', '!contains': true });
454 o
.default = o
.disabled
;
456 o
= s
.taboption('wireless', form
.Value
, 'ca_cert', _('Path to CA-Certificate'));
457 o
.depends({ encryption
: 'wpa', '!contains': true });
458 o
.depends({ ca_cert_usesystem
: '0' });
462 o
= s
.taboption('wireless', form
.Value
, 'client_cert', _('Path to Client-Certificate'));
463 o
.depends({ eap_type
: 'tls' });
467 o
= s
.taboption('wireless', form
.Value
, 'priv_key', _('Path to Private Key'));
468 o
.depends({ eap_type
: 'tls' });
472 o
= s
.taboption('wireless', form
.Value
, 'priv_key_pwd', _('Password of Private Key'));
473 o
.depends({ eap_type
: 'tls' });
481 var mac
, mac_array
= [];
483 mac_array
= result
[0].trim().split('\n');
486 o
= s
.taboption('travelmate', form
.Value
, '_ssid', _('SSID'));
488 o
.uciconfig
= 'travelmate';
489 o
.ucisection
= 'uplink';
490 o
.ucioption
= 'ssid';
493 o
.cfgvalue = function (section_id
) {
494 return handleSectionsVal('get', section_id
, 'ssid');
497 o
= s
.taboption('travelmate', form
.Value
, '_bssid', _('BSSID'));
499 o
.uciconfig
= 'travelmate';
500 o
.ucisection
= 'uplink';
501 o
.ucioption
= 'bssid';
504 o
.cfgvalue = function (section_id
) {
505 return handleSectionsVal('get', section_id
, 'bssid');
508 o
= s
.taboption('travelmate', form
.Value
, '_con_start', _('Connection Start'));
510 o
.uciconfig
= 'travelmate';
511 o
.ucisection
= 'uplink';
512 o
.ucioption
= 'con_start';
515 o
.cfgvalue = function (section_id
) {
516 return handleSectionsVal('get', section_id
, 'con_start');
519 o
= s
.taboption('travelmate', form
.Value
, '_con_end', _('Connection End'));
521 o
.uciconfig
= 'travelmate';
522 o
.ucisection
= 'uplink';
523 o
.ucioption
= 'con_end';
526 o
.cfgvalue = function (section_id
) {
527 return handleSectionsVal('get', section_id
, 'con_end');
530 o
= s
.taboption('travelmate', form
.Flag
, '_opensta', _('Auto Added Open Uplink'),
531 _('This option is selected by default if this uplink was added automatically and counts as \'Open Uplink\'.'));
534 o
.uciconfig
= 'travelmate';
535 o
.ucisection
= 'uplink';
536 o
.ucioption
= 'opensta';
537 o
.cfgvalue = function (section_id
) {
538 return handleSectionsVal('get', section_id
, 'opensta');
540 o
.write = function (section_id
, value
) {
541 return handleSectionsVal('set', section_id
, 'opensta', value
);
543 o
.remove = function (section_id
, value
) {
544 return handleSectionsVal('set', section_id
, 'opensta', value
);
547 o
= s
.taboption('travelmate', form
.Value
, '_macaddr', _('MAC Address'),
548 _('Use the specified MAC address for this uplink.'));
549 for (var i
= 0; i
< mac_array
.length
; i
++) {
550 if (mac_array
[i
].match(/^\s+([0-9A-Fa-f]{2}[:]?){5}[0-9A-Fa-f]{2}/)) {
551 mac
= mac_array
[i
].slice(4).trim();
556 o
.uciconfig
= 'travelmate';
557 o
.ucisection
= 'uplink';
558 o
.ucioption
= 'macaddr';
560 o
.unspecified
= true;
562 o
.datatype
= 'macaddr';
563 o
.cfgvalue = function (section_id
) {
564 return handleSectionsVal('get', section_id
, 'macaddr');
566 o
.write = function (section_id
, value
) {
567 return handleSectionsVal('set', section_id
, 'macaddr', value
);
569 o
.remove = function (section_id
, value
) {
570 return handleSectionsVal('set', section_id
, 'macaddr', value
);
573 o
= s
.taboption('travelmate', form
.Value
, '_con_start_expiry', _('Connection Start Expiry'),
574 _('Automatically disable the uplink after <em>n</em> minutes, e.g. for timed connections.<br /> \
575 The default of \'0\' disables this feature.'));
577 o
.uciconfig
= 'travelmate';
578 o
.ucisection
= 'uplink';
579 o
.ucioption
= 'con_start_expiry';
583 o
.datatype
= 'range(0,720)';
584 o
.cfgvalue = function (section_id
) {
585 return handleSectionsVal('get', section_id
, 'con_start_expiry');
587 o
.write = function (section_id
, value
) {
588 return handleSectionsVal('set', section_id
, 'con_start_expiry', value
);
591 o
= s
.taboption('travelmate', form
.Value
, '_con_end_expiry', _('Connection End Expiry'),
592 _('Automatically (re-)enable the uplink after <em>n</em> minutes, e.g. after failed login attempts.<br /> \
593 The default of \'0\' disables this feature.'));
595 o
.uciconfig
= 'travelmate';
596 o
.ucisection
= 'uplink';
597 o
.ucioption
= 'con_end_expiry';
601 o
.datatype
= 'range(0,720)';
602 o
.cfgvalue = function (section_id
) {
603 return handleSectionsVal('get', section_id
, 'con_end_expiry');
605 o
.write = function (section_id
, value
) {
606 return handleSectionsVal('set', section_id
, 'con_end_expiry', value
);
609 o
= s
.taboption('travelmate', form
.FileUpload
, '_script', _('Auto Login Script'),
610 _('External script reference which will be called for automated captive portal logins.'));
611 o
.root_directory
= '/etc/travelmate';
612 o
.enable_remove
= false;
613 o
.enable_upload
= false;
615 o
.uciconfig
= 'travelmate';
616 o
.ucisection
= 'uplink';
617 o
.ucioption
= 'script';
618 o
.renderWidget = function (section_id
, option_index
, cfgvalue
) {
619 var browserEl
= new ui
.FileUpload((cfgvalue
!= null) ? cfgvalue
: this.default, {
620 id
: this.cbid(section_id
),
621 name
: this.cbid(section_id
),
622 show_hidden
: this.show_hidden
,
623 enable_upload
: this.enable_upload
,
624 enable_remove
: this.enable_remove
,
625 root_directory
: this.root_directory
,
626 disabled
: (this.readonly
!= null) ? this.readonly
: this.map
.readonly
628 browserEl
.renderListing = function (container
, path
, list
) {
629 return ui
.FileUpload
.prototype.renderListing
.apply(this, [
631 list
.filter(function (entry
) {
632 return ((entry
.type
== 'directory') || (entry
.type
== 'file' && entry
.name
.match(/\.login$/)));
636 return browserEl
.render();
638 o
.cfgvalue = function (section_id
) {
639 return handleSectionsVal('get', section_id
, 'script');
641 o
.write = function (section_id
, value
) {
642 return handleSectionsVal('set', section_id
, 'script', value
);
644 o
.remove = function (section_id
) {
645 return handleSectionsVal('del', section_id
, 'script');
648 o
= s
.taboption('travelmate', form
.Value
, '_args', _('Script Arguments'),
649 _('Space separated list of additional arguments passed to the Auto Login Script, i.e. username and password'));
651 o
.uciconfig
= 'travelmate';
652 o
.ucisection
= 'uplink';
653 o
.ucioption
= 'script_args';
655 o
.depends({ _script
: '/etc/travelmate', '!contains': true });
656 o
.cfgvalue = function (section_id
) {
657 return handleSectionsVal('get', section_id
, 'script_args');
659 o
.write = function (section_id
, value
) {
660 return handleSectionsVal('set', section_id
, 'script_args', value
);
662 o
.remove = function (section_id
) {
663 return handleSectionsVal('del', section_id
, 'script_args');
669 o
= s
.taboption('vpn', form
.Flag
, '_vpn', _('VPN Hook'), _('Automatically handle VPN connections.<br /> \
670 Please note: This feature requires the additional configuration of <em>Wireguard</em> or <em>OpenVPN</em>.'));
673 o
.uciconfig
= 'travelmate';
674 o
.ucisection
= 'uplink';
676 o
.cfgvalue = function (section_id
) {
677 return handleSectionsVal('get', section_id
, 'vpn');
679 o
.write = function (section_id
, value
) {
680 return handleSectionsVal('set', section_id
, 'vpn', value
);
682 o
.remove = function (section_id
, value
) {
683 return handleSectionsVal('set', section_id
, 'vpn', value
);
686 o
= s
.taboption('vpn', form
.ListValue
, '_vpnservice', _('VPN Service'));
687 o
.value('wireguard');
691 o
.uciconfig
= 'travelmate';
692 o
.ucisection
= 'uplink';
693 o
.ucioption
= 'vpnservice';
694 o
.cfgvalue = function (section_id
) {
695 return handleSectionsVal('get', section_id
, 'vpnservice');
697 o
.write = function (section_id
, value
) {
698 return handleSectionsVal('set', section_id
, 'vpnservice', value
);
701 o
= s
.taboption('vpn', widgets
.NetworkSelect
, '_vpniface', _('VPN Interface'), _('The logical vpn network interface, e.g. \'wg0\' or \'tun0\'.'));
702 o
.unspecified
= false;
706 o
.uciconfig
= 'travelmate';
707 o
.ucisection
= 'uplink';
708 o
.ucioption
= 'vpniface';
709 o
.cfgvalue = function (section_id
) {
710 return handleSectionsVal('get', section_id
, 'vpniface');
712 o
.write = function (section_id
, value
) {
713 return handleSectionsVal('set', section_id
, 'vpniface', value
);
719 s
= m
.section(form
.GridSection
, 'wifi-device');
722 s
.render = function () {
723 return network
.getWifiDevices().then(L
.bind(function (radios
) {
724 var radio
, ifname
, btns
= [];
725 for (var i
= 0; i
< radios
.length
; i
++) {
726 radio
= radios
[i
].sid
;
728 btns
.push(E('button', {
729 'class': 'cbi-button cbi-button-apply',
731 'click': ui
.createHandlerFn(this, 'handleScan', radio
)
732 }, [_('Scan on ' + radio
+ '...')]),
736 return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns
));
743 s
.handleScan = function (radio
) {
744 var table
= E('table', { 'class': 'table' }, [
745 E('tr', { 'class': 'tr table-titles' }, [
746 E('th', { 'class': 'th col-1 middle left' }, _('Strength')),
747 E('th', { 'class': 'th col-1 middle left hide-xs' }, _('Channel')),
748 E('th', { 'class': 'th col-2 middle left' }, _('SSID')),
749 E('th', { 'class': 'th col-2 middle left' }, _('BSSID')),
750 E('th', { 'class': 'th col-3 middle left' }, _('Encryption')),
751 E('th', { 'class': 'th cbi-section-actions right' }, '\xa0')
754 cbi_update_table(table
, [], E('em', { class: 'spinning' }, _('Starting wireless scan on \'' + radio
+ '\'...')));
756 var md
= ui
.showModal(_('Wireless Scan'), [
758 E('div', { 'class': 'right' }, [
761 'click': ui
.hideModal
765 'class': 'cbi-button cbi-button-positive important',
766 'click': L
.bind(this.handleScan
, this, radio
)
771 md
.style
.maxWidth
= '90%';
772 md
.style
.maxHeight
= 'none';
774 return L
.resolveDefault(fs
.exec_direct('/etc/init.d/travelmate', ['scan', radio
]), null)
775 .then(L
.bind(function (res
) {
776 var lines
, strength
, channel
, encryption
, tbl_encryption
, bssid
, ssid
, tbl_ssid
, rows
= [];
778 lines
= res
.trim().split('\n');
779 for (var i
= 0; i
< lines
.length
; i
++) {
780 if (lines
[i
].match(/^\s+[0-9]/)) {
781 encryption
= lines
[i
].slice(80).trim();
782 if (!encryption
.includes('WEP')) {
783 strength
= lines
[i
].slice(4, 7).trim();
784 channel
= lines
[i
].slice(15, 18).trim();
785 bssid
= lines
[i
].slice(60, 77).trim();
786 ssid
= lines
[i
].slice(25, 59).trim();
787 if (ssid
.startsWith('"')) {
788 ssid
= ssid
.slice(1, ssid
.length
- 1);
793 tbl_ssid
= "<em>hidden</em>";
795 switch (encryption
) {
796 case 'WPA3 PSK (SAE)':
798 tbl_encryption
= 'WPA3 Pers. (SAE)';
800 case 'mixed WPA2/WPA3 PSK/SAE (CCMP)':
801 encryption
= 'sae-mixed';
802 tbl_encryption
= 'WPA2/WPA3 Pers. (CCMP)';
804 case 'WPA2 PSK (CCMP)':
805 encryption
= 'psk2+ccmp';
806 tbl_encryption
= 'WPA2 Pers. (CCMP)';
808 case 'WPA2 PSK (TKIP)':
809 encryption
= 'psk2+tkip';
810 tbl_encryption
= 'WPA2 Pers. (TKIP)';
812 case 'mixed WPA/WPA2 PSK (TKIP, CCMP)':
813 encryption
= 'psk-mixed+ccmp';
814 tbl_encryption
= 'WPA/WPA2 Pers. (CCMP)';
816 case 'WPA PSK (CCMP)':
817 encryption
= 'psk2+ccmp';
818 tbl_encryption
= 'WPA Pers. (CCMP)';
820 case 'WPA PSK (TKIP)':
821 encryption
= 'psk2+tkip';
822 tbl_encryption
= 'WPA Pers. (TKIP)';
824 case 'WPA3 802.1X (CCMP)':
826 tbl_encryption
= 'WPA3 Ent. (CCMP)';
828 case 'mixed WPA2/WPA3 802.1X (CCMP)':
829 encryption
= 'wpa3-mixed';
830 tbl_encryption
= 'WPA2/WPA3 Ent. (CCMP)';
834 tbl_encryption
= 'WPA2 Ent.';
836 case 'WPA2 802.1X (CCMP)':
837 encryption
= 'wpa2+ccmp';
838 tbl_encryption
= 'WPA2 Ent. (CCMP)';
840 case 'WPA3 OWE (CCMP)':
842 tbl_encryption
= 'WPA3 OWE (CCMP)';
846 tbl_encryption
= 'none';
855 E('div', { 'class': 'right' }, E('button', {
856 'class': 'cbi-button cbi-button-action',
857 'click': ui
.createHandlerFn(this, 'handleAdd', radio
, iface
, ssid
, bssid
, encryption
)
858 }, _('Add Uplink...')))
862 else if (lines
[i
] === '::: Empty resultset') {
864 'No scan results (empty resultset)'
871 'No scan results (timeout)'
874 cbi_update_table(table
, rows
);
881 s
.handleAdd = function (radio
, iface
, ssid
, bssid
, encryption
, ev
) {
884 m2
= new form
.Map('wireless'),
885 s2
= m2
.section(form
.NamedSection
, '_add_trm');
887 s2
.render = function () {
890 this.renderUCISection('_add_trm')
891 ]).then(this.renderContents
.bind(this));
894 o2
= s2
.option(form
.Value
, 'device', _('Device Name'));
898 o2
= s2
.option(form
.Value
, 'network', _('Interface Name'));
902 if (ssid
=== "hidden") {
903 o2
= s2
.option(form
.Value
, 'ssid', _('SSID (hidden)'));
904 o2
.placeholder
= 'hidden SSID';
907 o2
= s2
.option(form
.Value
, 'ssid', _('SSID'));
910 o2
.datatype
= 'maxlength(32)';
913 o2
= s2
.option(form
.Flag
, 'ignore_bssid', _('Ignore BSSID'));
914 if (ssid
=== "hidden") {
921 o2
= s2
.option(form
.Value
, 'bssid', _('BSSID'));
922 o2
.depends({ ignore_bssid
: '0' });
923 o2
.datatype
= 'macaddr';
927 o2
= s2
.option(form
.ListValue
, 'encryption', _('Encryption'));
928 o2
.value('sae', _('WPA3 Pers. (SAE)'));
929 o2
.value('sae-mixed', _('WPA2/WPA3 Pers. (CCMP)'));
930 o2
.value('psk2', _('WPA2 Pers.'));
931 o2
.value('psk2+ccmp', _('WPA2 Pers. (CCMP)'));
932 o2
.value('psk2+tkip', _('WPA2 Pers. (TKIP)'));
933 o2
.value('psk', _('WPA Pers.'));
934 o2
.value('psk+ccmp', _('WPA Pers. (CCMP)'));
935 o2
.value('psk+tkip', _('WPA Pers. (TKIP)'));
936 o2
.value('psk-mixed+ccmp', _('WPA/WPA2 Pers. (CCMP)'));
937 o2
.value('psk-mixed+tkip', _('WPA/WPA2 Pers. (TKIP)'));
938 o2
.value('wpa3', _('WPA3 Ent.'));
939 o2
.value('wpa3-mixed', _('WPA2/WPA3 Ent.'));
940 o2
.value('wpa2', _('WPA2 Ent.'));
941 o2
.value('wpa2+ccmp', _('WPA2 Ent. (CCMP)'));
942 o2
.value('wpa2+tkip', _('WPA2 Ent. (TKIP)'));
943 o2
.value('wpa+ccmp', _('WPA Ent. (CCMP)'));
944 o2
.value('wpa+tkip', _('WPA Ent. (TKIP)'));
945 o2
.value('wpa-mixed+ccmp', _('WPA/WPA2 Ent. (CCMP)'));
946 o2
.value('wpa-mixed+tkip', _('WPA/WPA2 Ent. (TKIP)'));
947 o2
.value('owe', _('WPA3 OWE (CCMP)'));
948 o2
.value('none', _('none'));
949 o2
.default = encryption
;
951 o2
= s2
.option(form
.Value
, 'key', _('Password'));
952 o2
.depends({ encryption
: 'sae', '!contains': true });
953 o2
.depends({ encryption
: 'psk', '!contains': true });
954 o2
.datatype
= 'wpakey';
957 o2
= s2
.option(form
.Value
, 'password', _('Password'));
958 o2
.depends({ encryption
: 'wpa', '!contains': true });
959 o2
.datatype
= 'wpakey';
962 o2
= s2
.option(form
.ListValue
, 'eap_type', _('EAP-Method'));
963 o2
.depends({ encryption
: 'wpa', '!contains': true });
964 o2
.value('tls', _('TLS'));
965 o2
.value('ttls', _('TTLS'));
966 o2
.value('peap', _('PEAP'));
967 o2
.value('fast', _('FAST'));
970 o2
= s2
.option(form
.ListValue
, 'auth', _('Authentication'));
971 o2
.depends({ encryption
: 'wpa', '!contains': true });
972 o2
.value('PAP', _('PAP'));
973 o2
.value('CHAP', _('CHAP'));
974 o2
.value('MSCHAP', _('MSCHAP'));
975 o2
.value('MSCHAPV2', _('MSCHAPV2'));
976 o2
.value('EAP-GTC', _('EAP-GTC'));
977 o2
.value('EAP-MD5', _('EAP-MD5'));
978 o2
.value('EAP-MSCHAPV2', _('EAP-MSCHAPV2'));
979 o2
.value('EAP-TLS', _('EAP-TLS'));
980 o2
.value('auth=PAP', _('auth=PAP'));
981 o2
.value('auth=MSCHAPV2', _('auth=MSCHAPV2'));
982 o2
.default = 'EAP-MSCHAPV2';
984 o2
= s2
.option(form
.Value
, 'identity', _('Identity'));
985 o2
.depends({ encryption
: 'wpa', '!contains': true });
987 o2
= s2
.option(form
.Value
, 'anonymous_identity', _('Anonymous Identity'));
988 o2
.depends({ encryption
: 'wpa', '!contains': true });
991 o2
= s2
.option(form
.ListValue
, 'ieee80211w', _('Mgmt. Frame Protection'));
992 o2
.depends({ encryption
: 'sae', '!contains': true });
993 o2
.depends({ encryption
: 'owe', '!contains': true });
994 o2
.depends({ encryption
: 'wpa', '!contains': true });
995 o2
.depends({ encryption
: 'psk', '!contains': true });
996 o2
.value('', _('Disabled'));
997 o2
.value('1', _('Optional'));
998 o2
.value('2', _('Required'));
1000 '2': [{ encryption
: 'sae' }, { encryption
: 'owe' }, { encryption
: 'wpa3' }, { encryption
: 'wpa3-mixed' }],
1001 '1': [{ encryption
: 'sae-mixed' }],
1005 o2
= s2
.option(form
.Flag
, 'ca_cert_usesystem', _('Use system certificates'), _("Validate server certificate using built-in system CA bundle"));
1006 o2
.depends({ encryption
: 'wpa', '!contains': true });
1009 o2
.default = o
.disabled
;
1011 o2
= s2
.option(form
.Value
, 'ca_cert', _('Path to CA-Certificate'));
1012 o2
.depends({ encryption
: 'wpa', '!contains': true });
1013 o2
.depends({ ca_cert_usesystem
: '0' });
1016 o2
= s2
.option(form
.Value
, 'client_cert', _('Path to Client-Certificate'));
1017 o2
.depends({ eap_type
: 'tls' });
1020 o2
= s2
.option(form
.Value
, 'priv_key', _('Path to Private Key'));
1021 o2
.depends({ eap_type
: 'tls' });
1024 o2
= s2
.option(form
.Value
, 'priv_key_pwd', _('Password of Private Key'));
1025 o2
.depends({ eap_type
: 'tls' });
1029 return m2
.render().then(L
.bind(function (elements
) {
1030 ui
.showModal(_('Add Uplink %q').replace(/%q/, '"%h"'.format(ssid
)), [
1032 E('div', { 'class': 'right' }, [
1035 'click': ui
.hideModal
1039 'class': 'cbi-button cbi-button-positive important',
1040 'click': ui
.createHandlerFn(this, 'handleCommit', m2
)
1050 s
.handleCommit = function (map
, ev
) {
1051 var w_sections
= uci
.sections('wireless', 'wifi-iface'),
1052 device
= L
.toArray(map
.lookupOption('device', '_add_trm'))[0].formvalue('_add_trm'),
1053 network
= L
.toArray(map
.lookupOption('network', '_add_trm'))[0].formvalue('_add_trm'),
1054 ssid
= L
.toArray(map
.lookupOption('ssid', '_add_trm'))[0].formvalue('_add_trm'),
1055 ignore_bssid
= L
.toArray(map
.lookupOption('ignore_bssid', '_add_trm'))[0].formvalue('_add_trm'),
1056 bssid
= L
.toArray(map
.lookupOption('bssid', '_add_trm'))[0].formvalue('_add_trm'),
1057 encryption
= L
.toArray(map
.lookupOption('encryption', '_add_trm'))[0].formvalue('_add_trm');
1058 if (encryption
.includes('wpa')) {
1059 var eap_type
= L
.toArray(map
.lookupOption('eap_type', '_add_trm'))[0].formvalue('_add_trm'),
1060 auth
= L
.toArray(map
.lookupOption('auth', '_add_trm'))[0].formvalue('_add_trm'),
1061 identity
= L
.toArray(map
.lookupOption('identity', '_add_trm'))[0].formvalue('_add_trm'),
1062 anonymous_identity
= L
.toArray(map
.lookupOption('anonymous_identity', '_add_trm'))[0].formvalue('_add_trm'),
1063 password
= L
.toArray(map
.lookupOption('password', '_add_trm'))[0].formvalue('_add_trm'),
1064 ca_cert_usesystem
= L
.toArray(map
.lookupOption('ca_cert_usesystem', '_add_trm'))[0].formvalue('_add_trm'),
1065 ca_cert
= L
.toArray(map
.lookupOption('ca_cert', '_add_trm'))[0].formvalue('_add_trm'),
1066 ieee80211w
= L
.toArray(map
.lookupOption('ieee80211w', '_add_trm'))[0].formvalue('_add_trm');
1067 if (eap_type
.includes('tls')) {
1068 var client_cert
= L
.toArray(map
.lookupOption('client_cert', '_add_trm'))[0].formvalue('_add_trm'),
1069 priv_key
= L
.toArray(map
.lookupOption('priv_key', '_add_trm'))[0].formvalue('_add_trm'),
1070 priv_key_pwd
= L
.toArray(map
.lookupOption('priv_key_pwd', '_add_trm'))[0].formvalue('_add_trm');
1073 var password
= L
.toArray(map
.lookupOption('key', '_add_trm'))[0].formvalue('_add_trm');
1075 if (!ssid
|| ((encryption
.includes('psk') || encryption
.includes('wpa') || encryption
.includes('sae')) && !password
)) {
1077 ui
.addNotification(null, E('p', 'Empty SSID, the uplink station could not be saved.'), 'error');
1080 ui
.addNotification(null, E('p', 'Empty Password, the uplink station could not be saved.'), 'error');
1082 return ui
.hideModal();
1084 for (var i
= 0; i
< w_sections
.length
; i
++) {
1085 if (w_sections
[i
].device
=== device
&& w_sections
[i
].ssid
=== ssid
) {
1086 if (ignore_bssid
=== '1' || (ignore_bssid
=== '0' && w_sections
[i
].bssid
=== bssid
)) {
1087 ui
.addNotification(null, E('p', 'Duplicate wireless entry, the uplink station could not be saved.'), 'error');
1088 return ui
.hideModal();
1093 var offset
= w_sections
.length
,
1094 new_sid
= 'trm_uplink' + (++offset
);
1095 while (uci
.get('wireless', new_sid
)) {
1096 new_sid
= 'trm_uplink' + (++offset
);
1098 uci
.add('wireless', 'wifi-iface', new_sid
);
1099 uci
.set('wireless', new_sid
, 'device', device
);
1100 uci
.set('wireless', new_sid
, 'mode', 'sta');
1101 uci
.set('wireless', new_sid
, 'network', network
);
1102 uci
.set('wireless', new_sid
, 'ssid', ssid
);
1103 if (ignore_bssid
=== '0') {
1104 uci
.set('wireless', new_sid
, 'bssid', bssid
);
1106 uci
.set('wireless', new_sid
, 'encryption', encryption
);
1107 if (encryption
.includes('wpa')) {
1108 uci
.set('wireless', new_sid
, 'eap_type', eap_type
);
1109 uci
.set('wireless', new_sid
, 'auth', auth
);
1110 uci
.set('wireless', new_sid
, 'identity', identity
);
1111 uci
.set('wireless', new_sid
, 'anonymous_identity', anonymous_identity
);
1112 uci
.set('wireless', new_sid
, 'password', password
);
1113 uci
.set('wireless', new_sid
, 'ca_cert_usesystem', ca_cert_usesystem
);
1114 uci
.set('wireless', new_sid
, 'ca_cert', ca_cert
);
1115 uci
.set('wireless', new_sid
, 'ieee80211w', ieee80211w
);
1116 if (eap_type
.includes('tls')) {
1117 uci
.set('wireless', new_sid
, 'client_cert', client_cert
);
1118 uci
.set('wireless', new_sid
, 'priv_key', priv_key
);
1119 uci
.set('wireless', new_sid
, 'priv_key_pwd', priv_key_pwd
);
1122 uci
.set('wireless', new_sid
, 'key', password
);
1124 uci
.set('wireless', new_sid
, 'disabled', '1');
1125 handleSectionsAdd(network
);
1127 .then(L
.bind(this.map
.load
, this.map
))
1128 .then(L
.bind(this.map
.reset
, this.map
))
1130 var row
= document
.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(new_sid
));
1131 row
.setAttribute('style', 'opacity: 0.5; color: #4a4 !important;');