summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2014-02-01 18:29:03 +0000
committerJo-Philipp Wich <jow@openwrt.org>2014-02-01 18:29:03 +0000
commitb5dc25c09ca938be6f9d82f461873eb69728481f (patch)
tree525251e72bf8b7ef7c6a2194e49f06c316d5c0d5
parent639d2147af1293101ce10b4d67bde91a42da6926 (diff)
downloadluci2-ui-b5dc25c09ca938be6f9d82f461873eb69728481f.tar.gz
luci2: move most RPC proxy function declarations into the views using them to reduce the size of the core luci2.js library
-rw-r--r--luci2/htdocs/luci2/luci2.js262
-rw-r--r--luci2/htdocs/luci2/view/network.diagnostics.js47
-rw-r--r--luci2/htdocs/luci2/view/network.hosts.js44
-rw-r--r--luci2/htdocs/luci2/view/network.routes.js206
-rw-r--r--luci2/htdocs/luci2/view/network.switch.js73
-rw-r--r--luci2/htdocs/luci2/view/status.dmesg.js27
-rw-r--r--luci2/htdocs/luci2/view/status.overview.js109
-rw-r--r--luci2/htdocs/luci2/view/status.processes.js133
-rw-r--r--luci2/htdocs/luci2/view/status.routes.js26
-rw-r--r--luci2/htdocs/luci2/view/status.syslog.js27
-rw-r--r--luci2/htdocs/luci2/view/system.admin.js722
-rw-r--r--luci2/htdocs/luci2/view/system.cron.js24
-rw-r--r--luci2/htdocs/luci2/view/system.leds.js215
-rw-r--r--luci2/htdocs/luci2/view/system.software.js139
-rw-r--r--luci2/htdocs/luci2/view/system.startup.js179
-rw-r--r--luci2/htdocs/luci2/view/system.system.js420
-rw-r--r--luci2/htdocs/luci2/view/system.upgrade.js107
-rw-r--r--luci2/htdocs/luci2/view/system.users.js584
18 files changed, 1725 insertions, 1619 deletions
diff --git a/luci2/htdocs/luci2/luci2.js b/luci2/htdocs/luci2/luci2.js
index 30e3063..34cef8a 100644
--- a/luci2/htdocs/luci2/luci2.js
+++ b/luci2/htdocs/luci2/luci2.js
@@ -2805,41 +2805,6 @@ function LuCI2()
});
},
- 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',
@@ -2879,239 +2844,12 @@ function LuCI2()
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({
diff --git a/luci2/htdocs/luci2/view/network.diagnostics.js b/luci2/htdocs/luci2/view/network.diagnostics.js
index 99f185a..1649264 100644
--- a/luci2/htdocs/luci2/view/network.diagnostics.js
+++ b/luci2/htdocs/luci2/view/network.diagnostics.js
@@ -1,24 +1,59 @@
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() {
@@ -38,7 +73,7 @@ L.ui.view.extend({
$('#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)
diff --git a/luci2/htdocs/luci2/view/network.hosts.js b/luci2/htdocs/luci2/view/network.hosts.js
index 587b181..99fbe47 100644
--- a/luci2/htdocs/luci2/view/network.hosts.js
+++ b/luci2/htdocs/luci2/view/network.hosts.js
@@ -1,29 +1,29 @@
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');
+ }
});
diff --git a/luci2/htdocs/luci2/view/network.routes.js b/luci2/htdocs/luci2/view/network.routes.js
index a1ed560..4464706 100644
--- a/luci2/htdocs/luci2/view/network.routes.js
+++ b/luci2/htdocs/luci2/view/network.routes.js
@@ -1,105 +1,105 @@
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');
+ }
});
diff --git a/luci2/htdocs/luci2/view/network.switch.js b/luci2/htdocs/luci2/view/network.switch.js
index bfe27c6..39a5b0b 100644
--- a/luci2/htdocs/luci2/view/network.switch.js
+++ b/luci2/htdocs/luci2/view/network.switch.js
@@ -2,6 +2,37 @@ L.ui.view.extend({
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') ],
@@ -60,11 +91,11 @@ L.ui.view.extend({
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) {
@@ -283,25 +314,25 @@ L.ui.view.extend({
}
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 = '&#160;';
-
- 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 = '&#160;';
+
+ 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);
+ });
});
}
});
diff --git a/luci2/htdocs/luci2/view/status.dmesg.js b/luci2/htdocs/luci2/view/status.dmesg.js
index bcb35d0..de03973 100644
--- a/luci2/htdocs/luci2/view/status.dmesg.js
+++ b/luci2/htdocs/luci2/view/status.dmesg.js
@@ -1,13 +1,20 @@
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");
+ });
+ }
});
diff --git a/luci2/htdocs/luci2/view/status.overview.js b/luci2/htdocs/luci2/view/status.overview.js
index 7440f8c..909c4c1 100644
--- a/luci2/htdocs/luci2/view/status.overview.js
+++ b/luci2/htdocs/luci2/view/status.overview.js
@@ -1,10 +1,30 @@
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)
{
@@ -21,57 +41,36 @@ L.ui.view.extend({
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;
}
@@ -86,7 +85,7 @@ L.ui.view.extend({
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: [ {
@@ -352,7 +351,7 @@ L.ui.view.extend({
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.'),
@@ -378,7 +377,7 @@ L.ui.view.extend({
leaseTable.rows(leases);
leaseTable.insertInto('#lease_status_table');
}),
- L.network.getDHCPv6Leases().then(function(leases) {
+ self.getDHCPv6Leases().then(function(leases) {
if (!leases.length)
return;
@@ -407,5 +406,13 @@ L.ui.view.extend({
leaseTable.insertInto('#lease6_status_table');
})
)
+ },
+
+ execute: function()
+ {
+ var self = this;
+ return L.NetworkModel.init().then(function() {
+ self.repeat(self.renderContents, 5000);
+ });
}
});
diff --git a/luci2/htdocs/luci2/view/status.processes.js b/luci2/htdocs/luci2/view/status.processes.js
index 9c80d89..b58df8a 100644
--- a/luci2/htdocs/luci2/view/status.processes.js
+++ b/luci2/htdocs/luci2/view/status.processes.js
@@ -1,59 +1,80 @@
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');
+ });
+ }
});
diff --git a/luci2/htdocs/luci2/view/status.routes.js b/luci2/htdocs/luci2/view/status.routes.js
index 249acdf..a73cf82 100644
--- a/luci2/htdocs/luci2/view/status.routes.js
+++ b/luci2/htdocs/luci2/view/status.routes.js
@@ -1,9 +1,29 @@
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: [{
@@ -21,7 +41,7 @@ L.ui.view.extend({
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: [{
@@ -42,7 +62,7 @@ L.ui.view.extend({
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: [{
diff --git a/luci2/htdocs/luci2/view/status.syslog.js b/luci2/htdocs/luci2/view/status.syslog.js
index e57db2c..87b3386 100644
--- a/luci2/htdocs/luci2/view/status.syslog.js
+++ b/luci2/htdocs/luci2/view/status.syslog.js
@@ -1,13 +1,20 @@
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");
+ });
+ }
});
diff --git a/luci2/htdocs/luci2/view/system.admin.js b/luci2/htdocs/luci2/view/system.admin.js
index c10cb3c..8ecc95f 100644
--- a/luci2/htdocs/luci2/view/system.admin.js
+++ b/luci2/htdocs/luci2/view/system.admin.js
@@ -1,355 +1,373 @@
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');
+ });
+ }
});
diff --git a/luci2/htdocs/luci2/view/system.cron.js b/luci2/htdocs/luci2/view/system.cron.js
index aae4ce4..c663e01 100644
--- a/luci2/htdocs/luci2/view/system.cron.js
+++ b/luci2/htdocs/luci2/view/system.cron.js
@@ -1,19 +1,33 @@
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);
});
});
});
- }
+ }
});
diff --git a/luci2/htdocs/luci2/view/system.leds.js b/luci2/htdocs/luci2/view/system.leds.js
index c19462d..8165daf 100644
--- a/luci2/htdocs/luci2/view/system.leds.js
+++ b/luci2/htdocs/luci2/view/system.leds.js
@@ -1,98 +1,121 @@
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');
+ }
});
diff --git a/luci2/htdocs/luci2/view/system.software.js b/luci2/htdocs/luci2/view/system.software.js
index 65a86ea..7aed31c 100644
--- a/luci2/htdocs/luci2/view/system.software.js
+++ b/luci2/htdocs/luci2/view/system.software.js
@@ -1,6 +1,120 @@
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) {
@@ -15,19 +129,19 @@ L.ui.view.extend({
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 = [ ];
@@ -52,7 +166,7 @@ L.ui.view.extend({
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;
@@ -67,19 +181,21 @@ L.ui.view.extend({
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');
@@ -88,9 +204,8 @@ L.ui.view.extend({
$('#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: [ {
@@ -159,7 +274,7 @@ L.ui.view.extend({
$('#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);
@@ -168,7 +283,7 @@ L.ui.view.extend({
.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);
@@ -225,7 +340,7 @@ L.ui.view.extend({
$('#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)
diff --git a/luci2/htdocs/luci2/view/system.startup.js b/luci2/htdocs/luci2/view/system.startup.js
index e00e74a..769d12d 100644
--- a/luci2/htdocs/luci2/view/system.startup.js
+++ b/luci2/htdocs/luci2/view/system.startup.js
@@ -1,90 +1,103 @@
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);
+ });
+ });
+ })
+ );
+ }
});
diff --git a/luci2/htdocs/luci2/view/system.system.js b/luci2/htdocs/luci2/view/system.system.js
index 924c45d..90e0012 100644
--- a/luci2/htdocs/luci2/view/system.system.js
+++ b/luci2/htdocs/luci2/view/system.system.js
@@ -1,212 +1,212 @@
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');
+ }
});
diff --git a/luci2/htdocs/luci2/view/system.upgrade.js b/luci2/htdocs/luci2/view/system.upgrade.js
index 9caac28..4c0799c 100644
--- a/luci2/htdocs/luci2/view/system.upgrade.js
+++ b/luci2/htdocs/luci2/view/system.upgrade.js
@@ -1,22 +1,78 @@
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(
@@ -38,7 +94,7 @@ L.ui.view.extend({
], {
style: 'confirm',
confirm: function() {
- //L.system.startUpgrade().then(function() {
+ //self.startUpgrade().then(function() {
// L.ui.reconnect();
//});
@@ -59,7 +115,7 @@ L.ui.view.extend({
], {
style: 'close',
close: function() {
- L.system.cleanUpgrade().then(function() {
+ self.cleanUpgrade().then(function() {
L.ui.dialog(false);
});
}
@@ -69,20 +125,20 @@ L.ui.view.extend({
});
},
- 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'), [
@@ -97,15 +153,15 @@ L.ui.view.extend({
], {
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(
@@ -119,7 +175,7 @@ L.ui.view.extend({
], {
style: 'close',
close: function() {
- L.system.cleanBackup().then(function() {
+ self.cleanBackup().then(function() {
L.ui.dialog(false);
});
}
@@ -138,7 +194,7 @@ L.ui.view.extend({
], {
style: 'close',
close: function() {
- L.system.cleanBackup().then(function() {
+ self.cleanBackup().then(function() {
L.ui.dialog(false);
});
}
@@ -148,18 +204,19 @@ L.ui.view.extend({
});
},
- 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();
//});
@@ -171,7 +228,7 @@ L.ui.view.extend({
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);
}
@@ -180,19 +237,19 @@ L.ui.view.extend({
$('#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)
@@ -202,7 +259,7 @@ L.ui.view.extend({
.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);
@@ -214,7 +271,7 @@ L.ui.view.extend({
$('#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'),
diff --git a/luci2/htdocs/luci2/view/system.users.js b/luci2/htdocs/luci2/view/system.users.js
index 6b30d30..cc495e9 100644
--- a/luci2/htdocs/luci2/view/system.users.js
+++ b/luci2/htdocs/luci2/view/system.users.js
@@ -1,180 +1,180 @@
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)
{
@@ -185,133 +185,133 @@ L.ui.view.extend({
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');
+ });
+ }
});