luci-app-travelmate: EAP-bugfixes
[project/luci.git] / applications / luci-app-travelmate / htdocs / luci-static / resources / view / travelmate / stations.js
1 'use strict';
2 'require view';
3 'require poll';
4 'require fs';
5 'require ui';
6 'require uci';
7 'require form';
8 'require network';
9 'require tools.widgets as widgets';
10
11 /*
12 change the status of travelmate stations
13 */
14 function handleToggle(sid) {
15 var w_device, w_ssid, w_bssid, t_sections, row, element, value, enabled;
16
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');
21
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;');
33 });
34 }
35 }
36 }
37
38 /*
39 remove wireless and stale travelmate sections
40 */
41 function handleRemove(sid) {
42 var w_sections, t_sections, match, row;
43
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++) {
48 match = false;
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) {
51 match = true;
52 break;
53 }
54 }
55 if (match === false) {
56 uci.remove('travelmate', t_sections[i]['.name']);
57 }
58 }
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;');
62 });
63 }
64
65 /*
66 add missing travelmate sections
67 */
68 function handleSectionsAdd(iface) {
69 var w_sections, t_sections, match;
70
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) {
75 continue;
76 }
77 match = false;
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) {
80 match = true;
81 break;
82 }
83 }
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');
92 }
93 }
94 }
95
96 /*
97 update travelmate sections
98 */
99 function handleSectionsVal(action, section_id, option, value) {
100 var date, oldValue, w_device, w_ssid, w_bssid, t_sections;
101
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');
106
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];
111 }
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);
118 }
119 else if (oldValue !== value && value === '1') {
120 uci.unset('travelmate', t_sections[i]['.name'], 'con_end');
121 }
122 }
123 return uci.set('travelmate', t_sections[i]['.name'], option, value);
124 }
125 else if (action === 'del') {
126 return uci.unset('travelmate', t_sections[i]['.name'], option);
127 }
128 }
129 }
130 }
131
132 /*
133 update travelmate status
134 */
135 function handleStatus() {
136 poll.add(function () {
137 L.resolveDefault(fs.stat('/var/state/travelmate.refresh'), null).then(function (res) {
138 if (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') {
142 location.reload();
143 }
144 else if (res && res === 'cfg_reload') {
145 if (document.readyState === 'complete') {
146 uci.unload('wireless');
147 uci.unload('travelmate');
148 }
149 await Promise.all([
150 uci.load('wireless'),
151 uci.load('travelmate')
152 ]);
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');
159 }
160 }
161 });
162 }
163 });
164 return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) {
165 if (res) {
166 L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) {
167 if (res) {
168 var info = JSON.parse(res);
169 if (info) {
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++) {
178 if (!t_ssid) {
179 t_ssid = uplinkId[i];
180 }
181 else {
182 t_ssid = t_ssid + '/' + uplinkId[i];
183 }
184 }
185 if (t_ssid === '-') {
186 if (oldUplinkView.length > 0) {
187 oldUplinkView[0].removeAttribute('style');
188 oldUplinkView[0].removeAttribute('name', 'uplinkStation');
189 }
190 }
191 else {
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;');
199 }
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;');
205 }
206 else if (newUplinkView && newUplinkView.style.color != uplinkColor) {
207 newUplinkView.setAttribute('style', 'text-align: left !important; color: ' + uplinkColor + ' !important;font-weight: bold !important;');
208 }
209 }
210 }
211 }
212 }
213 }
214 });
215 }
216 });
217 }, 1);
218 }
219
220 return view.extend({
221 load: function () {
222 return Promise.all([
223 L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['assoc']), {}),
224 uci.load('wireless'),
225 uci.load('travelmate')
226 ]);
227 },
228
229 render: function (result) {
230 var m, s, o,
231 iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan';
232
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 \&#38; 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>.'));
239 s.anonymous = true;
240 s.sortable = true;
241 s.filter = function (section_id) {
242 return (uci.get('wireless', section_id, 'network') == iface && uci.get('wireless', section_id, 'mode') == 'sta');
243 };
244 s.tab('wireless', _('Wireless Settings'));
245 s.tab('travelmate', _('Travelmate Settings'));
246 s.tab('vpn', _('VPN Settings'));
247 s.renderRowActions = function (section_id) {
248 var btns;
249 btns = [
250 E('button', {
251 'class': 'btn cbi-button drag-handle center',
252 'title': _('Drag to reorder'),
253 'style': 'cursor:move',
254 'disabled': this.map.readonly || null
255 }, '☰'),
256 E('button', {
257 'class': 'cbi-button cbi-button-action important',
258 'title': _('Edit this network'),
259 'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id)
260 }, _('Edit')),
261 E('button', {
262 'class': 'cbi-button cbi-button-apply',
263 'title': _('Enable/Disable this network'),
264 'click': ui.createHandlerFn(this, handleToggle, section_id)
265 }, _('On/Off')),
266 E('button', {
267 'class': 'cbi-button cbi-button-negative remove',
268 'title': _('Remove this network'),
269 'click': ui.createHandlerFn(this, handleRemove, section_id)
270 }, _('Remove'))
271 ];
272 return E('td', { 'class': 'td middle cbi-section-actions' }, E('div', btns));
273 };
274
275 o = s.taboption('travelmate', form.Flag, '_enabled', _('Enabled'));
276 o.uciconfig = 'travelmate';
277 o.ucisection = 'uplink';
278 o.ucioption = 'enabled';
279 o.rmempty = false;
280 o.cfgvalue = function (section_id) {
281 return handleSectionsVal('get', section_id, 'enabled');
282 }
283 o.write = function (section_id, value) {
284 return handleSectionsVal('set', section_id, 'enabled', value);
285 }
286
287 o = s.taboption('wireless', form.Value, 'device', _('Device'));
288 o.readonly = true;
289
290 o = s.taboption('wireless', form.Value, 'ssid', _('SSID'));
291 o.datatype = 'maxlength(32)';
292 o.readonly = true;
293
294 o = s.taboption('wireless', form.Value, 'bssid', _('BSSID'));
295 o.datatype = 'macaddr';
296 o.readonly = true;
297
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'));
320 o.default = 'none';
321 o.textvalue = function (section_id) {
322 var cfgvalue = this.map.data.get('wireless', section_id, 'encryption');
323 switch (cfgvalue) {
324 case 'sae':
325 cfgvalue = 'WPA3 Pers. (SAE)';
326 break;
327 case 'sae-mixed':
328 cfgvalue = 'WPA2/WPA3 Pers. (CCMP)';
329 break;
330 case 'psk2':
331 cfgvalue = 'WPA2 Pers.';
332 break;
333 case 'psk2+ccmp':
334 cfgvalue = 'WPA2 Pers. (CCMP)';
335 break;
336 case 'psk2+tkip':
337 cfgvalue = 'WPA2 Ent. (TKIP)';
338 break;
339 case 'psk':
340 cfgvalue = 'WPA Pers.';
341 break;
342 case 'psk-mixed+ccmp':
343 cfgvalue = 'WPA/WPA2 Pers. (CCMP)';
344 break;
345 case 'psk-mixed+tkip':
346 cfgvalue = 'WPA/WPA2 Pers. (TKIP)';
347 break;
348 case 'wpa3':
349 cfgvalue = 'WPA3 Ent. (CCMP)';
350 break;
351 case 'wpa3-mixed':
352 cfgvalue = 'WPA2/WPA3 Ent. (CCMP)';
353 break;
354 case 'wpa2':
355 cfgvalue = 'WPA2 Ent.';
356 break;
357 case 'wpa2+ccmp':
358 cfgvalue = 'WPA2 Ent. (CCMP)';
359 break;
360 case 'wpa2+tkip':
361 cfgvalue = 'WPA2 Ent. (TKIP)';
362 break;
363 case 'wpa+ccmp':
364 cfgvalue = 'WPA Ent. (CCMP)';
365 break;
366 case 'wpa+tkip':
367 cfgvalue = 'WPA Ent. (TKIP)';
368 break;
369 case 'wpa-mixed+ccmp':
370 cfgvalue = 'WPA/WPA2 Ent. (CCMP)';
371 break;
372 case 'wpa-mixed+tkip':
373 cfgvalue = 'WPA/WPA2 Ent. (TKIP)';
374 break;
375 case 'owe':
376 cfgvalue = 'WPA3 OWE (CCMP)';
377 break;
378 case 'none':
379 cfgvalue = 'none';
380 break;
381 }
382 return cfgvalue;
383 };
384 handleStatus();
385
386 /*
387 modal wireless tab
388 */
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 });
393 o.modalonly = true;
394 o.password = true;
395
396 o = s.taboption('wireless', form.Value, 'password', _('Password'));
397 o.datatype = 'wpakey';
398 o.depends({ encryption: 'wpa', '!contains': true });
399 o.modalonly = true;
400 o.password = true;
401
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'));
408 o.default = 'peap';
409 o.modalonly = true;
410
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 });
424 o.modalonly = true;
425
426 o = s.taboption('wireless', form.Value, 'identity', _('Identity'));
427 o.depends({ encryption: 'wpa', '!contains': true });
428 o.modalonly = true;
429
430 o = s.taboption('wireless', form.Value, 'anonymous_identity', _('Anonymous Identity'));
431 o.depends({ encryption: 'wpa', '!contains': true });
432 o.modalonly = true;
433
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'));
442 o.modalonly = true;
443 o.defaults = {
444 '2': [{ encryption: 'sae' }, { encryption: 'owe' }, { encryption: 'wpa3' }, { encryption: 'wpa3-mixed' }],
445 '1': [{ encryption: 'sae-mixed' }],
446 '': []
447 };
448
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 });
451 o.enabled = '1';
452 o.disabled = '0';
453 o.modalonly = true;
454 o.default = o.disabled;
455
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' });
459 o.modalonly = true;
460 o.rmempty = true;
461
462 o = s.taboption('wireless', form.Value, 'client_cert', _('Path to Client-Certificate'));
463 o.depends({ eap_type: 'tls' });
464 o.modalonly = true;
465 o.rmempty = true;
466
467 o = s.taboption('wireless', form.Value, 'priv_key', _('Path to Private Key'));
468 o.depends({ eap_type: 'tls' });
469 o.modalonly = true;
470 o.rmempty = true;
471
472 o = s.taboption('wireless', form.Value, 'priv_key_pwd', _('Password of Private Key'));
473 o.depends({ eap_type: 'tls' });
474 o.modalonly = true;
475 o.password = true;
476 o.rmempty = true;
477
478 /*
479 modal travelmate tab
480 */
481 var mac, mac_array = [];
482 if (result[0]) {
483 mac_array = result[0].trim().split('\n');
484 }
485
486 o = s.taboption('travelmate', form.Value, '_ssid', _('SSID'));
487 o.modalonly = true;
488 o.uciconfig = 'travelmate';
489 o.ucisection = 'uplink';
490 o.ucioption = 'ssid';
491 o.rmempty = false;
492 o.readonly = true;
493 o.cfgvalue = function (section_id) {
494 return handleSectionsVal('get', section_id, 'ssid');
495 }
496
497 o = s.taboption('travelmate', form.Value, '_bssid', _('BSSID'));
498 o.modalonly = true;
499 o.uciconfig = 'travelmate';
500 o.ucisection = 'uplink';
501 o.ucioption = 'bssid';
502 o.rmempty = true;
503 o.readonly = true;
504 o.cfgvalue = function (section_id) {
505 return handleSectionsVal('get', section_id, 'bssid');
506 }
507
508 o = s.taboption('travelmate', form.Value, '_con_start', _('Connection Start'));
509 o.modalonly = true;
510 o.uciconfig = 'travelmate';
511 o.ucisection = 'uplink';
512 o.ucioption = 'con_start';
513 o.rmempty = true;
514 o.readonly = true;
515 o.cfgvalue = function (section_id) {
516 return handleSectionsVal('get', section_id, 'con_start');
517 }
518
519 o = s.taboption('travelmate', form.Value, '_con_end', _('Connection End'));
520 o.modalonly = true;
521 o.uciconfig = 'travelmate';
522 o.ucisection = 'uplink';
523 o.ucioption = 'con_end';
524 o.rmempty = true;
525 o.readonly = true;
526 o.cfgvalue = function (section_id) {
527 return handleSectionsVal('get', section_id, 'con_end');
528 }
529
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\'.'));
532 o.rmempty = true;
533 o.modalonly = true;
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');
539 }
540 o.write = function (section_id, value) {
541 return handleSectionsVal('set', section_id, 'opensta', value);
542 }
543 o.remove = function (section_id, value) {
544 return handleSectionsVal('set', section_id, 'opensta', value);
545 }
546
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();
552 o.value(mac);
553 }
554 }
555 o.modalonly = true;
556 o.uciconfig = 'travelmate';
557 o.ucisection = 'uplink';
558 o.ucioption = 'macaddr';
559 o.nocreate = false;
560 o.unspecified = true;
561 o.rmempty = true;
562 o.datatype = 'macaddr';
563 o.cfgvalue = function (section_id) {
564 return handleSectionsVal('get', section_id, 'macaddr');
565 }
566 o.write = function (section_id, value) {
567 return handleSectionsVal('set', section_id, 'macaddr', value);
568 }
569 o.remove = function (section_id, value) {
570 return handleSectionsVal('set', section_id, 'macaddr', value);
571 }
572
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.'));
576 o.modalonly = true;
577 o.uciconfig = 'travelmate';
578 o.ucisection = 'uplink';
579 o.ucioption = 'con_start_expiry';
580 o.rmempty = false;
581 o.placeholder = '0';
582 o.default = '0';
583 o.datatype = 'range(0,720)';
584 o.cfgvalue = function (section_id) {
585 return handleSectionsVal('get', section_id, 'con_start_expiry');
586 }
587 o.write = function (section_id, value) {
588 return handleSectionsVal('set', section_id, 'con_start_expiry', value);
589 }
590
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.'));
594 o.modalonly = true;
595 o.uciconfig = 'travelmate';
596 o.ucisection = 'uplink';
597 o.ucioption = 'con_end_expiry';
598 o.rmempty = false;
599 o.placeholder = '0';
600 o.default = '0';
601 o.datatype = 'range(0,720)';
602 o.cfgvalue = function (section_id) {
603 return handleSectionsVal('get', section_id, 'con_end_expiry');
604 }
605 o.write = function (section_id, value) {
606 return handleSectionsVal('set', section_id, 'con_end_expiry', value);
607 }
608
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;
614 o.modalonly = true;
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
627 });
628 browserEl.renderListing = function (container, path, list) {
629 return ui.FileUpload.prototype.renderListing.apply(this, [
630 container, path,
631 list.filter(function (entry) {
632 return ((entry.type == 'directory') || (entry.type == 'file' && entry.name.match(/\.login$/)));
633 })
634 ]);
635 };
636 return browserEl.render();
637 };
638 o.cfgvalue = function (section_id) {
639 return handleSectionsVal('get', section_id, 'script');
640 }
641 o.write = function (section_id, value) {
642 return handleSectionsVal('set', section_id, 'script', value);
643 }
644 o.remove = function (section_id) {
645 return handleSectionsVal('del', section_id, 'script');
646 }
647
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'));
650 o.modalonly = true;
651 o.uciconfig = 'travelmate';
652 o.ucisection = 'uplink';
653 o.ucioption = 'script_args';
654 o.rmempty = true;
655 o.depends({ _script: '/etc/travelmate', '!contains': true });
656 o.cfgvalue = function (section_id) {
657 return handleSectionsVal('get', section_id, 'script_args');
658 }
659 o.write = function (section_id, value) {
660 return handleSectionsVal('set', section_id, 'script_args', value);
661 }
662 o.remove = function (section_id) {
663 return handleSectionsVal('del', section_id, 'script_args');
664 }
665
666 /*
667 modal vpn tab
668 */
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>.'));
671 o.rmempty = true;
672 o.modalonly = true;
673 o.uciconfig = 'travelmate';
674 o.ucisection = 'uplink';
675 o.ucioption = 'vpn';
676 o.cfgvalue = function (section_id) {
677 return handleSectionsVal('get', section_id, 'vpn');
678 }
679 o.write = function (section_id, value) {
680 return handleSectionsVal('set', section_id, 'vpn', value);
681 }
682 o.remove = function (section_id, value) {
683 return handleSectionsVal('set', section_id, 'vpn', value);
684 }
685
686 o = s.taboption('vpn', form.ListValue, '_vpnservice', _('VPN Service'));
687 o.value('wireguard');
688 o.value('openvpn');
689 o.optional = true;
690 o.modalonly = true;
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');
696 }
697 o.write = function (section_id, value) {
698 return handleSectionsVal('set', section_id, 'vpnservice', value);
699 }
700
701 o = s.taboption('vpn', widgets.NetworkSelect, '_vpniface', _('VPN Interface'), _('The logical vpn network interface, e.g. \'wg0\' or \'tun0\'.'));
702 o.unspecified = false;
703 o.nocreate = true;
704 o.optional = true;
705 o.modalonly = true;
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');
711 }
712 o.write = function (section_id, value) {
713 return handleSectionsVal('set', section_id, 'vpniface', value);
714 }
715
716 /*
717 scan buttons
718 */
719 s = m.section(form.GridSection, 'wifi-device');
720 s.anonymous = true;
721 s.addremove = false;
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;
727 if (radio) {
728 btns.push(E('button', {
729 'class': 'cbi-button cbi-button-apply',
730 'id': radio,
731 'click': ui.createHandlerFn(this, 'handleScan', radio)
732 }, [_('Scan on ' + radio + '...')]),
733 '\xa0')
734 }
735 }
736 return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns));
737 }, this))
738 };
739
740 /*
741 modal 'scan' dialog
742 */
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')
752 ])
753 ]);
754 cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan on \'' + radio + '\'...')));
755
756 var md = ui.showModal(_('Wireless Scan'), [
757 table,
758 E('div', { 'class': 'right' }, [
759 E('button', {
760 'class': 'btn',
761 'click': ui.hideModal
762 }, _('Dismiss')),
763 '\xa0',
764 E('button', {
765 'class': 'cbi-button cbi-button-positive important',
766 'click': L.bind(this.handleScan, this, radio)
767 }, _('Repeat Scan'))
768 ])
769 ]);
770
771 md.style.maxWidth = '90%';
772 md.style.maxHeight = 'none';
773
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 = [];
777 if (res) {
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);
789 tbl_ssid = ssid;
790 }
791 else {
792 ssid = "hidden";
793 tbl_ssid = "<em>hidden</em>";
794 }
795 switch (encryption) {
796 case 'WPA3 PSK (SAE)':
797 encryption = 'sae';
798 tbl_encryption = 'WPA3 Pers. (SAE)';
799 break;
800 case 'mixed WPA2/WPA3 PSK/SAE (CCMP)':
801 encryption = 'sae-mixed';
802 tbl_encryption = 'WPA2/WPA3 Pers. (CCMP)';
803 break;
804 case 'WPA2 PSK (CCMP)':
805 encryption = 'psk2+ccmp';
806 tbl_encryption = 'WPA2 Pers. (CCMP)';
807 break;
808 case 'WPA2 PSK (TKIP)':
809 encryption = 'psk2+tkip';
810 tbl_encryption = 'WPA2 Pers. (TKIP)';
811 break;
812 case 'mixed WPA/WPA2 PSK (TKIP, CCMP)':
813 encryption = 'psk-mixed+ccmp';
814 tbl_encryption = 'WPA/WPA2 Pers. (CCMP)';
815 break;
816 case 'WPA PSK (CCMP)':
817 encryption = 'psk2+ccmp';
818 tbl_encryption = 'WPA Pers. (CCMP)';
819 break;
820 case 'WPA PSK (TKIP)':
821 encryption = 'psk2+tkip';
822 tbl_encryption = 'WPA Pers. (TKIP)';
823 break;
824 case 'WPA3 802.1X (CCMP)':
825 encryption = 'wpa3';
826 tbl_encryption = 'WPA3 Ent. (CCMP)';
827 break;
828 case 'mixed WPA2/WPA3 802.1X (CCMP)':
829 encryption = 'wpa3-mixed';
830 tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)';
831 break;
832 case 'WPA2 802.1X':
833 encryption = 'wpa2';
834 tbl_encryption = 'WPA2 Ent.';
835 break;
836 case 'WPA2 802.1X (CCMP)':
837 encryption = 'wpa2+ccmp';
838 tbl_encryption = 'WPA2 Ent. (CCMP)';
839 break;
840 case 'WPA3 OWE (CCMP)':
841 encryption = 'owe';
842 tbl_encryption = 'WPA3 OWE (CCMP)';
843 break;
844 case 'none':
845 encryption = 'none';
846 tbl_encryption = 'none';
847 break;
848 }
849 rows.push([
850 strength,
851 channel,
852 tbl_ssid,
853 bssid,
854 tbl_encryption,
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...')))
859 ]);
860 }
861 }
862 else if (lines[i] === '::: Empty resultset') {
863 rows.push([
864 'No scan results (empty resultset)'
865 ]);
866 }
867 }
868 }
869 else {
870 rows.push([
871 'No scan results (timeout)'
872 ]);
873 }
874 cbi_update_table(table, rows);
875 }, this));
876 };
877
878 /*
879 modal 'add' dialog
880 */
881 s.handleAdd = function (radio, iface, ssid, bssid, encryption, ev) {
882 var m2, s2, o2;
883
884 m2 = new form.Map('wireless'),
885 s2 = m2.section(form.NamedSection, '_add_trm');
886
887 s2.render = function () {
888 return Promise.all([
889 {},
890 this.renderUCISection('_add_trm')
891 ]).then(this.renderContents.bind(this));
892 };
893
894 o2 = s2.option(form.Value, 'device', _('Device Name'));
895 o2.default = radio;
896 o2.readonly = true;
897
898 o2 = s2.option(form.Value, 'network', _('Interface Name'));
899 o2.default = iface;
900 o2.readonly = true;
901
902 if (ssid === "hidden") {
903 o2 = s2.option(form.Value, 'ssid', _('SSID (hidden)'));
904 o2.placeholder = 'hidden SSID';
905 }
906 else {
907 o2 = s2.option(form.Value, 'ssid', _('SSID'));
908 o2.default = ssid;
909 }
910 o2.datatype = 'maxlength(32)';
911 o2.rmempty = false;
912
913 o2 = s2.option(form.Flag, 'ignore_bssid', _('Ignore BSSID'));
914 if (ssid === "hidden") {
915 o2.default = '0';
916 }
917 else {
918 o2.default = '1';
919 }
920
921 o2 = s2.option(form.Value, 'bssid', _('BSSID'));
922 o2.depends({ ignore_bssid: '0' });
923 o2.datatype = 'macaddr';
924 o2.rmempty = true;
925 o2.default = bssid;
926
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;
950
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';
955 o2.password = true;
956
957 o2 = s2.option(form.Value, 'password', _('Password'));
958 o2.depends({ encryption: 'wpa', '!contains': true });
959 o2.datatype = 'wpakey';
960 o2.password = true;
961
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'));
968 o2.default = 'peap';
969
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';
983
984 o2 = s2.option(form.Value, 'identity', _('Identity'));
985 o2.depends({ encryption: 'wpa', '!contains': true });
986
987 o2 = s2.option(form.Value, 'anonymous_identity', _('Anonymous Identity'));
988 o2.depends({ encryption: 'wpa', '!contains': true });
989 o2.rmempty = true;
990
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'));
999 o2.defaults = {
1000 '2': [{ encryption: 'sae' }, { encryption: 'owe' }, { encryption: 'wpa3' }, { encryption: 'wpa3-mixed' }],
1001 '1': [{ encryption: 'sae-mixed' }],
1002 '': []
1003 };
1004
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 });
1007 o2.enabled = '1';
1008 o2.disabled = '0';
1009 o2.default = o.disabled;
1010
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' });
1014 o2.rmempty = true;
1015
1016 o2 = s2.option(form.Value, 'client_cert', _('Path to Client-Certificate'));
1017 o2.depends({ eap_type: 'tls' });
1018 o2.rmempty = true;
1019
1020 o2 = s2.option(form.Value, 'priv_key', _('Path to Private Key'));
1021 o2.depends({ eap_type: 'tls' });
1022 o2.rmempty = true;
1023
1024 o2 = s2.option(form.Value, 'priv_key_pwd', _('Password of Private Key'));
1025 o2.depends({ eap_type: 'tls' });
1026 o2.password = true;
1027 o2.rmempty = true;
1028
1029 return m2.render().then(L.bind(function (elements) {
1030 ui.showModal(_('Add Uplink %q').replace(/%q/, '"%h"'.format(ssid)), [
1031 elements,
1032 E('div', { 'class': 'right' }, [
1033 E('button', {
1034 'class': 'btn',
1035 'click': ui.hideModal
1036 }, _('Dismiss')),
1037 '\xa0',
1038 E('button', {
1039 'class': 'cbi-button cbi-button-positive important',
1040 'click': ui.createHandlerFn(this, 'handleCommit', m2)
1041 }, _('Save'))
1042 ])
1043 ]);
1044 }, this));
1045 };
1046
1047 /*
1048 save new uplink
1049 */
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');
1071 }
1072 } else {
1073 var password = L.toArray(map.lookupOption('key', '_add_trm'))[0].formvalue('_add_trm');
1074 }
1075 if (!ssid || ((encryption.includes('psk') || encryption.includes('wpa') || encryption.includes('sae')) && !password)) {
1076 if (!ssid) {
1077 ui.addNotification(null, E('p', 'Empty SSID, the uplink station could not be saved.'), 'error');
1078 }
1079 else {
1080 ui.addNotification(null, E('p', 'Empty Password, the uplink station could not be saved.'), 'error');
1081 }
1082 return ui.hideModal();
1083 }
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();
1089 }
1090 }
1091 }
1092
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);
1097 }
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);
1105 }
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);
1120 }
1121 } else {
1122 uci.set('wireless', new_sid, 'key', password);
1123 }
1124 uci.set('wireless', new_sid, 'disabled', '1');
1125 handleSectionsAdd(network);
1126 uci.save()
1127 .then(L.bind(this.map.load, this.map))
1128 .then(L.bind(this.map.reset, this.map))
1129 .then(function () {
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;');
1132 })
1133 .then(ui.hideModal)
1134 };
1135 return m.render();
1136 },
1137 handleReset: null
1138 });