9 return fs.lines('/etc/passwd').then(function(lines) {
10 return lines.map(function(line) { return line.split(/:/)[0] });
14 function getGroups() {
15 return fs.lines('/etc/group').then(function(lines) {
16 return lines.map(function(line) { return line.split(/:/)[0] });
20 var CBIZoneSelect = form.ListValue.extend({
21 __name__: 'CBI.ZoneSelect',
23 load: function(section_id) {
24 return Promise.all([ firewall.getZones(), network.getNetworks() ]).then(L.bind(function(zn) {
26 this.networks = zn[1];
28 return this.super('load', section_id);
32 filter: function(section_id, value) {
36 lookupZone: function(name) {
37 return this.zones.filter(function(zone) { return zone.getName() == name })[0];
40 lookupNetwork: function(name) {
41 return this.networks.filter(function(network) { return network.getName() == name })[0];
44 renderWidget: function(section_id, option_index, cfgvalue) {
45 var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
49 if (this.option == 'dest') {
50 for (var i = 0; i < this.section.children.length; i++) {
51 var opt = this.section.children[i];
52 if (opt.option == 'src') {
53 var val = opt.cfgvalue(section_id) || opt.default;
54 isOutputOnly = (val == null || val == '');
59 this.title = isOutputOnly ? _('Output zone') : _('Destination zone');
62 if (this.allowlocal) {
63 choices[''] = E('span', {
65 'style': 'background-color:' + firewall.getColorForName(null)
67 E('strong', _('Device')),
68 (this.allowany || this.allowlocal)
69 ? ' (%s)'.format(this.option != 'dest' ? _('output') : _('input')) : ''
72 else if (!this.multiple && (this.rmempty || this.optional)) {
73 choices[''] = E('span', {
75 'style': 'background-color:' + firewall.getColorForName(null)
76 }, E('em', _('unspecified')));
80 choices['*'] = E('span', {
82 'style': 'background-color:' + firewall.getColorForName(null)
84 E('strong', _('Any zone')),
85 (this.allowany && this.allowlocal && !isOutputOnly) ? ' (%s)'.format(_('forward')) : ''
89 for (var i = 0; i < this.zones.length; i++) {
90 var zone = this.zones[i],
91 name = zone.getName(),
92 networks = zone.getNetworks(),
95 if (!this.filter(section_id, name))
98 for (var j = 0; j < networks.length; j++) {
99 var network = this.lookupNetwork(networks[j]);
104 var span = E('span', {
105 'class': 'ifacebadge' + (network.getName() == this.network ? ' ifacebadge-active' : '')
106 }, network.getName() + ': ');
108 var devices = network.isBridge() ? network.getDevices() : L.toArray(network.getDevice());
110 for (var k = 0; k < devices.length; k++) {
111 span.appendChild(E('img', {
112 'title': devices[k].getI18n(),
113 'src': L.resource('icons/%s%s.png'.format(devices[k].getType(), devices[k].isUp() ? '' : '_disabled'))
118 span.appendChild(E('em', _('(empty)')));
124 ifaces.push(E('em', _('(empty)')));
126 choices[name] = E('span', {
127 'class': 'zonebadge',
128 'style': 'background-color:' + zone.getColor()
129 }, [ E('strong', name) ].concat(ifaces));
132 var widget = new ui.Dropdown(values, choices, {
133 id: this.cbid(section_id),
135 multiple: this.multiple,
136 optional: this.optional || this.rmempty,
137 disabled: (this.readonly != null) ? this.readonly : this.map.readonly,
138 select_placeholder: E('em', _('unspecified')),
139 display_items: this.display_size || this.size || 3,
140 dropdown_items: this.dropdown_size || this.size || 5,
141 validate: L.bind(this.validate, this, section_id),
142 create: !this.nocreate,
144 '<li data-value="{{value}}">' +
145 '<span class="zonebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">' +
146 '<strong>{{value}}:</strong> <em>('+_('create')+')</em>' +
151 var elem = widget.render();
153 if (this.option == 'src') {
154 elem.addEventListener('cbi-dropdown-change', L.bind(function(ev) {
155 var opt = this.map.lookupOption('dest', section_id),
156 val = ev.detail.instance.getValue();
161 var cbid = opt[0].cbid(section_id),
162 label = document.querySelector('label[for="widget.%s"]'.format(cbid)),
163 node = document.getElementById(cbid);
165 L.dom.content(label, val == '' ? _('Output zone') : _('Destination zone'));
168 if (L.dom.callClassMethod(node, 'getValue') == '')
169 L.dom.callClassMethod(node, 'setValue', '*');
171 var emptyval = node.querySelector('[data-value=""]'),
172 anyval = node.querySelector('[data-value="*"]');
174 L.dom.content(anyval.querySelector('span'), E('strong', _('Any zone')));
176 if (emptyval != null)
177 emptyval.parentNode.removeChild(emptyval);
180 var anyval = node.querySelector('[data-value="*"]'),
181 emptyval = node.querySelector('[data-value=""]');
183 if (emptyval == null) {
184 emptyval = anyval.cloneNode(true);
185 emptyval.removeAttribute('display');
186 emptyval.removeAttribute('selected');
187 emptyval.setAttribute('data-value', '');
190 L.dom.content(emptyval.querySelector('span'), [
191 E('strong', _('Device')), ' (%s)'.format(_('input'))
194 L.dom.content(anyval.querySelector('span'), [
195 E('strong', _('Any zone')), ' (%s)'.format(_('forward'))
198 anyval.parentNode.insertBefore(emptyval, anyval);
203 else if (isOutputOnly) {
204 var emptyval = elem.querySelector('[data-value=""]');
205 emptyval.parentNode.removeChild(emptyval);
212 var CBIZoneForwards = form.DummyValue.extend({
213 __name__: 'CBI.ZoneForwards',
215 load: function(section_id) {
217 firewall.getDefaults(),
219 network.getNetworks(),
221 ]).then(L.bind(function(dznd) {
222 this.defaults = dznd[0];
223 this.zones = dznd[1];
224 this.networks = dznd[2];
225 this.devices = dznd[3];
227 return this.super('load', section_id);
231 renderZone: function(zone) {
232 var name = zone.getName(),
233 networks = zone.getNetworks(),
234 devices = zone.getDevices(),
235 subnets = zone.getSubnets(),
238 for (var j = 0; j < networks.length; j++) {
239 var network = this.networks.filter(function(net) { return net.getName() == networks[j] })[0];
244 var span = E('span', {
245 'class': 'ifacebadge' + (network.getName() == this.network ? ' ifacebadge-active' : '')
246 }, network.getName() + ': ');
248 var subdevs = network.isBridge() ? network.getDevices() : L.toArray(network.getDevice());
250 for (var k = 0; k < subdevs.length && subdevs[k]; k++) {
251 span.appendChild(E('img', {
252 'title': subdevs[k].getI18n(),
253 'src': L.resource('icons/%s%s.png'.format(subdevs[k].getType(), subdevs[k].isUp() ? '' : '_disabled'))
258 span.appendChild(E('em', _('(empty)')));
263 for (var i = 0; i < devices.length; i++) {
264 var device = this.devices.filter(function(dev) { return dev.getName() == devices[i] })[0],
265 title = device ? device.getI18n() : _('Absent Interface'),
266 type = device ? device.getType() : 'ethernet',
267 up = device ? device.isUp() : false;
269 ifaces.push(E('span', { 'class': 'ifacebadge' }, [
272 'src': L.resource('icons/%s%s.png'.format(type, up ? '' : '_disabled'))
274 device ? device.getName() : devices[i]
278 if (subnets.length > 0)
279 ifaces.push(E('span', { 'class': 'ifacebadge' }, [ '{ %s }'.format(subnets.join('; ')) ]));
282 ifaces.push(E('span', { 'class': 'ifacebadge' }, E('em', _('(empty)'))));
285 'class': 'zonebadge cbi-tooltip-container',
286 'style': 'background-color:' + zone.getColor()
289 E('div', { 'class': 'cbi-tooltip' }, ifaces)
293 renderWidget: function(section_id, option_index, cfgvalue) {
294 var value = (cfgvalue != null) ? cfgvalue : this.default,
295 zone = this.zones.filter(function(z) { return z.getName() == value })[0];
300 var forwards = zone.getForwardingsBy('src'),
303 for (var i = 0; i < forwards.length; i++) {
304 var dzone = forwards[i].getDestinationZone();
309 dzones.push(this.renderZone(dzone));
313 dzones.push(E('label', { 'class': 'zonebadge zonebadge-empty' },
314 E('strong', this.defaults.getForward())));
316 return E('div', { 'class': 'zone-forwards' }, [
317 E('div', { 'class': 'zone-src' }, this.renderZone(zone)),
319 E('div', { 'class': 'zone-dest' }, dzones)
324 var CBINetworkSelect = form.ListValue.extend({
325 __name__: 'CBI.NetworkSelect',
327 load: function(section_id) {
328 return network.getNetworks().then(L.bind(function(networks) {
329 this.networks = networks;
331 return this.super('load', section_id);
335 filter: function(section_id, value) {
339 renderIfaceBadge: function(network) {
340 var span = E('span', { 'class': 'ifacebadge' }, network.getName() + ': '),
341 devices = network.isBridge() ? network.getDevices() : L.toArray(network.getDevice());
343 for (var j = 0; j < devices.length && devices[j]; j++) {
344 span.appendChild(E('img', {
345 'title': devices[j].getI18n(),
346 'src': L.resource('icons/%s%s.png'.format(devices[j].getType(), devices[j].isUp() ? '' : '_disabled'))
350 if (!devices.length) {
351 span.appendChild(E('em', { 'class': 'hide-close' }, _('(no interfaces attached)')));
352 span.appendChild(E('em', { 'class': 'hide-open' }, '-'));
358 renderWidget: function(section_id, option_index, cfgvalue) {
359 var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
363 for (var i = 0; i < values.length; i++)
364 checked[values[i]] = true;
368 if (!this.multiple && (this.rmempty || this.optional))
369 choices[''] = E('em', _('unspecified'));
371 for (var i = 0; i < this.networks.length; i++) {
372 var network = this.networks[i],
373 name = network.getName();
375 if (name == 'loopback' || name == this.exclude || !this.filter(section_id, name))
378 if (this.novirtual && network.isVirtual())
384 choices[name] = this.renderIfaceBadge(network);
387 var widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
388 id: this.cbid(section_id),
390 multiple: this.multiple,
391 optional: this.optional || this.rmempty,
392 disabled: (this.readonly != null) ? this.readonly : this.map.readonly,
393 select_placeholder: E('em', _('unspecified')),
394 display_items: this.display_size || this.size || 3,
395 dropdown_items: this.dropdown_size || this.size || 5,
396 validate: L.bind(this.validate, this, section_id),
397 create: !this.nocreate,
399 '<li data-value="{{value}}">' +
400 '<span class="ifacebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">' +
401 '{{value}}: <em>('+_('create')+')</em>' +
406 return widget.render();
409 textvalue: function(section_id) {
410 var cfgvalue = this.cfgvalue(section_id),
411 values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
414 for (var i = 0; i < (this.networks || []).length; i++) {
415 var network = this.networks[i],
416 name = network.getName();
418 if (values.indexOf(name) == -1)
422 L.dom.append(rv, ' ');
424 L.dom.append(rv, this.renderIfaceBadge(network));
428 rv.appendChild(E('em', _('unspecified')));
434 var CBIDeviceSelect = form.ListValue.extend({
435 __name__: 'CBI.DeviceSelect',
437 load: function(section_id) {
439 network.getDevices(),
440 this.noaliases ? null : network.getNetworks()
441 ]).then(L.bind(function(data) {
442 this.devices = data[0];
443 this.networks = data[1];
445 return this.super('load', section_id);
449 filter: function(section_id, value) {
453 renderWidget: function(section_id, option_index, cfgvalue) {
454 var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
459 for (var i = 0; i < values.length; i++)
460 checked[values[i]] = true;
464 if (!this.multiple && (this.rmempty || this.optional))
465 choices[''] = E('em', _('unspecified'));
467 for (var i = 0; i < this.devices.length; i++) {
468 var device = this.devices[i],
469 name = device.getName(),
470 type = device.getType();
472 if (name == 'lo' || name == this.exclude || !this.filter(section_id, name))
475 if (this.noaliases && type == 'alias')
478 if (this.nobridges && type == 'bridge')
481 if (this.noinactive && device.isUp() == false)
486 'title': device.getI18n(),
487 'src': L.resource('icons/%s%s.png'.format(type, device.isUp() ? '' : '_disabled'))
489 E('span', { 'class': 'hide-open' }, [ name ]),
490 E('span', { 'class': 'hide-close'}, [ device.getI18n() ])
493 var networks = device.getNetworks();
495 if (networks.length > 0)
496 L.dom.append(item.lastChild, [ ' (', networks.map(function(n) { return n.getName() }).join(', '), ')' ]);
501 choices[name] = item;
505 if (this.networks != null) {
506 for (var i = 0; i < this.networks.length; i++) {
507 var net = this.networks[i],
508 device = network.instantiateDevice('@%s'.format(net.getName()), net),
509 name = device.getName();
511 if (name == '@loopback' || name == this.exclude || !this.filter(section_id, name))
514 if (this.noinactive && net.isUp() == false)
519 'title': device.getI18n(),
520 'src': L.resource('icons/alias%s.png'.format(net.isUp() ? '' : '_disabled'))
522 E('span', { 'class': 'hide-open' }, [ name ]),
523 E('span', { 'class': 'hide-close'}, [ device.getI18n() ])
529 choices[name] = item;
534 if (!this.nocreate) {
535 var keys = Object.keys(checked).sort();
537 for (var i = 0; i < keys.length; i++) {
538 if (choices.hasOwnProperty(keys[i]))
541 choices[keys[i]] = E([
543 'title': _('Absent Interface'),
544 'src': L.resource('icons/ethernet_disabled.png')
546 E('span', { 'class': 'hide-open' }, [ keys[i] ]),
547 E('span', { 'class': 'hide-close'}, [ '%s: "%h"'.format(_('Absent Interface'), keys[i]) ])
550 values.push(keys[i]);
555 var widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
556 id: this.cbid(section_id),
558 multiple: this.multiple,
559 optional: this.optional || this.rmempty,
560 disabled: (this.readonly != null) ? this.readonly : this.map.readonly,
561 select_placeholder: E('em', _('unspecified')),
562 display_items: this.display_size || this.size || 3,
563 dropdown_items: this.dropdown_size || this.size || 5,
564 validate: L.bind(this.validate, this, section_id),
565 create: !this.nocreate,
567 '<li data-value="{{value}}">' +
568 '<img title="'+_('Custom Interface')+': "{{value}}"" src="'+L.resource('icons/ethernet_disabled.png')+'" />' +
569 '<span class="hide-open">{{value}}</span>' +
570 '<span class="hide-close">'+_('Custom Interface')+': "{{value}}"</span>' +
574 return widget.render();
578 var CBIUserSelect = form.ListValue.extend({
579 __name__: 'CBI.UserSelect',
581 load: function(section_id) {
582 return getUsers().then(L.bind(function(users) {
583 for (var i = 0; i < users.length; i++) {
584 this.value(users[i]);
587 return this.super('load', section_id);
591 filter: function(section_id, value) {
596 var CBIGroupSelect = form.ListValue.extend({
597 __name__: 'CBI.GroupSelect',
599 load: function(section_id) {
600 return getGroups().then(L.bind(function(groups) {
601 for (var i = 0; i < groups.length; i++) {
602 this.value(groups[i]);
605 return this.super('load', section_id);
609 filter: function(section_id, value) {
615 return L.Class.extend({
616 ZoneSelect: CBIZoneSelect,
617 ZoneForwards: CBIZoneForwards,
618 NetworkSelect: CBINetworkSelect,
619 DeviceSelect: CBIDeviceSelect,
620 UserSelect: CBIUserSelect,
621 GroupSelect: CBIGroupSelect,