});
},
- getProcessList: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'process_list',
- expect: { processes: [ ] },
- filter: function(data) {
- data.sort(function(a, b) { return a.pid - b.pid });
- return data;
- }
- }),
-
- getSystemLog: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'syslog',
- expect: { log: '' }
- }),
-
- getKernelLog: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'dmesg',
- expect: { log: '' }
- }),
-
- getZoneInfo: function(cb)
- {
- return $.getJSON(_luci2.globals.resource + '/zoneinfo.json', cb);
- },
-
- sendSignal: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'process_signal',
- params: [ 'pid', 'signal' ],
- filter: function(data) {
- return (data == 0);
- }
- }),
initList: _luci2.rpc.declare({
object: 'luci2.system',
initDisable: function(init, cb) { return _luci2.system.initRun(init, 'disable', cb) },
- getRcLocal: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'rclocal_get',
- expect: { data: '' }
- }),
-
- setRcLocal: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'rclocal_set',
- params: [ 'data' ]
- }),
-
-
- getCrontab: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'crontab_get',
- expect: { data: '' }
- }),
-
- setCrontab: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'crontab_set',
- params: [ 'data' ]
- }),
-
-
- getSSHKeys: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'sshkeys_get',
- expect: { keys: [ ] }
- }),
-
- setSSHKeys: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'sshkeys_set',
- params: [ 'keys' ]
- }),
-
-
- setPassword: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'password_set',
- params: [ 'user', 'password' ]
- }),
-
-
- listLEDs: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'led_list',
- expect: { leds: [ ] }
- }),
-
- listUSBDevices: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'usb_list',
- expect: { devices: [ ] }
- }),
-
-
- testUpgrade: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'upgrade_test',
- expect: { '': { } }
- }),
-
- startUpgrade: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'upgrade_start',
- params: [ 'keep' ]
- }),
-
- cleanUpgrade: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'upgrade_clean'
- }),
-
-
- restoreBackup: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'backup_restore'
- }),
-
- cleanBackup: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'backup_clean'
- }),
-
-
- getBackupConfig: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'backup_config_get',
- expect: { config: '' }
- }),
-
- setBackupConfig: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'backup_config_set',
- params: [ 'data' ]
- }),
-
-
- listBackup: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'backup_list',
- expect: { files: [ ] }
- }),
-
-
- testReset: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'reset_test',
- expect: { supported: false }
- }),
-
- startReset: _luci2.rpc.declare({
- object: 'luci2.system',
- method: 'reset_start'
- }),
-
-
performReboot: _luci2.rpc.declare({
object: 'luci2.system',
method: 'reboot'
})
};
- this.opkg = {
- updateLists: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'update',
- expect: { '': { } }
- }),
-
- _allPackages: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'list',
- params: [ 'offset', 'limit', 'pattern' ],
- expect: { '': { } }
- }),
-
- _installedPackages: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'list_installed',
- params: [ 'offset', 'limit', 'pattern' ],
- expect: { '': { } }
- }),
-
- _findPackages: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'find',
- params: [ 'offset', 'limit', 'pattern' ],
- expect: { '': { } }
- }),
-
- _fetchPackages: function(action, offset, limit, pattern)
- {
- var packages = [ ];
-
- return action(offset, limit, pattern).then(function(list) {
- if (!list.total || !list.packages)
- return { length: 0, total: 0 };
-
- packages.push.apply(packages, list.packages);
- packages.total = list.total;
-
- if (limit <= 0)
- limit = list.total;
-
- if (packages.length >= limit)
- return packages;
-
- _luci2.rpc.batch();
-
- for (var i = offset + packages.length; i < limit; i += 100)
- action(i, (Math.min(i + 100, limit) % 100) || 100, pattern);
-
- return _luci2.rpc.flush();
- }).then(function(lists) {
- for (var i = 0; i < lists.length; i++)
- {
- if (!lists[i].total || !lists[i].packages)
- continue;
-
- packages.push.apply(packages, lists[i].packages);
- packages.total = lists[i].total;
- }
-
- return packages;
- });
- },
-
- listPackages: function(offset, limit, pattern)
- {
- return _luci2.opkg._fetchPackages(_luci2.opkg._allPackages, offset, limit, pattern);
- },
-
- installedPackages: function(offset, limit, pattern)
- {
- return _luci2.opkg._fetchPackages(_luci2.opkg._installedPackages, offset, limit, pattern);
- },
-
- findPackages: function(offset, limit, pattern)
- {
- return _luci2.opkg._fetchPackages(_luci2.opkg._findPackages, offset, limit, pattern);
- },
-
- installPackage: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'install',
- params: [ 'package' ],
- expect: { '': { } }
- }),
-
- removePackage: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'remove',
- params: [ 'package' ],
- expect: { '': { } }
- }),
-
- getConfig: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'config_get',
- expect: { config: '' }
- }),
-
- setConfig: _luci2.rpc.declare({
- object: 'luci2.opkg',
- method: 'config_set',
- params: [ 'data' ]
- })
- };
-
this.session = {
login: _luci2.rpc.declare({
L.ui.view.extend({
title: L.tr('Diagnostics'),
+ runPing: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'ping',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runPing6: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'ping6',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runTraceroute: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'traceroute',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runTraceroute6: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'traceroute6',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runNslookup: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'nslookup',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
execute: function() {
var self = this;
var tools = [ ];
$.when(
- L.network.runPing('?').then(function(rv) {
+ self.runPing('?').then(function(rv) {
if (rv.code != -1) tools.push(['runPing', L.tr('IPv4 Ping')]);
}),
- L.network.runPing6('?').then(function(rv) {
+ self.runPing6('?').then(function(rv) {
if (rv.code != -1) tools.push(['runPing6', L.tr('IPv6 Ping')]);
}),
- L.network.runTraceroute('?').then(function(rv) {
+ self.runTraceroute('?').then(function(rv) {
if (rv.code != -1) tools.push(['runTraceroute', L.tr('IPv4 Traceroute')]);
}),
- L.network.runTraceroute6('?').then(function(rv) {
+ self.runTraceroute6('?').then(function(rv) {
if (rv.code != -1) tools.push(['runTraceroute6', L.tr('IPv6 Tracroute')]);
}),
- L.network.runNslookup('?').then(function(rv) {
+ self.runNslookup('?').then(function(rv) {
if (rv.code != -1) tools.push(['runNslookup', L.tr('DNS Lookup')]);
})
).then(function() {
$('#run').click(function() {
L.ui.loading(true);
- L.network[$('#tool').val()]($('#host').val()).then(function(rv) {
+ self[$('#tool').val()]($('#host').val()).then(function(rv) {
$('#output').empty().show();
if (rv.stdout)
L.ui.view.extend({
- title: L.tr('Hostnames'),
- description: L.tr('Manage static host records to let the local DNS server resolve certain names to specific IP addresses.'),
+ title: L.tr('Hostnames'),
+ description: L.tr('Manage static host records to let the local DNS server resolve certain names to specific IP addresses.'),
- execute: function() {
- var m = new L.cbi.Map('dhcp', {
- readonly: !this.options.acls.hostnames
- });
+ execute: function() {
+ var m = new L.cbi.Map('dhcp', {
+ readonly: !this.options.acls.hostnames
+ });
- var s = m.section(L.cbi.TableSection, 'domain', {
- anonymous: true,
- addremove: true,
- add_caption: L.tr('Add new hostname'),
- remove_caption: L.tr('Remove hostname')
- });
+ var s = m.section(L.cbi.TableSection, 'domain', {
+ anonymous: true,
+ addremove: true,
+ add_caption: L.tr('Add new hostname'),
+ remove_caption: L.tr('Remove hostname')
+ });
- s.option(L.cbi.InputValue, 'name', {
- caption: L.tr('Hostname'),
- datatype: 'hostname'
- });
+ s.option(L.cbi.InputValue, 'name', {
+ caption: L.tr('Hostname'),
+ datatype: 'hostname'
+ });
- s.option(L.cbi.InputValue, 'ip', {
- caption: L.tr('IP address'),
- datatype: 'ipaddr'
- });
+ s.option(L.cbi.InputValue, 'ip', {
+ caption: L.tr('IP address'),
+ datatype: 'ipaddr'
+ });
- return m.insertInto('#map');
- }
+ return m.insertInto('#map');
+ }
});
L.ui.view.extend({
- title: L.tr('Routes'),
- description: L.tr('Routes specify over which interface and gateway a certain host or network can be reached.'),
-
- execute: function() {
- var self = this;
- return L.network.listNetworkNames().then(function(list) {
- var m = new L.cbi.Map('network', {
- readonly: !self.options.acls.network
- });
-
- var s4 = m.section(L.cbi.TableSection, 'route', {
- caption: L.tr('Static IPv4 Routes'),
- anonymous: true,
- addremove: true,
- sortable: true,
- add_caption: L.tr('Add new route'),
- remove_caption: L.tr('Remove route')
- });
-
- var ifc = s4.option(L.cbi.ListValue, 'interface', {
- caption: L.tr('Interface')
- });
-
- for (var i = 0; i < list.length; i++)
- ifc.value(list[i]);
-
- s4.option(L.cbi.InputValue, 'target', {
- caption: L.tr('Target'),
- datatype: 'ip4addr'
- });
-
- s4.option(L.cbi.InputValue, 'netmask', {
- caption: L.tr('IPv4-Netmask'),
- datatype: 'ip4addr',
- placeholder: '255.255.255.255',
- optional: true
- });
-
- s4.option(L.cbi.InputValue, 'gateway', {
- caption: L.tr('IPv4-Gateway'),
- datatype: 'ip4addr',
- optional: true
- });
-
- s4.option(L.cbi.InputValue, 'metric', {
- caption: L.tr('Metric'),
- datatype: 'range(0,255)',
- placeholder: 0,
- optional: true
- });
-
- s4.option(L.cbi.InputValue, 'mtu', {
- caption: L.tr('MTU'),
- datatype: 'range(64,9000)',
- placeholder: 1500,
- optional: true
- });
-
-
- var s6 = m.section(L.cbi.TableSection, 'route6', {
- caption: L.tr('Static IPv6 Routes'),
- anonymous: true,
- addremove: true,
- sortable: true,
- add_caption: L.tr('Add new route'),
- remove_caption: L.tr('Remove route')
- });
-
- var ifc = s6.option(L.cbi.ListValue, 'interface', {
- caption: L.tr('Interface')
- });
-
- for (var i = 0; i < list.length; i++)
- ifc.value(list[i]);
-
- s6.option(L.cbi.InputValue, 'target', {
- caption: L.tr('Target'),
- datatype: 'ip6addr'
- });
-
- s6.option(L.cbi.InputValue, 'gateway', {
- caption: L.tr('IPv6-Gateway'),
- datatype: 'ip6addr',
- optional: true
- });
-
- s6.option(L.cbi.InputValue, 'metric', {
- caption: L.tr('Metric'),
- datatype: 'range(0,255)',
- placeholder: 0,
- optional: true
- });
-
- s6.option(L.cbi.InputValue, 'mtu', {
- caption: L.tr('MTU'),
- datatype: 'range(64,9000)',
- placeholder: 1500,
- optional: true
- });
-
- m.insertInto('#map');
- });
- }
+ title: L.tr('Routes'),
+ description: L.tr('Routes specify over which interface and gateway a certain host or network can be reached.'),
+
+ execute: function() {
+ var self = this;
+ var ifaces = L.NetworkModel.getInterfaces();
+
+ var m = new L.cbi.Map('network', {
+ readonly: !self.options.acls.network
+ });
+
+ var s4 = m.section(L.cbi.TableSection, 'route', {
+ caption: L.tr('Static IPv4 Routes'),
+ anonymous: true,
+ addremove: true,
+ sortable: true,
+ add_caption: L.tr('Add new route'),
+ remove_caption: L.tr('Remove route')
+ });
+
+ var ifc = s4.option(L.cbi.ListValue, 'interface', {
+ caption: L.tr('Interface')
+ });
+
+ for (var i = 0; i < ifaces.length; i++)
+ ifc.value(ifaces[i].name());
+
+ s4.option(L.cbi.InputValue, 'target', {
+ caption: L.tr('Target'),
+ datatype: 'ip4addr'
+ });
+
+ s4.option(L.cbi.InputValue, 'netmask', {
+ caption: L.tr('IPv4-Netmask'),
+ datatype: 'ip4addr',
+ placeholder: '255.255.255.255',
+ optional: true
+ });
+
+ s4.option(L.cbi.InputValue, 'gateway', {
+ caption: L.tr('IPv4-Gateway'),
+ datatype: 'ip4addr',
+ optional: true
+ });
+
+ s4.option(L.cbi.InputValue, 'metric', {
+ caption: L.tr('Metric'),
+ datatype: 'range(0,255)',
+ placeholder: 0,
+ optional: true
+ });
+
+ s4.option(L.cbi.InputValue, 'mtu', {
+ caption: L.tr('MTU'),
+ datatype: 'range(64,9000)',
+ placeholder: 1500,
+ optional: true
+ });
+
+
+ var s6 = m.section(L.cbi.TableSection, 'route6', {
+ caption: L.tr('Static IPv6 Routes'),
+ anonymous: true,
+ addremove: true,
+ sortable: true,
+ add_caption: L.tr('Add new route'),
+ remove_caption: L.tr('Remove route')
+ });
+
+ var ifc = s6.option(L.cbi.ListValue, 'interface', {
+ caption: L.tr('Interface')
+ });
+
+ for (var i = 0; i < ifaces.length; i++)
+ ifc.value(ifaces[i].name());
+
+ s6.option(L.cbi.InputValue, 'target', {
+ caption: L.tr('Target'),
+ datatype: 'ip6addr'
+ });
+
+ s6.option(L.cbi.InputValue, 'gateway', {
+ caption: L.tr('IPv6-Gateway'),
+ datatype: 'ip6addr',
+ optional: true
+ });
+
+ s6.option(L.cbi.InputValue, 'metric', {
+ caption: L.tr('Metric'),
+ datatype: 'range(0,255)',
+ placeholder: 0,
+ optional: true
+ });
+
+ s6.option(L.cbi.InputValue, 'mtu', {
+ caption: L.tr('MTU'),
+ datatype: 'range(64,9000)',
+ placeholder: 1500,
+ optional: true
+ });
+
+ m.insertInto('#map');
+ }
});
title: L.tr('Switch'),
description: L.tr('The network ports on this device can be combined to several VLANs in which computers can communicate directly with each other. VLANs are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network.'),
+ listSwitchNames: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'switch_list',
+ expect: { switches: [ ] }
+ }),
+
+ getSwitchInfo: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'switch_info',
+ params: [ 'switch' ],
+ expect: { info: { } },
+ filter: function(data, params) {
+ data['attrs'] = data['switch'];
+ data['vlan_attrs'] = data['vlan'];
+ data['port_attrs'] = data['port'];
+ data['switch'] = params['switch'];
+
+ delete data.vlan;
+ delete data.port;
+
+ return data;
+ }
+ }),
+
+ getSwitchStatus: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'switch_status',
+ params: [ 'switch' ],
+ expect: { ports: [ ] }
+ }),
+
switchPortState: L.cbi.ListValue.extend({
choices: [
[ 'n', L.trc('Switch port state', 'off') ],
execute: function() {
var self = this;
- return L.network.listSwitchNames().then(function(switches) {
+ return self.listSwitchNames().then(function(switches) {
L.rpc.batch();
for (var i = 0; i < switches.length; i++)
- L.network.getSwitchInfo(switches[i]);
+ self.getSwitchInfo(switches[i]);
return L.rpc.flush();
}).then(function(switches) {
}
return m.insertInto('#map').then(function() {
- self.repeat(function() {
- return L.network.getSwitchStatus(swname).then(function(ports) {
- for (var j = 0; j < ports.length; j++)
- {
- var s = L.tr('No link');
- var d = ' ';
-
- if (ports[j].link)
- {
- s = '%dbaseT'.format(ports[j].speed);
- d = ports[j].full_duplex ? L.tr('Full-duplex') : L.tr('Half-duplex');
- }
-
- $('#portstatus-%s-%d'.format(swname, j))
- .empty().append(s + '<br />' + d);
- }
- });
- }, 5000);
- });
+ self.repeat(function() {
+ return self.getSwitchStatus(swname).then(function(ports) {
+ for (var j = 0; j < ports.length; j++)
+ {
+ var s = L.tr('No link');
+ var d = ' ';
+
+ if (ports[j].link)
+ {
+ s = '%dbaseT'.format(ports[j].speed);
+ d = ports[j].full_duplex ? L.tr('Full-duplex') : L.tr('Half-duplex');
+ }
+
+ $('#portstatus-%s-%d'.format(swname, j))
+ .empty().append(s + '<br />' + d);
+ }
+ });
+ }, 5000);
+ });
});
}
});
L.ui.view.extend({
- title: L.tr('Kernel Log'),
- refresh: 5000,
- execute: function() {
- return L.system.getKernelLog().then(function(log) {
- var ta = document.getElementById('syslog');
- var lines = log.replace(/\n+$/, '').split(/\n/);
+ title: L.tr('Kernel Log'),
+ refresh: 5000,
- ta.rows = lines.length;
- ta.value = lines.reverse().join("\n");
- });
- }
+ getKernelLog: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'dmesg',
+ expect: { log: '' }
+ }),
+
+ execute: function() {
+ return this.getKernelLog().then(function(log) {
+ var ta = document.getElementById('syslog');
+ var lines = log.replace(/\n+$/, '').split(/\n/);
+
+ ta.rows = lines.length;
+ ta.value = lines.reverse().join("\n");
+ });
+ }
});
L.ui.view.extend({
title: L.tr('Status'),
- execute: function() {
+
+ getConntrackCount: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'conntrack_count',
+ expect: { '': { count: 0, limit: 0 } }
+ }),
+
+ getDHCPLeases: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'dhcp_leases',
+ expect: { leases: [ ] }
+ }),
+
+ getDHCPv6Leases: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'dhcp6_leases',
+ expect: { leases: [ ] }
+ }),
+
+ renderContents: function() {
+ var self = this;
return $.when(
- L.network.findWanInterfaces().then(function(wans) {
- var wan = wans[0];
- var wan6 = wans[1];
+ L.NetworkModel.refreshStatus().then(function() {
+ var wan = L.NetworkModel.findWAN();
+ var wan6 = L.NetworkModel.findWAN6();
if (!wan && !wan6)
{
width: '146px',
align: 'right',
format: function(v) {
- return new L.ui.devicebadge(v).render();
+ var dev = L.NetworkModel.resolveAlias(v.getDevice());
+ if (dev)
+ return $('<span />')
+ .addClass('badge')
+ .attr('title', dev.description())
+ .append($('<img />').attr('src', dev.icon()))
+ .append(' %s'.format(dev.name()));
+
+ return '';
}
}, {
format: function(v, n) {
- var format_addr = function()
- {
- var rv = [ ];
- if (n > 0)
- {
- for (var i = 0; i < v['ipv6-address'].length; i++)
- rv.push('%s/%d'.format(v['ipv6-address'][i].address, v['ipv6-address'][i].mask));
-
- for (var i = 0; i < v['ipv6-prefix-assignment'].length; i++)
- rv.push('%s1/%d'.format(v['ipv6-prefix-assignment'][i].address, v['ipv6-prefix-assignment'][i].mask));
- }
- else
- {
- for (var i = 0; i < v['ipv4-address'].length; i++)
- rv.push('%s/%d'.format(v['ipv4-address'][i].address, v['ipv4-address'][i].mask));
- }
- return rv.join(', ');
- };
-
- var format_dns = function()
- {
- var rv = [ ];
- for (var i = 0; i < v['dns-server'].length; i++)
- {
- if ((n > 0 && v['dns-server'][i].indexOf(':') > -1) ||
- (n == 0 && v['dns-server'][i].indexOf(':') == -1))
- rv.push(v['dns-server'][i]);
- }
- return rv.join(', ');
- };
-
var s = '<strong>' + L.tr('Type') + ':</strong> %s | ' +
- '<strong>' + L.tr('Connected') + ':</strong> %t<br />' +
- '<strong>' + L.tr('Address') + ':</strong> %s<br />';
+ '<strong>' + L.tr('Connected') + ':</strong> %t<br />';
- s = s.format(v.proto, v.uptime, format_addr());
+ s = s.format(v.getProtocol().description, v.getUptime(),
+ n ? v.getIPv6Addrs(true).join(', ')
+ : v.getIPv4Addrs(true).join(', '));
- for (var i = 0; i < v.route.length; i++)
- if (v.route[i].mask == 0 && v.route[i].nexthop != '::')
- {
- s += '<strong>' + L.tr('Gateway') + ':</strong> %s<br />'.format(v.route[i].nexthop);
- break;
- }
+ var addr = n ? v.getIPv6Addrs() : v.getIPv4Addrs();
+ if (addr.length)
+ s += '<strong>' + L.tr('Address') + ':</strong> %s<br />'.format(addr.join(', '));
+
+ var gw = v.getIPv4Gateway();
+ if (gw)
+ s += '<strong>' + L.tr('Gateway') + ':</strong> %s<br />'.format(gw);
- var dns = format_dns();
- if (dns)
- s += '<strong>' + L.tr('DNS') + ':</strong> %s<br />'.format(dns);
+ var dns = n ? v.getIPv6DNS() : v.getIPv4DNS();
+ if (dns.length)
+ s += '<strong>' + L.tr('DNS') + ':</strong> %s<br />'.format(dns.join(', '));
return s;
}
networkTable.insertInto('#network_status_table');
}),
- L.network.getConntrackCount().then(function(count) {
+ self.getConntrackCount().then(function(count) {
var conntrackTable = new L.ui.table({
caption: L.tr('Connection Tracking'),
columns: [ {
assocTable.rows(assoclist);
assocTable.insertInto('#wifi_assoc_table');
}),
- L.network.getDHCPLeases().then(function(leases) {
+ self.getDHCPLeases().then(function(leases) {
var leaseTable = new L.ui.table({
caption: L.tr('DHCP Leases'),
placeholder: L.tr('There are no active leases.'),
leaseTable.rows(leases);
leaseTable.insertInto('#lease_status_table');
}),
- L.network.getDHCPv6Leases().then(function(leases) {
+ self.getDHCPv6Leases().then(function(leases) {
if (!leases.length)
return;
leaseTable.insertInto('#lease6_status_table');
})
)
+ },
+
+ execute: function()
+ {
+ var self = this;
+ return L.NetworkModel.init().then(function() {
+ self.repeat(self.renderContents, 5000);
+ });
}
});
L.ui.view.extend({
- title: L.tr('Processes'),
- description: L.tr('This list gives an overview over currently running system processes and their status.'),
- execute: function() {
- var allow_signals = this.options.acls.status;
- return L.system.getProcessList().then(function(list) {
- var procTable = new L.ui.table({
- columns: [ {
- caption: L.tr('PID'),
- key: 'pid'
- }, {
- caption: L.tr('Owner'),
- key: 'user'
- }, {
- caption: L.tr('Command'),
- key: 'command'
- }, {
- caption: L.tr('CPU usage (%)'),
- key: 'cpu_percent',
- format: '%d%%'
- }, {
- caption: L.tr('Memory usage (%)'),
- key: 'vsize_percent',
- format: '%d%%'
- }, {
- key: 'pid',
- format: function(v, n) {
- return $('<div />')
- .addClass('btn-group')
- .append($('<button />')
- .addClass('btn btn-primary btn-sm dropdown-toggle')
- .attr('data-toggle', 'dropdown')
- .text(L.tr('Signal…')))
- .append($('<ul />')
- .addClass('dropdown-menu pull-right')
- .append($('<li />')
- .append($('<a />')
- .attr('href', '#')
- .html('%s (<code>%s</code>)'.format(L.trc('UNIX signal', 'Reload'), 'HUP'))
- .click(function(ev) { L.system.sendSignal(v, 1).then(status); ev.preventDefault(); })))
- .append($('<li />')
- .append($('<a />')
- .attr('href', '#')
- .html('%s (<code>%s</code>)'.format(L.trc('UNIX signal', 'Terminate'), 'TERM'))
- .click(function(ev) { L.system.sendSignal(v, 15).then(status); ev.preventDefault(); })))
- .append($('<li />')
- .append($('<a />')
- .attr('href', '#')
- .html('%s (<code>%s</code>)'.format(L.trc('UNIX signal', 'Kill immediately'), 'KILL'))
- .click(function(ev) { L.system.sendSignal(v, 9).then(status); ev.preventDefault(); }))))
- }
- } ]
- });
+ title: L.tr('Processes'),
+ description: L.tr('This list gives an overview over currently running system processes and their status.'),
- procTable.rows(list);
- procTable.insertInto('#process_table');
- });
- }
+ getProcessList: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'process_list',
+ expect: { processes: [ ] },
+ filter: function(data) {
+ data.sort(function(a, b) { return a.pid - b.pid });
+ return data;
+ }
+ }),
+
+ sendSignal: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'process_signal',
+ params: [ 'pid', 'signal' ],
+ filter: function(data) {
+ return (data == 0);
+ }
+ }),
+
+ execute: function() {
+ var self = this;
+ var allow_signals = this.options.acls.status;
+ return self.getProcessList().then(function(list) {
+ var procTable = new L.ui.table({
+ columns: [ {
+ caption: L.tr('PID'),
+ key: 'pid'
+ }, {
+ caption: L.tr('Owner'),
+ key: 'user'
+ }, {
+ caption: L.tr('Command'),
+ key: 'command'
+ }, {
+ caption: L.tr('CPU usage (%)'),
+ key: 'cpu_percent',
+ format: '%d%%'
+ }, {
+ caption: L.tr('Memory usage (%)'),
+ key: 'vsize_percent',
+ format: '%d%%'
+ }, {
+ key: 'pid',
+ format: function(v, n) {
+ return $('<div />')
+ .addClass('btn-group')
+ .append($('<button />')
+ .addClass('btn btn-primary btn-sm dropdown-toggle')
+ .attr('data-toggle', 'dropdown')
+ .text(L.tr('Signal…')))
+ .append($('<ul />')
+ .addClass('dropdown-menu pull-right')
+ .append($('<li />')
+ .append($('<a />')
+ .attr('href', '#')
+ .html('%s (<code>%s</code>)'.format(L.trc('UNIX signal', 'Reload'), 'HUP'))
+ .click(function(ev) { self.sendSignal(v, 1).then(status); ev.preventDefault(); })))
+ .append($('<li />')
+ .append($('<a />')
+ .attr('href', '#')
+ .html('%s (<code>%s</code>)'.format(L.trc('UNIX signal', 'Terminate'), 'TERM'))
+ .click(function(ev) { self.sendSignal(v, 15).then(status); ev.preventDefault(); })))
+ .append($('<li />')
+ .append($('<a />')
+ .attr('href', '#')
+ .html('%s (<code>%s</code>)'.format(L.trc('UNIX signal', 'Kill immediately'), 'KILL'))
+ .click(function(ev) { self.sendSignal(v, 9).then(status); ev.preventDefault(); }))))
+ }
+ } ]
+ });
+
+ procTable.rows(list);
+ procTable.insertInto('#process_table');
+ });
+ }
});
L.ui.view.extend({
title: L.tr('Routes'),
description: L.tr('The following rules are currently active on this system.'),
+
+ getRoutes: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'routes',
+ expect: { routes: [ ] }
+ }),
+
+ getIPv6Routes: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'routes',
+ expect: { routes: [ ] }
+ }),
+
+ getARPTable: L.rpc.declare({
+ object: 'luci2.network',
+ method: 'arp_table',
+ expect: { entries: [ ] }
+ }),
+
execute: function() {
+ var self = this;
return $.when(
- L.network.getARPTable().then(function(arp) {
+ self.getARPTable().then(function(arp) {
var arpTable = new L.ui.table({
caption: L.tr('ARP'),
columns: [{
arpTable.rows(arp);
arpTable.insertInto('#arp_table');
}),
- L.network.getRoutes().then(function(routes) {
+ self.getRoutes().then(function(routes) {
var routeTable = new L.ui.table({
caption: L.tr('Active IPv4-Routes'),
columns: [{
routeTable.rows(routes);
routeTable.insertInto('#route_table');
}),
- L.network.getIPv6Routes().then(function(routes) {
+ self.getIPv6Routes().then(function(routes) {
var route6Table = new L.ui.table({
caption: L.tr('Active IPv6-Routes'),
columns: [{
L.ui.view.extend({
- title: L.tr('System Log'),
- refresh: 5000,
- execute: function() {
- return L.system.getSystemLog().then(function(log) {
- var ta = document.getElementById('syslog');
- var lines = log.replace(/\n+$/, '').split(/\n/);
+ title: L.tr('System Log'),
+ refresh: 5000,
- ta.rows = lines.length;
- ta.value = lines.reverse().join("\n");
- });
- }
+ getSystemLog: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'syslog',
+ expect: { log: '' }
+ }),
+
+ execute: function() {
+ return this.getSystemLog().then(function(log) {
+ var ta = document.getElementById('syslog');
+ var lines = log.replace(/\n+$/, '').split(/\n/);
+
+ ta.rows = lines.length;
+ ta.value = lines.reverse().join("\n");
+ });
+ }
});
L.ui.view.extend({
- PubkeyListValue: L.cbi.AbstractValue.extend({
- base64Table: {
- 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6,
- 'H': 7, 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13,
- 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20,
- 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, 'a': 26, 'b': 27,
- 'c': 28, 'd': 29, 'e': 30, 'f': 31, 'g': 32, 'h': 33, 'i': 34,
- 'j': 35, 'k': 36, 'l': 37, 'm': 38, 'n': 39, 'o': 40, 'p': 41,
- 'q': 42, 'r': 43, 's': 44, 't': 45, 'u': 46, 'v': 47, 'w': 48,
- 'x': 49, 'y': 50, 'z': 51, '0': 52, '1': 53, '2': 54, '3': 55,
- '4': 56, '5': 57, '6': 58, '7': 59, '8': 60, '9': 61, '+': 62,
- '/': 63, '=': 64
- },
-
- base64Decode: function(s)
- {
- var i = 0;
- var d = '';
+ PubkeyListValue: L.cbi.AbstractValue.extend({
+ base64Table: {
+ 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6,
+ 'H': 7, 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13,
+ 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20,
+ 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, 'a': 26, 'b': 27,
+ 'c': 28, 'd': 29, 'e': 30, 'f': 31, 'g': 32, 'h': 33, 'i': 34,
+ 'j': 35, 'k': 36, 'l': 37, 'm': 38, 'n': 39, 'o': 40, 'p': 41,
+ 'q': 42, 'r': 43, 's': 44, 't': 45, 'u': 46, 'v': 47, 'w': 48,
+ 'x': 49, 'y': 50, 'z': 51, '0': 52, '1': 53, '2': 54, '3': 55,
+ '4': 56, '5': 57, '6': 58, '7': 59, '8': 60, '9': 61, '+': 62,
+ '/': 63, '=': 64
+ },
+
+ base64Decode: function(s)
+ {
+ var i = 0;
+ var d = '';
- if (s.match(/[^A-Za-z0-9\+\/\=]/))
- return undefined;
-
- while (i < s.length)
- {
- var e1 = this.base64Table[s.charAt(i++)];
- var e2 = this.base64Table[s.charAt(i++)];
- var e3 = this.base64Table[s.charAt(i++)];
- var e4 = this.base64Table[s.charAt(i++)];
-
- var c1 = ( e1 << 2) | (e2 >> 4);
- var c2 = ((e2 & 15) << 4) | (e3 >> 2);
- var c3 = ((e3 & 3) << 6) | e4;
-
- d += String.fromCharCode(c1);
-
- if (e3 < 64)
- d += String.fromCharCode(c2);
-
- if (e4 < 64)
- d += String.fromCharCode(c3);
- }
-
- return d;
- },
-
- lengthDecode: function(s, off)
- {
- var l = (s.charCodeAt(off++) << 24) |
- (s.charCodeAt(off++) << 16) |
- (s.charCodeAt(off++) << 8) |
- s.charCodeAt(off++);
-
- if (l < 0 || (off + l) > s.length)
- return -1;
-
- return l;
- },
-
- pubkeyDecode: function(s)
- {
- var parts = s.split(/\s+/);
- if (parts.length < 2)
- return undefined;
-
- var key = this.base64Decode(parts[1]);
- if (!key)
- return undefined;
-
- var off, len;
-
- off = 0;
- len = this.lengthDecode(key, off);
-
- if (len < 0)
- return undefined;
-
- var type = key.substr(off + 4, len);
- if (type != parts[0])
- return undefined;
-
- off += 4 + len;
-
- var len1 = this.lengthDecode(key, off);
- if (len1 < 0)
- return undefined;
-
- off += 4 + len1;
-
- var len2 = this.lengthDecode(key, off);
- if (len2 < 0)
- return undefined;
-
- if (len1 & 1)
- len1--;
-
- if (len2 & 1)
- len2--;
-
- switch (type)
- {
- case 'ssh-rsa':
- return { type: 'RSA', bits: len2 * 8, comment: parts[2] };
-
- case 'ssh-dss':
- return { type: 'DSA', bits: len1 * 8, comment: parts[2] };
-
- default:
- return undefined;
- }
- },
-
- _remove: function(ev)
- {
- var self = ev.data.self;
-
- self._keys.splice(ev.data.index, 1);
- self._render(ev.data.div);
- },
-
- _add: function(ev)
- {
- var self = ev.data.self;
-
- var form = $('<div />')
- .append($('<p />')
- .text(L.tr('Paste the public key line into the field below and press "%s" to continue.').format(L.tr('Ok'))))
- .append($('<p />')
- .text(L.tr('Unrecognized public key! Please add only RSA or DSA keys.'))
- .addClass('alert alert-danger')
- .hide())
- .append($('<p />')
- .append($('<input />')
- .attr('type', 'text')
- .attr('placeholder', L.tr('Paste key here'))
- .addClass('form-control')));
-
- L.ui.dialog(L.tr('Add new public key'), form, {
- style: 'confirm',
- confirm: function() {
- var val = form.find('input').val();
- if (!val)
- {
- return;
- }
-
- var key = self.pubkeyDecode(val);
- if (!key)
- {
- form.find('input').val('');
- form.find('.alert').show();
- return;
- }
-
- self._keys.push(val);
- self._render(ev.data.div);
-
- L.ui.dialog(false);
- }
- });
- },
-
- _show: function(ev)
- {
- var self = ev.data.self;
-
- L.ui.dialog(
- L.tr('Public key'),
- $('<pre />').text(self._keys[ev.data.index]),
- { style: 'close' }
- );
- },
-
- _render: function(div)
- {
- div.empty();
-
- for (var i = 0; i < this._keys.length; i++)
- {
- var k = this.pubkeyDecode(this._keys[i] || '');
-
- if (!k)
- continue;
-
- $('<div />')
- .addClass('input-group')
- .append($('<input />')
- .addClass('form-control')
- .attr('type', 'text')
- .prop('readonly', true)
- .click({ self: this, index: i }, this._show)
- .val('%dBit %s - %s'.format(k.bits, k.type, k.comment || '?')))
- .append($('<span />')
- .addClass('input-group-btn')
- .append($('<button />')
- .addClass('btn btn-danger')
- .attr('title', L.tr('Remove public key'))
- .text('–')
- .click({ self: this, div: div, index: i }, this._remove)))
- .appendTo(div);
- }
-
- if (this._keys.length > 0)
- $('<br />').appendTo(div);
-
- L.ui.button(L.tr('Add public key …'), 'success')
- .click({ self: this, div: div }, this._add)
- .appendTo(div);
- },
-
- widget: function(sid)
- {
- this._keys = [ ];
-
- for (var i = 0; i < this.options.keys.length; i++)
- this._keys.push(this.options.keys[i]);
-
- var d = $('<div />')
- .attr('id', this.id(sid));
-
- this._render(d);
-
- return d;
- },
-
- changed: function(sid)
- {
- if (this.options.keys.length != this._keys.length)
- return true;
-
- for (var i = 0; i < this.options.keys.length; i++)
- if (this.options.keys[i] != this._keys[i])
- return true;
-
- return false;
- },
-
- save: function(sid)
- {
- if (this.changed(sid))
- {
- this.options.keys = [ ];
-
- for (var i = 0; i < this._keys.length; i++)
- this.options.keys.push(this._keys[i]);
-
- return L.system.setSSHKeys(this._keys);
- }
-
- return undefined;
- }
- }),
-
- execute: function() {
- var self = this;
- return L.system.getSSHKeys().then(function(keys) {
- var m = new L.cbi.Map('dropbear', {
- caption: L.tr('SSH Access'),
- description: L.tr('Dropbear offers SSH network shell access and an integrated SCP server'),
- tabbed: true
- });
-
- var s1 = m.section(L.cbi.DummySection, '__password', {
- caption: L.tr('Router Password'),
- description: L.tr('Changes the administrator password for accessing the device'),
- readonly: !self.options.acls.admin
- });
-
- var p1 = s1.option(L.cbi.PasswordValue, 'pass1', {
- caption: L.tr('Password'),
- optional: true
- });
-
- var p2 = s1.option(L.cbi.PasswordValue, 'pass2', {
- caption: L.tr('Confirmation'),
- optional: true,
- datatype: function(v) {
- var v1 = p1.formvalue('__password');
- if (v1 && v1.length && v != v1)
- return L.tr('Passwords must match!');
- return true;
- }
- });
-
- p1.save = function(sid) { };
- p2.save = function(sid) {
- var v1 = p1.formvalue(sid);
- var v2 = p2.formvalue(sid);
- if (v2 && v2.length > 0 && v1 == v2)
- return L.system.setPassword('root', v2);
- };
-
-
- var s2 = m.section(L.cbi.DummySection, '__pubkeys', {
- caption: L.tr('SSH-Keys'),
- description: L.tr('Specifies public keys for passwordless SSH authentication'),
- readonly: !self.options.acls.admin
- });
-
- var k = s2.option(self.PubkeyListValue, 'keys', {
- caption: L.tr('Saved keys'),
- keys: keys
- });
-
-
- var s3 = m.section(L.cbi.TypedSection, 'dropbear', {
- caption: L.tr('SSH Server'),
- description: L.tr('This sections define listening instances of the builtin Dropbear SSH server'),
- addremove: true,
- add_caption: L.tr('Add instance ...'),
- readonly: !self.options.acls.admin,
- collabsible: true
- });
-
- s3.option(L.cbi.NetworkList, 'Interface', {
- caption: L.tr('Interface'),
- description: L.tr('Listen only on the given interface or, if unspecified, on all')
- });
-
- s3.option(L.cbi.InputValue, 'Port', {
- caption: L.tr('Port'),
- description: L.tr('Specifies the listening port of this Dropbear instance'),
- datatype: 'port',
- placeholder: 22,
- optional: true
- });
-
- s3.option(L.cbi.CheckboxValue, 'PasswordAuth', {
- caption: L.tr('Password authentication'),
- description: L.tr('Allow SSH password authentication'),
- initial: true,
- enabled: 'on',
- disabled: 'off'
- });
-
- s3.option(L.cbi.CheckboxValue, 'RootPasswordAuth', {
- caption: L.tr('Allow root logins with password'),
- description: L.tr('Allow the root user to login with password'),
- initial: true,
- enabled: 'on',
- disabled: 'off'
- });
-
- s3.option(L.cbi.CheckboxValue, 'GatewayPorts', {
- caption: L.tr('Gateway ports'),
- description: L.tr('Allow remote hosts to connect to local SSH forwarded ports'),
- initial: false,
- enabled: 'on',
- disabled: 'off'
- });
-
- return m.insertInto('#map');
- });
- }
+ if (s.match(/[^A-Za-z0-9\+\/\=]/))
+ return undefined;
+
+ while (i < s.length)
+ {
+ var e1 = this.base64Table[s.charAt(i++)];
+ var e2 = this.base64Table[s.charAt(i++)];
+ var e3 = this.base64Table[s.charAt(i++)];
+ var e4 = this.base64Table[s.charAt(i++)];
+
+ var c1 = ( e1 << 2) | (e2 >> 4);
+ var c2 = ((e2 & 15) << 4) | (e3 >> 2);
+ var c3 = ((e3 & 3) << 6) | e4;
+
+ d += String.fromCharCode(c1);
+
+ if (e3 < 64)
+ d += String.fromCharCode(c2);
+
+ if (e4 < 64)
+ d += String.fromCharCode(c3);
+ }
+
+ return d;
+ },
+
+ lengthDecode: function(s, off)
+ {
+ var l = (s.charCodeAt(off++) << 24) |
+ (s.charCodeAt(off++) << 16) |
+ (s.charCodeAt(off++) << 8) |
+ s.charCodeAt(off++);
+
+ if (l < 0 || (off + l) > s.length)
+ return -1;
+
+ return l;
+ },
+
+ pubkeyDecode: function(s)
+ {
+ var parts = s.split(/\s+/);
+ if (parts.length < 2)
+ return undefined;
+
+ var key = this.base64Decode(parts[1]);
+ if (!key)
+ return undefined;
+
+ var off, len;
+
+ off = 0;
+ len = this.lengthDecode(key, off);
+
+ if (len < 0)
+ return undefined;
+
+ var type = key.substr(off + 4, len);
+ if (type != parts[0])
+ return undefined;
+
+ off += 4 + len;
+
+ var len1 = this.lengthDecode(key, off);
+ if (len1 < 0)
+ return undefined;
+
+ off += 4 + len1;
+
+ var len2 = this.lengthDecode(key, off);
+ if (len2 < 0)
+ return undefined;
+
+ if (len1 & 1)
+ len1--;
+
+ if (len2 & 1)
+ len2--;
+
+ switch (type)
+ {
+ case 'ssh-rsa':
+ return { type: 'RSA', bits: len2 * 8, comment: parts[2] };
+
+ case 'ssh-dss':
+ return { type: 'DSA', bits: len1 * 8, comment: parts[2] };
+
+ default:
+ return undefined;
+ }
+ },
+
+ _remove: function(ev)
+ {
+ var self = ev.data.self;
+
+ self._keys.splice(ev.data.index, 1);
+ self._render(ev.data.div);
+ },
+
+ _add: function(ev)
+ {
+ var self = ev.data.self;
+
+ var form = $('<div />')
+ .append($('<p />')
+ .text(L.tr('Paste the public key line into the field below and press "%s" to continue.').format(L.tr('Ok'))))
+ .append($('<p />')
+ .text(L.tr('Unrecognized public key! Please add only RSA or DSA keys.'))
+ .addClass('alert alert-danger')
+ .hide())
+ .append($('<p />')
+ .append($('<input />')
+ .attr('type', 'text')
+ .attr('placeholder', L.tr('Paste key here'))
+ .addClass('form-control')));
+
+ L.ui.dialog(L.tr('Add new public key'), form, {
+ style: 'confirm',
+ confirm: function() {
+ var val = form.find('input').val();
+ if (!val)
+ {
+ return;
+ }
+
+ var key = self.pubkeyDecode(val);
+ if (!key)
+ {
+ form.find('input').val('');
+ form.find('.alert').show();
+ return;
+ }
+
+ self._keys.push(val);
+ self._render(ev.data.div);
+
+ L.ui.dialog(false);
+ }
+ });
+ },
+
+ _show: function(ev)
+ {
+ var self = ev.data.self;
+
+ L.ui.dialog(
+ L.tr('Public key'),
+ $('<pre />').text(self._keys[ev.data.index]),
+ { style: 'close' }
+ );
+ },
+
+ _render: function(div)
+ {
+ div.empty();
+
+ for (var i = 0; i < this._keys.length; i++)
+ {
+ var k = this.pubkeyDecode(this._keys[i] || '');
+
+ if (!k)
+ continue;
+
+ $('<div />')
+ .addClass('input-group')
+ .append($('<input />')
+ .addClass('form-control')
+ .attr('type', 'text')
+ .prop('readonly', true)
+ .click({ self: this, index: i }, this._show)
+ .val('%dBit %s - %s'.format(k.bits, k.type, k.comment || '?')))
+ .append($('<span />')
+ .addClass('input-group-btn')
+ .append($('<button />')
+ .addClass('btn btn-danger')
+ .attr('title', L.tr('Remove public key'))
+ .text('–')
+ .click({ self: this, div: div, index: i }, this._remove)))
+ .appendTo(div);
+ }
+
+ if (this._keys.length > 0)
+ $('<br />').appendTo(div);
+
+ L.ui.button(L.tr('Add public key …'), 'success')
+ .click({ self: this, div: div }, this._add)
+ .appendTo(div);
+ },
+
+ widget: function(sid)
+ {
+ this._keys = [ ];
+
+ for (var i = 0; i < this.options.keys.length; i++)
+ this._keys.push(this.options.keys[i]);
+
+ var d = $('<div />')
+ .attr('id', this.id(sid));
+
+ this._render(d);
+
+ return d;
+ },
+
+ changed: function(sid)
+ {
+ if (this.options.keys.length != this._keys.length)
+ return true;
+
+ for (var i = 0; i < this.options.keys.length; i++)
+ if (this.options.keys[i] != this._keys[i])
+ return true;
+
+ return false;
+ },
+
+ save: function(sid)
+ {
+ if (this.changed(sid))
+ {
+ this.options.keys = [ ];
+
+ for (var i = 0; i < this._keys.length; i++)
+ this.options.keys.push(this._keys[i]);
+
+ return L.views.SystemAdmin.setSSHKeys(this._keys);
+ }
+
+ return undefined;
+ }
+ }),
+
+ getSSHKeys: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'sshkeys_get',
+ expect: { keys: [ ] }
+ }),
+
+ setSSHKeys: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'sshkeys_set',
+ params: [ 'keys' ]
+ }),
+
+ setPassword: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'password_set',
+ params: [ 'user', 'password' ]
+ }),
+
+ execute: function() {
+ var self = this;
+ return self.getSSHKeys().then(function(keys) {
+ var m = new L.cbi.Map('dropbear', {
+ caption: L.tr('SSH Access'),
+ description: L.tr('Dropbear offers SSH network shell access and an integrated SCP server'),
+ tabbed: true
+ });
+
+ var s1 = m.section(L.cbi.DummySection, '__password', {
+ caption: L.tr('Router Password'),
+ description: L.tr('Changes the administrator password for accessing the device'),
+ readonly: !self.options.acls.admin
+ });
+
+ var p1 = s1.option(L.cbi.PasswordValue, 'pass1', {
+ caption: L.tr('Password'),
+ optional: true
+ });
+
+ var p2 = s1.option(L.cbi.PasswordValue, 'pass2', {
+ caption: L.tr('Confirmation'),
+ optional: true,
+ datatype: function(v) {
+ var v1 = p1.formvalue('__password');
+ if (v1 && v1.length && v != v1)
+ return L.tr('Passwords must match!');
+ return true;
+ }
+ });
+
+ p1.save = function(sid) { };
+ p2.save = function(sid) {
+ var v1 = p1.formvalue(sid);
+ var v2 = p2.formvalue(sid);
+ if (v2 && v2.length > 0 && v1 == v2)
+ return L.system.setPassword('root', v2);
+ };
+
+
+ var s2 = m.section(L.cbi.DummySection, '__pubkeys', {
+ caption: L.tr('SSH-Keys'),
+ description: L.tr('Specifies public keys for passwordless SSH authentication'),
+ readonly: !self.options.acls.admin
+ });
+
+ var k = s2.option(self.PubkeyListValue, 'keys', {
+ caption: L.tr('Saved keys'),
+ keys: keys
+ });
+
+
+ var s3 = m.section(L.cbi.TypedSection, 'dropbear', {
+ caption: L.tr('SSH Server'),
+ description: L.tr('This sections define listening instances of the builtin Dropbear SSH server'),
+ addremove: true,
+ add_caption: L.tr('Add instance ...'),
+ readonly: !self.options.acls.admin,
+ collabsible: true
+ });
+
+ s3.option(L.cbi.NetworkList, 'Interface', {
+ caption: L.tr('Interface'),
+ description: L.tr('Listen only on the given interface or, if unspecified, on all')
+ });
+
+ s3.option(L.cbi.InputValue, 'Port', {
+ caption: L.tr('Port'),
+ description: L.tr('Specifies the listening port of this Dropbear instance'),
+ datatype: 'port',
+ placeholder: 22,
+ optional: true
+ });
+
+ s3.option(L.cbi.CheckboxValue, 'PasswordAuth', {
+ caption: L.tr('Password authentication'),
+ description: L.tr('Allow SSH password authentication'),
+ initial: true,
+ enabled: 'on',
+ disabled: 'off'
+ });
+
+ s3.option(L.cbi.CheckboxValue, 'RootPasswordAuth', {
+ caption: L.tr('Allow root logins with password'),
+ description: L.tr('Allow the root user to login with password'),
+ initial: true,
+ enabled: 'on',
+ disabled: 'off'
+ });
+
+ s3.option(L.cbi.CheckboxValue, 'GatewayPorts', {
+ caption: L.tr('Gateway ports'),
+ description: L.tr('Allow remote hosts to connect to local SSH forwarded ports'),
+ initial: false,
+ enabled: 'on',
+ disabled: 'off'
+ });
+
+ return m.insertInto('#map');
+ });
+ }
});
L.ui.view.extend({
title: L.tr('Scheduled Tasks'),
description: L.tr('This is the system crontab in which scheduled tasks can be defined.'),
- execute: function() {
- var allow_write = this.options.acls.cron;
- return L.system.getCrontab().then(function(data) {
+ getCrontab: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'crontab_get',
+ expect: { data: '' }
+ }),
+
+ setCrontab: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'crontab_set',
+ params: [ 'data' ]
+ }),
+
+ execute: function() {
+ var self = this;
+ var allow_write = this.options.acls.cron;
+
+ return self.getCrontab().then(function(data) {
$('textarea').val(data).attr('disabled', !allow_write);
$('input.cbi-button-save').attr('disabled', !allow_write).click(function() {
var data = ($('textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
L.ui.loading(true);
- L.system.setCrontab(data).then(function() {
+ self.setCrontab(data).then(function() {
$('textarea').val(data);
L.ui.loading(false);
});
});
});
- }
+ }
});
L.ui.view.extend({
- execute: function() {
- var m = new L.cbi.Map('system', {
- caption: L.tr('LED Configuration'),
- description: L.tr('Customizes the behaviour of the device LEDs if possible.'),
- prepare: function() {
- return $.when(
- L.system.listLEDs().then(function(leds) {
- delete m.sections[0].fields.sysfs.choices;
- delete m.sections[0].fields.trigger.choices;
-
- for (var i = 0; i < leds.length; i++)
- m.sections[0].fields.sysfs.value(leds[i].name);
-
- for (var i = 0; i < leds[0].triggers.length; i++)
- m.sections[0].fields.trigger.value(leds[0].triggers[i]);
- }),
- L.system.listUSBDevices().then(function(devs) {
- delete m.sections[0].fields._usb_dev.choices;
-
- for (var i = 0; i < devs.length; i++)
- m.sections[0].fields._usb_dev.value(devs[i].name,
- '%04x:%04x (%s - %s)'.format(devs[i].vendor_id, devs[i].product_id,
- devs[i].vendor_name || '?', devs[i].product_name || '?'));
- }),
- L.network.listDeviceNames().then(function(devices) {
- delete m.sections[0].fields._net_dev.choices;
- for (var i = 0; i < devices.length; i++)
- m.sections[0].fields._net_dev.value(devices[i]);
- })
- );
- }
- });
-
- var s = m.section(L.cbi.TypedSection, 'led', {
- caption: L.tr('LED Definitions'),
- teasers: [ 'name', 'sysfs', 'default', 'trigger', '_net_dev', 'mode', '_usb_dev', 'delayon', 'delayoff' ],
- collabsible: true,
- addremove: true,
- add_caption: L.tr('Add new LED defintion'),
- remove_caption: L.tr('Remove LED definition'),
- readonly: !this.options.acls.leds
- });
-
- s.option(L.cbi.InputValue, 'name', {
- caption: L.tr('Name')
- });
-
- s.option(L.cbi.ListValue, 'sysfs', {
- caption: L.tr('LED Name')
- });
-
- s.option(L.cbi.ListValue, 'default', {
- caption: L.tr('Default state'),
- initial: '0'
- }).value('0', L.trc('LED state', 'off')).value('1', L.trc('LED state', 'on'));
-
- s.option(L.cbi.ListValue, 'trigger', {
- caption: L.tr('Trigger')
- });
-
-
- s.option(L.cbi.InputValue, 'delayon', {
- caption: L.trc('LED timer trigger', 'On-State Delay'),
- description: L.trc('LED timer trigger', 'Time in milliseconds the LED stays on'),
- datatype: 'uinteger'
- }).depends('trigger', 'timer');
-
- s.option(L.cbi.InputValue, 'delayoff', {
- caption: L.trc('LED timer trigger', 'Off-State Delay'),
- description: L.trc('LED timer trigger', 'Time in milliseconds the LED stays off'),
- datatype: 'uinteger'
- }).depends('trigger', 'timer');
-
-
- s.option(L.cbi.ListValue, '_net_dev', {
- caption: L.trc('LED netdev trigger', 'Device'),
- uci_option: 'dev',
- optional: true
- }).depends('trigger', 'netdev');
-
- s.option(L.cbi.MultiValue, 'mode', {
- caption: L.trc('LED netdev trigger', 'Trigger Mode')
- }).depends('trigger', 'netdev')
- .value('link', L.trc('LED netdev trigger mode', 'Link On'))
- .value('tx', L.trc('LED netdev trigger mode', 'Transmit'))
- .value('rx', L.trc('LED netdev trigger mode', 'Receive'));
-
-
- s.option(L.cbi.ListValue, '_usb_dev', {
- caption: L.trc('LED usbdev trigger', 'Device'),
- uci_option: 'dev',
- optional: true
- }).depends('trigger', 'usbdev');
-
- return m.insertInto('#map');
- }
+ listLEDs: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'led_list',
+ expect: { leds: [ ] }
+ }),
+
+ listUSBDevices: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'usb_list',
+ expect: { devices: [ ] }
+ }),
+
+ execute: function() {
+ var self = this;
+ var m = new L.cbi.Map('system', {
+ caption: L.tr('LED Configuration'),
+ description: L.tr('Customizes the behaviour of the device LEDs if possible.'),
+ prepare: function() {
+ delete m.sections[0].fields._net_dev.choices;
+
+ var devs = L.NetworkModel.getDevices().sort(function(a, b) {
+ if (a.name() < b.name())
+ return -1;
+ else if (a.name() > b.name())
+ return 1;
+ else
+ return 0;
+ });
+
+ for (var i = 0; i < devs.length; i++)
+ if (!devs[i].isAlias())
+ m.sections[0].fields._net_dev.value(devs[i].name());
+
+ return $.when(
+ self.listLEDs().then(function(leds) {
+ delete m.sections[0].fields.sysfs.choices;
+ delete m.sections[0].fields.trigger.choices;
+
+ for (var i = 0; i < leds.length; i++)
+ m.sections[0].fields.sysfs.value(leds[i].name);
+
+ for (var i = 0; i < leds[0].triggers.length; i++)
+ m.sections[0].fields.trigger.value(leds[0].triggers[i]);
+ }),
+ self.listUSBDevices().then(function(devs) {
+ delete m.sections[0].fields._usb_dev.choices;
+
+ for (var i = 0; i < devs.length; i++)
+ m.sections[0].fields._usb_dev.value(devs[i].name,
+ '%04x:%04x (%s - %s)'.format(devs[i].vendor_id, devs[i].product_id,
+ devs[i].vendor_name || '?', devs[i].product_name || '?'));
+ })
+ );
+ }
+ });
+
+ var s = m.section(L.cbi.TypedSection, 'led', {
+ caption: L.tr('LED Definitions'),
+ teasers: [ 'name', 'sysfs', 'default', 'trigger', '_net_dev', 'mode', '_usb_dev', 'delayon', 'delayoff' ],
+ collabsible: true,
+ addremove: true,
+ add_caption: L.tr('Add new LED defintion'),
+ remove_caption: L.tr('Remove LED definition'),
+ readonly: !this.options.acls.leds
+ });
+
+ s.option(L.cbi.InputValue, 'name', {
+ caption: L.tr('Name')
+ });
+
+ s.option(L.cbi.ListValue, 'sysfs', {
+ caption: L.tr('LED Name')
+ });
+
+ s.option(L.cbi.ListValue, 'default', {
+ caption: L.tr('Default state'),
+ initial: '0'
+ }).value('0', L.trc('LED state', 'off')).value('1', L.trc('LED state', 'on'));
+
+ s.option(L.cbi.ListValue, 'trigger', {
+ caption: L.tr('Trigger')
+ });
+
+
+ s.option(L.cbi.InputValue, 'delayon', {
+ caption: L.trc('LED timer trigger', 'On-State Delay'),
+ description: L.trc('LED timer trigger', 'Time in milliseconds the LED stays on'),
+ datatype: 'uinteger'
+ }).depends('trigger', 'timer');
+
+ s.option(L.cbi.InputValue, 'delayoff', {
+ caption: L.trc('LED timer trigger', 'Off-State Delay'),
+ description: L.trc('LED timer trigger', 'Time in milliseconds the LED stays off'),
+ datatype: 'uinteger'
+ }).depends('trigger', 'timer');
+
+
+ s.option(L.cbi.ListValue, '_net_dev', {
+ caption: L.trc('LED netdev trigger', 'Device'),
+ uci_option: 'dev',
+ optional: true
+ }).depends('trigger', 'netdev');
+
+ s.option(L.cbi.MultiValue, 'mode', {
+ caption: L.trc('LED netdev trigger', 'Trigger Mode')
+ }).depends('trigger', 'netdev')
+ .value('link', L.trc('LED netdev trigger mode', 'Link On'))
+ .value('tx', L.trc('LED netdev trigger mode', 'Transmit'))
+ .value('rx', L.trc('LED netdev trigger mode', 'Receive'));
+
+
+ s.option(L.cbi.ListValue, '_usb_dev', {
+ caption: L.trc('LED usbdev trigger', 'Device'),
+ uci_option: 'dev',
+ optional: true
+ }).depends('trigger', 'usbdev');
+
+ return m.insertInto('#map');
+ }
});
L.ui.view.extend({
title: L.tr('Package management'),
+ opkg: {
+ updateLists: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'update',
+ expect: { '': { } }
+ }),
+
+ _allPackages: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'list',
+ params: [ 'offset', 'limit', 'pattern' ],
+ expect: { '': { } }
+ }),
+
+ _installedPackages: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'list_installed',
+ params: [ 'offset', 'limit', 'pattern' ],
+ expect: { '': { } }
+ }),
+
+ _findPackages: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'find',
+ params: [ 'offset', 'limit', 'pattern' ],
+ expect: { '': { } }
+ }),
+
+ _fetchPackages: function(action, offset, limit, pattern)
+ {
+ var packages = [ ];
+
+ return action(offset, limit, pattern).then(function(list) {
+ if (!list.total || !list.packages)
+ return { length: 0, total: 0 };
+
+ packages.push.apply(packages, list.packages);
+ packages.total = list.total;
+
+ if (limit <= 0)
+ limit = list.total;
+
+ if (packages.length >= limit)
+ return packages;
+
+ L.rpc.batch();
+
+ for (var i = offset + packages.length; i < limit; i += 100)
+ action(i, (Math.min(i + 100, limit) % 100) || 100, pattern);
+
+ return L.rpc.flush();
+ }).then(function(lists) {
+ for (var i = 0; i < lists.length; i++)
+ {
+ if (!lists[i].total || !lists[i].packages)
+ continue;
+
+ packages.push.apply(packages, lists[i].packages);
+ packages.total = lists[i].total;
+ }
+
+ return packages;
+ });
+ },
+
+ listPackages: function(offset, limit, pattern)
+ {
+ return this._fetchPackages(this._allPackages, offset, limit, pattern);
+ },
+
+ installedPackages: function(offset, limit, pattern)
+ {
+ return this._fetchPackages(this._installedPackages, offset, limit, pattern);
+ },
+
+ findPackages: function(offset, limit, pattern)
+ {
+ return this._fetchPackages(this._findPackages, offset, limit, pattern);
+ },
+
+ installPackage: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'install',
+ params: [ 'package' ],
+ expect: { '': { } }
+ }),
+
+ removePackage: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'remove',
+ params: [ 'package' ],
+ expect: { '': { } }
+ }),
+
+ getConfig: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'config_get',
+ expect: { config: '' }
+ }),
+
+ setConfig: L.rpc.declare({
+ object: 'luci2.opkg',
+ method: 'config_set',
+ params: [ 'data' ]
+ }),
+
+ isInstalled: function(pkg)
+ {
+ return this._installedPackages(0, 1, pkg).then(function(list) {
+ return (!isNaN(list.total) && list.total > 0);
+ });
+ }
+ },
+
updateDiskSpace: function()
{
return L.system.getDiskInfo().then(function(info) {
installRemovePackage: function(pkgname, installed)
{
+ var self = this;
+
var dspname = pkgname.replace(/^.+\//, '');
- var action = installed ? L.opkg.removePackage : L.opkg.installPackage;
+ var action = installed ? self.opkg.removePackage : self.opkg.installPackage;
var title = (installed ? L.tr('Removing package "%s" …') : L.tr('Installing package "%s" …')).format(dspname);
var confirm = (installed ? L.tr('Really remove package "%h" ?') : L.tr('Really install package "%h" ?')).format(dspname);
- var self = this;
-
L.ui.dialog(title, confirm, {
style: 'confirm',
confirm: function() {
L.ui.dialog(title, L.tr('Waiting for package manager …'), { style: 'wait' });
- action(pkgname).then(function(res) {
+ action.call(self.opkg, pkgname).then(function(res) {
self.fetchInstalledList().then(function() { return self.fetchPackageList(); }).then(function() {
var output = [ ];
fetchInstalledList: function()
{
var self = this;
- return L.opkg.installedPackages(0, 0, '*').then(function(list) {
+ return self.opkg.installedPackages(0, 0, '*').then(function(list) {
self.installedList = { };
for (var i = 0; i < list.length; i++)
self.installedList[list[i][0]] = true;
if (typeof(offset) == 'undefined')
offset = parseInt($('#package_filter').attr('offset')) || 0;
+ var self = this;
+
var pattern = $('#package_filter').val() || '';
var action;
if (pattern.length)
{
- action = $('#package_which').prop('checked') ? L.opkg.installedPackages : L.opkg.findPackages;
+ action = $('#package_which').prop('checked') ? self.opkg.installedPackages : self.opkg.findPackages;
pattern = '*' + pattern + '*';
$('#package_filter').next().attr('src', L.globals.resource + '/icons/cbi/remove.gif');
}
else
{
- action = $('#package_which').prop('checked') ? L.opkg.installedPackages : L.opkg.listPackages;
+ action = $('#package_which').prop('checked') ? self.opkg.installedPackages : self.opkg.listPackages;
pattern = '*';
$('#package_filter').next().attr('src', L.globals.resource + '/icons/cbi/find.gif');
$('#package_filter').attr('offset', offset);
var install_disabled = $('#package_install').attr('disabled');
- var self = this;
- return action(offset, 100, pattern).then(function(list) {
+ return action.call(self.opkg, offset, 100, pattern).then(function(list) {
var packageTable = new L.ui.table({
placeholder: L.tr('No matching packages found.'),
columns: [ {
$('#package_update, #package_url, #package_install').attr('disabled', !this.options.acls.software);
return $.when(
- L.opkg.getConfig().then(function(config) {
+ self.opkg.getConfig().then(function(config) {
$('#config textarea')
.attr('rows', (config.match(/\n/g) || [ ]).length + 1)
.val(config);
.click(function() {
var data = ($('#config textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
L.ui.loading(true);
- L.opkg.setConfig(data).then(function() {
+ self.opkg.setConfig(data).then(function() {
$('#config textarea')
.attr('rows', (data.match(/\n/g) || [ ]).length + 1)
.val(data);
$('#package_update').click(function(ev) {
L.ui.dialog(L.tr('Updating package lists'), L.tr('Waiting for package manager …'), { style: 'wait' });
- L.opkg.updateLists().then(function(res) {
+ self.opkg.updateLists().then(function(res) {
var output = [ ];
if (res.stdout)
L.ui.view.extend({
- title: L.tr('Startup'),
- execute: function() {
- var self = this;
- var redraw = function() { return self.execute(); };
- var allow_write = self.options.acls.startup;
+ title: L.tr('Startup'),
- return $.when(
- L.system.initList().then(function(list) {
- /* filter init scripts with no start prio */
- for (var i = 0; i < list.length; i++)
- {
- if (typeof(list[i].start) != 'undefined')
- continue;
+ getRcLocal: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'rclocal_get',
+ expect: { data: '' }
+ }),
- list.splice(i--, 1);
- }
+ setRcLocal: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'rclocal_set',
+ params: [ 'data' ]
+ }),
- var initTable = new L.ui.table({
- columns: [ {
- caption: L.tr('Start priority'),
- key: 'start'
- }, {
- caption: L.tr('Initscript'),
- key: 'name'
- }, {
- key: 'enabled',
- format: function(v, n) {
- return [
- $('<div />')
- .addClass('btn-group pull-right')
- .append($('<button />')
- .attr('disabled', !allow_write)
- .attr('name', list[n].name)
- .addClass('btn btn-sm')
- .addClass(v ? 'btn-success' : 'btn-danger')
- .text(v ? L.trc('Init script state', 'Enabled') : L.trc('Init script state', 'Disabled'))
- .click(function() {
- L.ui.loading(true);
- if (v)
- L.system.initDisable(this.getAttribute('name')).then(redraw);
- else
- L.system.initEnable(this.getAttribute('name')).then(redraw);
- }))
- .append($('<button />')
- .addClass('btn btn-primary btn-sm dropdown-toggle')
- .attr('data-toggle', 'dropdown')
- .attr('disabled', !allow_write)
- .text(L.tr('Action…')))
- .append($('<ul />')
- .addClass('dropdown-menu pull-right')
- .append($('<li />')
- .append($('<a />')
- .attr('href', '#')
- .text(L.tr('Reload'))
- .click(function(ev) { L.system.initReload(v).then(redraw); ev.preventDefault(); })))
- .append($('<li />')
- .append($('<a />')
- .attr('href', '#')
- .text(L.tr('Restart'))
- .click(function(ev) { L.system.initRestart(v).then(redraw); ev.preventDefault(); })))
- .append($('<li />')
- .append($('<a />')
- .attr('href', '#')
- .text(L.tr('Stop'))
- .click(function(ev) { L.system.initStop(v).then(redraw); ev.preventDefault(); }))))
- ];
- }
- } ]
- });
+ execute: function() {
+ var self = this;
+ var redraw = function() { return self.execute(); };
+ var allow_write = self.options.acls.startup;
- initTable.rows(list);
- initTable.insertInto('#init_table');
+ return $.when(
+ L.system.initList().then(function(list) {
+ /* filter init scripts with no start prio */
+ for (var i = 0; i < list.length; i++)
+ {
+ if (typeof(list[i].start) != 'undefined')
+ continue;
- L.ui.loading(false);
- }),
- L.system.getRcLocal().then(function(data) {
- $('textarea').val(data).attr('disabled', !allow_write);
- $('input.cbi-button-save').attr('disabled', !allow_write).click(function() {
- var data = ($('textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
- L.ui.loading(true);
- L.system.setRcLocal(data).then(function() {
- $('textarea').val(data);
- L.ui.loading(false);
- });
- });
- })
- );
- }
+ list.splice(i--, 1);
+ }
+
+ var initTable = new L.ui.table({
+ columns: [ {
+ caption: L.tr('Start priority'),
+ key: 'start'
+ }, {
+ caption: L.tr('Initscript'),
+ key: 'name'
+ }, {
+ key: 'enabled',
+ format: function(v, n) {
+ return [
+ $('<div />')
+ .addClass('btn-group pull-right')
+ .append($('<button />')
+ .attr('disabled', !allow_write)
+ .attr('name', list[n].name)
+ .addClass('btn btn-sm')
+ .addClass(v ? 'btn-success' : 'btn-danger')
+ .text(v ? L.trc('Init script state', 'Enabled') : L.trc('Init script state', 'Disabled'))
+ .click(function() {
+ L.ui.loading(true);
+ if (v)
+ L.system.initDisable(this.getAttribute('name')).then(redraw);
+ else
+ L.system.initEnable(this.getAttribute('name')).then(redraw);
+ }))
+ .append($('<button />')
+ .addClass('btn btn-primary btn-sm dropdown-toggle')
+ .attr('data-toggle', 'dropdown')
+ .attr('disabled', !allow_write)
+ .text(L.tr('Action…')))
+ .append($('<ul />')
+ .addClass('dropdown-menu pull-right')
+ .append($('<li />')
+ .append($('<a />')
+ .attr('href', '#')
+ .text(L.tr('Reload'))
+ .click(function(ev) { L.system.initReload(v).then(redraw); ev.preventDefault(); })))
+ .append($('<li />')
+ .append($('<a />')
+ .attr('href', '#')
+ .text(L.tr('Restart'))
+ .click(function(ev) { L.system.initRestart(v).then(redraw); ev.preventDefault(); })))
+ .append($('<li />')
+ .append($('<a />')
+ .attr('href', '#')
+ .text(L.tr('Stop'))
+ .click(function(ev) { L.system.initStop(v).then(redraw); ev.preventDefault(); }))))
+ ];
+ }
+ } ]
+ });
+
+ initTable.rows(list);
+ initTable.insertInto('#init_table');
+
+ L.ui.loading(false);
+ }),
+ self.getRcLocal().then(function(data) {
+ $('textarea').val(data).attr('disabled', !allow_write);
+ $('input.cbi-button-save').attr('disabled', !allow_write).click(function() {
+ var data = ($('textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
+ L.ui.loading(true);
+ self.setRcLocal(data).then(function() {
+ $('textarea').val(data);
+ L.ui.loading(false);
+ });
+ });
+ })
+ );
+ }
});
L.ui.view.extend({
- execute: function() {
- var m = new L.cbi.Map('system', {
- caption: L.tr('System'),
- description: L.tr('Here you can configure the basic aspects of your device like its hostname or the timezone.'),
- collabsible: true
- });
-
- var s = m.section(L.cbi.TypedSection, 'system', {
- caption: L.tr('System Properties'),
- teasers: [ 'hostname', 'zonename', 'languages', 'themes' ],
- readonly: !this.options.acls.system
- });
-
- s.tab({
- id: 'general',
- caption: L.tr('General Settings')
- });
-
- var t = s.taboption('general', L.cbi.DummyValue, '__time', {
- caption: L.tr('Local Time')
- });
-
- t.load = function(sid)
- {
- var id = this.id(sid);
-
- return L.system.getSystemInfo().then(function(info) {
- var date = new Date();
- var time = info.localtime;
-
- window.setInterval(function() {
- date.setTime(++time * 1000);
-
- $('#' + id).text('%04d/%02d/%02d %02d:%02d:%02d'.format(
- date.getUTCFullYear(),
- date.getUTCMonth() + 1,
- date.getUTCDate(),
- date.getUTCHours(),
- date.getUTCMinutes(),
- date.getUTCSeconds()
- ));
- }, 1000);
- });
- };
-
-
- s.taboption('general', L.cbi.InputValue, 'hostname', {
- caption: L.tr('Hostname'),
- datatype: 'hostname'
- });
-
-
- var z = s.taboption('general', L.cbi.ListValue, 'zonename', {
- caption: L.tr('Timezone')
- });
-
- z.load = function(sid) {
- return L.system.getZoneInfo(function(zones) {
- var znames = [ ];
-
- for (var i = 0; i < zones.length; i++)
- for (var j = 5; j < zones[i].length; j++)
- znames.push(zones[i][j]);
-
- znames.sort();
-
- for (var i = 0; i < znames.length; i++)
- z.value(znames[i]);
-
- z.zones = zones;
- });
- };
-
- z.save = function(sid)
- {
- var uci = this.ucipath(sid);
- var val = this.formvalue(sid);
-
- if (!this.callSuper('save', sid))
- return false;
-
- for (var i = 0; i < z.zones.length; i++)
- for (var j = 5; j < z.zones[i].length; j++)
- if (z.zones[i][j] == val)
- {
- m.set(uci.config, uci.section, 'timezone', z.zones[i][0]);
- return true;
- }
-
- m.set(uci.config, uci.section, 'timezone', 'GMT0');
- return true;
- };
-
-
- s.tab({
- id: 'logging',
- caption: L.tr('Logging')
- });
-
- s.taboption('logging', L.cbi.InputValue, 'log_size', {
- caption: L.tr('System log buffer size'),
- description: L.tr('kiB'),
- placeholder: 16,
- optional: true,
- datatype: 'range(0, 32)'
- });
-
- s.taboption('logging', L.cbi.InputValue, 'log_ip', {
- caption: L.tr('External system log server'),
- placeholder: '0.0.0.0',
- optional: true,
- datatype: 'ip4addr'
- });
-
- s.taboption('logging', L.cbi.InputValue, 'log_port', {
- caption: L.tr('External system log server port'),
- placeholder: 514,
- optional: true,
- datatype: 'port'
- });
-
- s.taboption('logging', L.cbi.ListValue, 'conloglevel', {
- caption: L.tr('Log output level')
- }).value(8, L.tr('Debug'))
- .value(7, L.tr('Info'))
- .value(6, L.tr('Notice'))
- .value(5, L.tr('Warning'))
- .value(4, L.tr('Error'))
- .value(3, L.tr('Critical'))
- .value(2, L.tr('Alert'))
- .value(1, L.tr('Emergency'));
-
- s.taboption('logging', L.cbi.ListValue, 'cronloglevel', {
- caption: L.tr('Cron Log level')
- }).value(5, L.tr('Debug'))
- .value(8, L.tr('Normal'))
- .value(9, L.tr('Warning'));
-
- s.tab({
- id: 'language',
- caption: L.tr('Language and Style')
- });
-
-
- var l = s.taboption('language', L.cbi.ListValue, 'languages', {
- caption: L.tr('Language'),
- uci_package: 'luci',
- uci_section: 'main',
- uci_option: 'lang'
- }).value('auto', L.tr('Automatic'));
-
- l.load = function(sid)
- {
- var langs = m.get('luci', 'languages');
- for (var key in langs)
- if (key.charAt(0) != '.')
- l.value(key, langs[key]);
- };
-
-
- var t = s.taboption('language', L.cbi.ListValue, 'themes', {
- caption: L.tr('Design'),
- uci_package: 'luci',
- uci_section: 'main',
- uci_option: 'mediaurlbase'
- });
-
- t.load = function(sid)
- {
- var themes = m.get('luci', 'themes');
- for (var key in themes)
- if (key.charAt(0) != '.')
- t.value(themes[key], key);
- };
-
-
- var s2 = m.section(L.cbi.NamedSection, 'ntp', {
- caption: L.tr('Time Synchronization'),
- readonly: !this.options.acls.system
- });
-
- var e = s2.option(L.cbi.CheckboxValue, '.enable', {
- caption: L.tr('Enable NTP client'),
- optional: true
- });
-
- e.load = function(sid) {
- return L.system.initEnabled('sysntpd').then(function(enabled) {
- e.options.initial = enabled;
- });
- };
-
- e.save = function(sid) {
- if (this.formvalue(sid))
- return L.system.initEnable('sysntpd');
- else
- return L.system.initDisable('sysntpd');
- };
-
- s2.option(L.cbi.CheckboxValue, 'enable_server', {
- caption: L.tr('Enable NTP server')
- }).depends('.enable');
-
- s2.option(L.cbi.DynamicList, 'server', {
- caption: L.tr('NTP server candidates'),
- datatype: 'host'
- }).depends('.enable');
-
- return m.insertInto('#map');
- }
+ execute: function() {
+ var m = new L.cbi.Map('system', {
+ caption: L.tr('System'),
+ description: L.tr('Here you can configure the basic aspects of your device like its hostname or the timezone.'),
+ collabsible: true
+ });
+
+ var s = m.section(L.cbi.TypedSection, 'system', {
+ caption: L.tr('System Properties'),
+ teasers: [ 'hostname', 'zonename', 'languages', 'themes' ],
+ readonly: !this.options.acls.system
+ });
+
+ s.tab({
+ id: 'general',
+ caption: L.tr('General Settings')
+ });
+
+ var t = s.taboption('general', L.cbi.DummyValue, '__time', {
+ caption: L.tr('Local Time')
+ });
+
+ t.load = function(sid)
+ {
+ var id = this.id(sid);
+
+ return L.system.getSystemInfo().then(function(info) {
+ var date = new Date();
+ var time = info.localtime;
+
+ window.setInterval(function() {
+ date.setTime(++time * 1000);
+
+ $('#' + id).text('%04d/%02d/%02d %02d:%02d:%02d'.format(
+ date.getUTCFullYear(),
+ date.getUTCMonth() + 1,
+ date.getUTCDate(),
+ date.getUTCHours(),
+ date.getUTCMinutes(),
+ date.getUTCSeconds()
+ ));
+ }, 1000);
+ });
+ };
+
+
+ s.taboption('general', L.cbi.InputValue, 'hostname', {
+ caption: L.tr('Hostname'),
+ datatype: 'hostname'
+ });
+
+
+ var z = s.taboption('general', L.cbi.ListValue, 'zonename', {
+ caption: L.tr('Timezone')
+ });
+
+ z.load = function(sid) {
+ return $.getJSON(L.globals.resource + '/zoneinfo.json').then(function(zones) {
+ var znames = [ ];
+
+ for (var i = 0; i < zones.length; i++)
+ for (var j = 5; j < zones[i].length; j++)
+ znames.push(zones[i][j]);
+
+ znames.sort();
+
+ for (var i = 0; i < znames.length; i++)
+ z.value(znames[i]);
+
+ z.zones = zones;
+ });
+ };
+
+ z.save = function(sid)
+ {
+ var uci = this.ucipath(sid);
+ var val = this.formvalue(sid);
+
+ if (!this.callSuper('save', sid))
+ return false;
+
+ for (var i = 0; i < z.zones.length; i++)
+ for (var j = 5; j < z.zones[i].length; j++)
+ if (z.zones[i][j] == val)
+ {
+ m.set(uci.config, uci.section, 'timezone', z.zones[i][0]);
+ return true;
+ }
+
+ m.set(uci.config, uci.section, 'timezone', 'GMT0');
+ return true;
+ };
+
+
+ s.tab({
+ id: 'logging',
+ caption: L.tr('Logging')
+ });
+
+ s.taboption('logging', L.cbi.InputValue, 'log_size', {
+ caption: L.tr('System log buffer size'),
+ description: L.tr('kiB'),
+ placeholder: 16,
+ optional: true,
+ datatype: 'range(0, 32)'
+ });
+
+ s.taboption('logging', L.cbi.InputValue, 'log_ip', {
+ caption: L.tr('External system log server'),
+ placeholder: '0.0.0.0',
+ optional: true,
+ datatype: 'ip4addr'
+ });
+
+ s.taboption('logging', L.cbi.InputValue, 'log_port', {
+ caption: L.tr('External system log server port'),
+ placeholder: 514,
+ optional: true,
+ datatype: 'port'
+ });
+
+ s.taboption('logging', L.cbi.ListValue, 'conloglevel', {
+ caption: L.tr('Log output level')
+ }).value(8, L.tr('Debug'))
+ .value(7, L.tr('Info'))
+ .value(6, L.tr('Notice'))
+ .value(5, L.tr('Warning'))
+ .value(4, L.tr('Error'))
+ .value(3, L.tr('Critical'))
+ .value(2, L.tr('Alert'))
+ .value(1, L.tr('Emergency'));
+
+ s.taboption('logging', L.cbi.ListValue, 'cronloglevel', {
+ caption: L.tr('Cron Log level')
+ }).value(5, L.tr('Debug'))
+ .value(8, L.tr('Normal'))
+ .value(9, L.tr('Warning'));
+
+ s.tab({
+ id: 'language',
+ caption: L.tr('Language and Style')
+ });
+
+
+ var l = s.taboption('language', L.cbi.ListValue, 'languages', {
+ caption: L.tr('Language'),
+ uci_package: 'luci',
+ uci_section: 'main',
+ uci_option: 'lang'
+ }).value('auto', L.tr('Automatic'));
+
+ l.load = function(sid)
+ {
+ var langs = m.get('luci', 'languages');
+ for (var key in langs)
+ if (key.charAt(0) != '.')
+ l.value(key, langs[key]);
+ };
+
+
+ var t = s.taboption('language', L.cbi.ListValue, 'themes', {
+ caption: L.tr('Design'),
+ uci_package: 'luci',
+ uci_section: 'main',
+ uci_option: 'mediaurlbase'
+ });
+
+ t.load = function(sid)
+ {
+ var themes = m.get('luci', 'themes');
+ for (var key in themes)
+ if (key.charAt(0) != '.')
+ t.value(themes[key], key);
+ };
+
+
+ var s2 = m.section(L.cbi.NamedSection, 'ntp', {
+ caption: L.tr('Time Synchronization'),
+ readonly: !this.options.acls.system
+ });
+
+ var e = s2.option(L.cbi.CheckboxValue, '.enable', {
+ caption: L.tr('Enable NTP client'),
+ optional: true
+ });
+
+ e.load = function(sid) {
+ return L.system.initEnabled('sysntpd').then(function(enabled) {
+ e.options.initial = enabled;
+ });
+ };
+
+ e.save = function(sid) {
+ if (this.formvalue(sid))
+ return L.system.initEnable('sysntpd');
+ else
+ return L.system.initDisable('sysntpd');
+ };
+
+ s2.option(L.cbi.CheckboxValue, 'enable_server', {
+ caption: L.tr('Enable NTP server')
+ }).depends('.enable');
+
+ s2.option(L.cbi.DynamicList, 'server', {
+ caption: L.tr('NTP server candidates'),
+ datatype: 'host'
+ }).depends('.enable');
+
+ return m.insertInto('#map');
+ }
});
L.ui.view.extend({
title: L.tr('Flash operations'),
- handle_flash_upload: function() {
+ testUpgrade: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'upgrade_test',
+ expect: { '': { } }
+ }),
+
+ startUpgrade: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'upgrade_start',
+ params: [ 'keep' ]
+ }),
+
+ cleanUpgrade: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'upgrade_clean'
+ }),
+
+ restoreBackup: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'backup_restore'
+ }),
+
+ cleanBackup: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'backup_clean'
+ }),
+
+ getBackupConfig: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'backup_config_get',
+ expect: { config: '' }
+ }),
+
+ setBackupConfig: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'backup_config_set',
+ params: [ 'data' ]
+ }),
+
+ listBackup: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'backup_list',
+ expect: { files: [ ] }
+ }),
+
+ testReset: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'reset_test',
+ expect: { supported: false }
+ }),
+
+ startReset: L.rpc.declare({
+ object: 'luci2.system',
+ method: 'reset_start'
+ }),
+
+ handleFlashUpload: function() {
var self = this;
L.ui.upload(
L.tr('Firmware upload'),
L.tr('Select the sysupgrade image to flash and click "%s" to proceed.').format(L.tr('Ok')), {
filename: '/tmp/firmware.bin',
success: function(info) {
- self.handle_flash_verify(info);
+ self.handleFlashVerify(info);
}
}
);
},
- handle_flash_verify: function(info) {
+ handleFlashVerify: function(info) {
var self = this;
- L.system.testUpgrade().then(function(res) {
+ self.testUpgrade().then(function(res) {
if (res.code == 0)
{
L.ui.dialog(
], {
style: 'confirm',
confirm: function() {
- //L.system.startUpgrade().then(function() {
+ //self.startUpgrade().then(function() {
// L.ui.reconnect();
//});
], {
style: 'close',
close: function() {
- L.system.cleanUpgrade().then(function() {
+ self.cleanUpgrade().then(function() {
L.ui.dialog(false);
});
}
});
},
- handle_backup_upload: function() {
+ handleBackupUpload: function() {
var self = this;
L.ui.upload(
L.tr('Backup restore'),
L.tr('Select the backup archive to restore and click "%s" to proceed.').format(L.tr('Ok')), {
filename: '/tmp/backup.tar.gz',
success: function(info) {
- self.handle_backup_verify(info);
+ self.handleBackupVerify(info);
}
}
);
},
- handle_backup_verify: function(info) {
+ handleBackupVerify: function(info) {
var self = this;
L.ui.dialog(
L.tr('Backup restore'), [
], {
style: 'confirm',
confirm: function() {
- self.handle_backup_restore();
+ self.handleBackupRestore();
}
}
);
},
- handle_backup_restore: function() {
+ handleBackupRestore: function() {
var self = this;
- L.system.restoreBackup().then(function(res) {
+ self.restoreBackup().then(function(res) {
if (res.code == 0)
{
L.ui.dialog(
], {
style: 'close',
close: function() {
- L.system.cleanBackup().then(function() {
+ self.cleanBackup().then(function() {
L.ui.dialog(false);
});
}
], {
style: 'close',
close: function() {
- L.system.cleanBackup().then(function() {
+ self.cleanBackup().then(function() {
L.ui.dialog(false);
});
}
});
},
- handle_backup_download: function() {
+ handleBackupDownload: function() {
var form = $('#btn_backup').parent();
form.find('[name=sessionid]').val(L.globals.sid);
form.submit();
},
- handle_reset: function() {
+ handleReset: function() {
+ var self = this;
L.ui.dialog(L.tr('Really reset all changes?'), L.tr('This will reset the system to its initial configuration, all changes made since the initial flash will be lost!'), {
style: 'confirm',
confirm: function() {
- //L.system.startReset().then(function() {
+ //self.startReset().then(function() {
// L.ui.reconnect();
//});
execute: function() {
var self = this;
- L.system.testReset().then(function(reset_avail) {
+ self.testReset().then(function(reset_avail) {
if (!reset_avail) {
$('#btn_reset').prop('disabled', true);
}
$('#btn_restore, #btn_save, textarea').prop('disabled', true);
}
else {
- $('#btn_backup').click(function() { self.handle_backup_download(); });
- $('#btn_restore').click(function() { self.handle_backup_upload(); });
+ $('#btn_backup').click(function() { self.handleBackupDownload(); });
+ $('#btn_restore').click(function() { self.handleBackupUpload(); });
}
if (!self.options.acls.upgrade) {
$('#btn_flash, #btn_reset').prop('disabled', true);
}
else {
- $('#btn_flash').click(function() { self.handle_flash_upload(); });
- $('#btn_reset').click(function() { self.handle_reset(); });
+ $('#btn_flash').click(function() { self.handleFlashUpload(); });
+ $('#btn_reset').click(function() { self.handleReset(); });
}
- return L.system.getBackupConfig();
+ return self.getBackupConfig();
}).then(function(config) {
$('textarea')
.attr('rows', (config.match(/\n/g) || [ ]).length + 1)
.click(function() {
var data = ($('textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
L.ui.loading(true);
- L.system.setBackupConfig(data).then(function() {
+ self.setBackupConfig(data).then(function() {
$('textarea')
.attr('rows', (data.match(/\n/g) || [ ]).length + 1)
.val(data);
$('#btn_list')
.click(function() {
L.ui.loading(true);
- L.system.listBackup().then(function(list) {
+ self.listBackup().then(function(list) {
L.ui.loading(false);
L.ui.dialog(
L.tr('Backup file list'),
L.ui.view.extend({
- aclTable: L.cbi.AbstractValue.extend({
- strGlob: function(pattern, match) {
- var re = new RegExp('^' + (pattern
- .replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1')
- .replace(/\\\*/g, '.*?')) + '$');
-
- return re.test(match);
- },
-
- aclMatch: function(list, group) {
- for (var i = 0; i < list.length; i++)
- {
- var x = list[i].replace(/^\s*!\s*/, '');
- if (x == list[i])
- continue;
-
- if (this.strGlob(x, group))
- return false;
- }
-
- for (var i = 0; i < list.length; i++)
- {
- var x = list[i].replace(/^\s*!\s*/, '');
- if (x != list[i])
- continue;
-
- if (this.strGlob(x, group))
- return true;
- }
-
- return false;
- },
-
- aclTest: function(list, group) {
- for (var i = 0; i < list.length; i++)
- if (list[i] == group)
- return true;
-
- return false;
- },
-
- aclEqual: function(list1, list2) {
- if (list1.length != list2.length)
- return false;
-
- for (var i = 0; i < list1.length; i++)
- if (list1[i] != list2[i])
- return false;
-
- return true;
- },
-
- aclFromUCI: function(value) {
- var list;
- if (typeof(value) == 'string')
- list = value.split(/\s+/);
- else if ($.isArray(value))
- list = value;
- else
- list = [ ];
-
- var rv = [ ];
- if (this.choices)
- for (var i = 0; i < this.choices.length; i++)
- if (this.aclMatch(list, this.choices[i][0]))
- rv.push(this.choices[i][0]);
-
- return rv;
- },
-
- aclToUCI: function(list) {
- if (list.length < (this.choices.length / 2))
- return list;
-
- var set = { };
- for (var i = 0; i < list.length; i++)
- set[list[i]] = true;
-
- var rv = [ '*' ];
- for (var i = 0; i < this.choices.length; i++)
- if (!set[this.choices[i][0]])
- rv.push('!' + this.choices[i][0]);
-
- return rv;
- },
-
- setAll: function(ev) {
- $(this).parents('table')
- .find('input[value=%d]'.format(ev.data.level))
- .prop('checked', true);
- },
+ aclTable: L.cbi.AbstractValue.extend({
+ strGlob: function(pattern, match) {
+ var re = new RegExp('^' + (pattern
+ .replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1')
+ .replace(/\\\*/g, '.*?')) + '$');
+
+ return re.test(match);
+ },
+
+ aclMatch: function(list, group) {
+ for (var i = 0; i < list.length; i++)
+ {
+ var x = list[i].replace(/^\s*!\s*/, '');
+ if (x == list[i])
+ continue;
+
+ if (this.strGlob(x, group))
+ return false;
+ }
+
+ for (var i = 0; i < list.length; i++)
+ {
+ var x = list[i].replace(/^\s*!\s*/, '');
+ if (x != list[i])
+ continue;
+
+ if (this.strGlob(x, group))
+ return true;
+ }
+
+ return false;
+ },
+
+ aclTest: function(list, group) {
+ for (var i = 0; i < list.length; i++)
+ if (list[i] == group)
+ return true;
+
+ return false;
+ },
+
+ aclEqual: function(list1, list2) {
+ if (list1.length != list2.length)
+ return false;
+
+ for (var i = 0; i < list1.length; i++)
+ if (list1[i] != list2[i])
+ return false;
+
+ return true;
+ },
+
+ aclFromUCI: function(value) {
+ var list;
+ if (typeof(value) == 'string')
+ list = value.split(/\s+/);
+ else if ($.isArray(value))
+ list = value;
+ else
+ list = [ ];
+
+ var rv = [ ];
+ if (this.choices)
+ for (var i = 0; i < this.choices.length; i++)
+ if (this.aclMatch(list, this.choices[i][0]))
+ rv.push(this.choices[i][0]);
+
+ return rv;
+ },
+
+ aclToUCI: function(list) {
+ if (list.length < (this.choices.length / 2))
+ return list;
+
+ var set = { };
+ for (var i = 0; i < list.length; i++)
+ set[list[i]] = true;
+
+ var rv = [ '*' ];
+ for (var i = 0; i < this.choices.length; i++)
+ if (!set[this.choices[i][0]])
+ rv.push('!' + this.choices[i][0]);
+
+ return rv;
+ },
+
+ setAll: function(ev) {
+ $(this).parents('table')
+ .find('input[value=%d]'.format(ev.data.level))
+ .prop('checked', true);
+ },
widget: function(sid)
{
- var t = $('<table />')
- .addClass('table table-condensed table-hover')
- .attr('id', this.id(sid))
- .append($('<tr />')
- .append($('<th />')
- .text(L.tr('ACL Group')))
- .append($('<th />')
- .text(L.trc('No access', 'N'))
- .attr('title', L.tr('Set all to no access'))
- .css('cursor', 'pointer')
- .click({ level: 0 }, this.setAll))
- .append($('<th />')
- .text(L.trc('Read only access', 'R'))
- .attr('title', L.tr('Set all to read only access'))
- .css('cursor', 'pointer')
- .click({ level: 1 }, this.setAll))
- .append($('<th />')
- .text(L.trc('Full access', 'F'))
- .attr('title', L.tr('Set all to full access'))
- .css('cursor', 'pointer')
- .click({ level: 2 }, this.setAll)));
-
- var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
- var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
-
- if (this.choices)
- for (var i = 0; i < this.choices.length; i++)
- {
- var r = t.get(0).insertRow(-1);
- var is_r = this.aclTest(acl_r, this.choices[i][0]);
- var is_w = this.aclTest(acl_w, this.choices[i][0]);
-
- $(r.insertCell(-1))
- .text(this.choices[i][1]);
-
- for (var j = 0; j < 3; j++)
- {
- $(r.insertCell(-1))
- .append($('<input />')
- .addClass('form-control')
- .attr('type', 'radio')
- .attr('name', '%s_%s'.format(this.id(sid), this.choices[i][0]))
- .attr('value', j)
- .prop('checked', (j == 0 && !is_r && !is_w) ||
- (j == 1 && is_r && !is_w) ||
- (j == 2 && is_w)));
- }
- }
-
- return t;
+ var t = $('<table />')
+ .addClass('table table-condensed table-hover')
+ .attr('id', this.id(sid))
+ .append($('<tr />')
+ .append($('<th />')
+ .text(L.tr('ACL Group')))
+ .append($('<th />')
+ .text(L.trc('No access', 'N'))
+ .attr('title', L.tr('Set all to no access'))
+ .css('cursor', 'pointer')
+ .click({ level: 0 }, this.setAll))
+ .append($('<th />')
+ .text(L.trc('Read only access', 'R'))
+ .attr('title', L.tr('Set all to read only access'))
+ .css('cursor', 'pointer')
+ .click({ level: 1 }, this.setAll))
+ .append($('<th />')
+ .text(L.trc('Full access', 'F'))
+ .attr('title', L.tr('Set all to full access'))
+ .css('cursor', 'pointer')
+ .click({ level: 2 }, this.setAll)));
+
+ var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
+ var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
+
+ if (this.choices)
+ for (var i = 0; i < this.choices.length; i++)
+ {
+ var r = t.get(0).insertRow(-1);
+ var is_r = this.aclTest(acl_r, this.choices[i][0]);
+ var is_w = this.aclTest(acl_w, this.choices[i][0]);
+
+ $(r.insertCell(-1))
+ .text(this.choices[i][1]);
+
+ for (var j = 0; j < 3; j++)
+ {
+ $(r.insertCell(-1))
+ .append($('<input />')
+ .addClass('form-control')
+ .attr('type', 'radio')
+ .attr('name', '%s_%s'.format(this.id(sid), this.choices[i][0]))
+ .attr('value', j)
+ .prop('checked', (j == 0 && !is_r && !is_w) ||
+ (j == 1 && is_r && !is_w) ||
+ (j == 2 && is_w)));
+ }
+ }
+
+ return t;
},
- textvalue: function(sid)
- {
- var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
- var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
+ textvalue: function(sid)
+ {
+ var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
+ var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
- var htmlid = this.id(sid);
- var radios = $('#' + htmlid + ' input');
+ var htmlid = this.id(sid);
+ var radios = $('#' + htmlid + ' input');
- var acls = [ ];
+ var acls = [ ];
- for (var i = 0; i < this.choices.length; i++)
- {
- switch (radios.filter('[name=%s_%s]:checked'.format(htmlid, this.choices[i][0])).val())
- {
- case '2':
- acls.push('%s: %s'.format(this.choices[i][0], L.trc('Full access', 'F')));
- break;
+ for (var i = 0; i < this.choices.length; i++)
+ {
+ switch (radios.filter('[name=%s_%s]:checked'.format(htmlid, this.choices[i][0])).val())
+ {
+ case '2':
+ acls.push('%s: %s'.format(this.choices[i][0], L.trc('Full access', 'F')));
+ break;
- case '1':
- acls.push('%s: %s'.format(this.choices[i][0], L.trc('Read only access', 'R')));
- break;
+ case '1':
+ acls.push('%s: %s'.format(this.choices[i][0], L.trc('Read only access', 'R')));
+ break;
- case '0':
- acls.push('%s: %s'.format(this.choices[i][0], L.trc('No access', 'N')));
- break;
- }
- }
+ case '0':
+ acls.push('%s: %s'.format(this.choices[i][0], L.trc('No access', 'N')));
+ break;
+ }
+ }
- return acls.join(', ');
- },
+ return acls.join(', ');
+ },
value: function(k, v)
{
return this;
},
- save: function(sid)
- {
- var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
- var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
-
- var acl_r_new = [ ];
- var acl_w_new = [ ];
-
- var htmlid = this.id(sid);
- var radios = $('#' + htmlid + ' input');
-
- for (var i = 0; i < this.choices.length; i++)
- {
- switch (radios.filter('[name=%s_%s]:checked'.format(htmlid, this.choices[i][0])).val())
- {
- case '2':
- acl_r_new.push(this.choices[i][0]);
- acl_w_new.push(this.choices[i][0]);
- break;
-
- case '1':
- acl_r_new.push(this.choices[i][0]);
- break;
- }
- }
-
- if (!this.aclEqual(acl_r, acl_r_new))
- this.map.set('rpcd', sid, 'read', this.aclToUCI(acl_r_new));
-
- if (!this.aclEqual(acl_w, acl_w_new))
- this.map.set('rpcd', sid, 'write', this.aclToUCI(acl_w_new));
- }
+ save: function(sid)
+ {
+ var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
+ var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
+
+ var acl_r_new = [ ];
+ var acl_w_new = [ ];
+
+ var htmlid = this.id(sid);
+ var radios = $('#' + htmlid + ' input');
+
+ for (var i = 0; i < this.choices.length; i++)
+ {
+ switch (radios.filter('[name=%s_%s]:checked'.format(htmlid, this.choices[i][0])).val())
+ {
+ case '2':
+ acl_r_new.push(this.choices[i][0]);
+ acl_w_new.push(this.choices[i][0]);
+ break;
+
+ case '1':
+ acl_r_new.push(this.choices[i][0]);
+ break;
+ }
+ }
+
+ if (!this.aclEqual(acl_r, acl_r_new))
+ this.map.set('rpcd', sid, 'read', this.aclToUCI(acl_r_new));
+
+ if (!this.aclEqual(acl_w, acl_w_new))
+ this.map.set('rpcd', sid, 'write', this.aclToUCI(acl_w_new));
+ }
}),
- execute: function() {
- var self = this;
- return L.ui.listAvailableACLs().then(function(acls) {
- var m = new L.cbi.Map('rpcd', {
- caption: L.tr('Guest Logins'),
- description: L.tr('Manage user accounts and permissions for accessing the LuCI ui.'),
- readonly: !self.options.acls.users
- });
-
- var s = m.section(L.cbi.TypedSection, 'login', {
- caption: L.tr('Accounts'),
- collabsible: true,
- addremove: true,
- add_caption: L.tr('Add account …'),
- teasers: [ 'username', '__shadow', '__acls' ]
- });
-
- s.option(L.cbi.InputValue, 'username', {
- caption: L.tr('Username'),
- description: L.tr('Specifies the login name for the guest account'),
- optional: false
- });
-
-
- var shadow = s.option(L.cbi.CheckboxValue, '__shadow', {
- caption: L.tr('Use system account'),
- description: L.tr('Use password from the Linux user database')
- });
-
- shadow.ucivalue = function(sid) {
- var pw = this.map.get('rpcd', sid, 'password');
- return (pw && pw.indexOf('$p$') == 0);
- };
-
-
- var password = s.option(L.cbi.PasswordValue, 'password', {
- caption: L.tr('Password'),
- description: L.tr('Specifies the password for the guest account. If you enter a plaintext password here, it will get replaced with a crypted password hash on save.'),
- optional: false
- });
-
- password.depends('__shadow', false);
-
- password.toggle = function(sid) {
- var id = '#' + this.id(sid);
- var pw = this.map.get('rpcd', sid, 'password');
- var sh = this.section.fields.__shadow.formvalue(sid);
-
- if (!sh && pw && pw.indexOf('$p$') == 0)
- $(id).val('');
-
- this.callSuper('toggle', sid);
- };
-
- shadow.save = password.save = function(sid) {
- var sh = this.section.fields.__shadow.formvalue(sid);
- var pw = this.section.fields.password.formvalue(sid);
-
- if (!sh && !pw)
- return;
-
- if (sh)
- pw = '$p$' + this.section.fields.username.formvalue(sid);
-
- if (pw.match(/^\$[0-9p][a-z]?\$/))
- {
- if (pw != this.map.get('rpcd', sid, 'password'))
- this.map.set('rpcd', sid, 'password', pw);
- }
- else
- {
- var map = this.map;
- return L.ui.cryptPassword(pw).then(function(crypt) {
- map.set('rpcd', sid, 'password', crypt);
- });
- }
- };
-
- var o = s.option(self.aclTable, '__acls', {
- caption: L.tr('User ACLs'),
- description: L.tr('Specifies the access levels of this account. The "N" column means no access, "R" stands for read only access and "F" for full access.')
- });
-
- var groups = [ ];
- for (var group_name in acls)
- groups.push(group_name);
-
- groups.sort();
-
- for (var i = 0; i < groups.length; i++)
- o.value(groups[i], acls[groups[i]].description);
-
- return m.insertInto('#map');
- });
- }
+ execute: function() {
+ var self = this;
+ return L.ui.listAvailableACLs().then(function(acls) {
+ var m = new L.cbi.Map('rpcd', {
+ caption: L.tr('Guest Logins'),
+ description: L.tr('Manage user accounts and permissions for accessing the LuCI ui.'),
+ readonly: !self.options.acls.users
+ });
+
+ var s = m.section(L.cbi.TypedSection, 'login', {
+ caption: L.tr('Accounts'),
+ collabsible: true,
+ addremove: true,
+ add_caption: L.tr('Add account …'),
+ teasers: [ 'username', '__shadow', '__acls' ]
+ });
+
+ s.option(L.cbi.InputValue, 'username', {
+ caption: L.tr('Username'),
+ description: L.tr('Specifies the login name for the guest account'),
+ optional: false
+ });
+
+
+ var shadow = s.option(L.cbi.CheckboxValue, '__shadow', {
+ caption: L.tr('Use system account'),
+ description: L.tr('Use password from the Linux user database')
+ });
+
+ shadow.ucivalue = function(sid) {
+ var pw = this.map.get('rpcd', sid, 'password');
+ return (pw && pw.indexOf('$p$') == 0);
+ };
+
+
+ var password = s.option(L.cbi.PasswordValue, 'password', {
+ caption: L.tr('Password'),
+ description: L.tr('Specifies the password for the guest account. If you enter a plaintext password here, it will get replaced with a crypted password hash on save.'),
+ optional: false
+ });
+
+ password.depends('__shadow', false);
+
+ password.toggle = function(sid) {
+ var id = '#' + this.id(sid);
+ var pw = this.map.get('rpcd', sid, 'password');
+ var sh = this.section.fields.__shadow.formvalue(sid);
+
+ if (!sh && pw && pw.indexOf('$p$') == 0)
+ $(id).val('');
+
+ this.callSuper('toggle', sid);
+ };
+
+ shadow.save = password.save = function(sid) {
+ var sh = this.section.fields.__shadow.formvalue(sid);
+ var pw = this.section.fields.password.formvalue(sid);
+
+ if (!sh && !pw)
+ return;
+
+ if (sh)
+ pw = '$p$' + this.section.fields.username.formvalue(sid);
+
+ if (pw.match(/^\$[0-9p][a-z]?\$/))
+ {
+ if (pw != this.map.get('rpcd', sid, 'password'))
+ this.map.set('rpcd', sid, 'password', pw);
+ }
+ else
+ {
+ var map = this.map;
+ return L.ui.cryptPassword(pw).then(function(crypt) {
+ map.set('rpcd', sid, 'password', crypt);
+ });
+ }
+ };
+
+ var o = s.option(self.aclTable, '__acls', {
+ caption: L.tr('User ACLs'),
+ description: L.tr('Specifies the access levels of this account. The "N" column means no access, "R" stands for read only access and "F" for full access.')
+ });
+
+ var groups = [ ];
+ for (var group_name in acls)
+ groups.push(group_name);
+
+ groups.sort();
+
+ for (var i = 0; i < groups.length; i++)
+ o.value(groups[i], acls[groups[i]].description);
+
+ return m.insertInto('#map');
+ });
+ }
});