summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2019-08-14 16:42:55 +0200
committerJo-Philipp Wich <jo@mein.io>2019-08-14 22:58:15 +0200
commita4621c95201a6ac436b3cfdc9bf6ed2d2571e607 (patch)
treeac4402d775b857eee27e649e12b541f2602502ec
parent3b335f2764bfda3f18e13bf492e461977599e411 (diff)
luci-base: luci.js: introduce hasSystemFeature() api
The new function allows querying the presence of certain system features such as dnsmasq or firewall availability or the compile time features of hostapd and wpa_supplicant. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/luci.js44
-rwxr-xr-xmodules/luci-base/root/usr/libexec/rpcd/luci86
-rw-r--r--modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json9
3 files changed, 137 insertions, 2 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/luci.js b/modules/luci-base/htdocs/luci-static/resources/luci.js
index 66f32d722..d72764b11 100644
--- a/modules/luci-base/htdocs/luci-static/resources/luci.js
+++ b/modules/luci-base/htdocs/luci-static/resources/luci.js
@@ -559,6 +559,7 @@
domParser = null,
originalCBIInit = null,
rpcBaseURL = null,
+ sysFeatures = null,
classes = {};
var LuCI = Class.extend({
@@ -797,6 +798,43 @@
return Promise.resolve(rpcBaseURL);
},
+ probeSystemFeatures: function() {
+ if (sysFeatures == null) {
+ try {
+ sysFeatures = JSON.parse(window.sessionStorage.getItem('sysFeatures'));
+ }
+ catch (e) {}
+ }
+
+ if (!this.isObject(sysFeatures)) {
+ sysFeatures = classes.rpc.declare({
+ object: 'luci',
+ method: 'getFeatures',
+ expect: { '': {} }
+ })().then(function(features) {
+ try {
+ window.sessionStorage.setItem('sysFeatures', JSON.stringify(features));
+ }
+ catch (e) {}
+
+ sysFeatures = features;
+
+ return features;
+ });
+ }
+
+ return Promise.resolve(sysFeatures);
+ },
+
+ hasSystemFeature: function() {
+ var ft = sysFeatures[arguments[0]];
+
+ if (arguments.length == 2)
+ return this.isObject(ft) ? ft[arguments[1]] : null;
+
+ return (ft != null && ft != false);
+ },
+
setupDOM: function(res) {
var domEv = res[0],
uiClass = res[1],
@@ -828,10 +866,12 @@
throw 'Session expired';
});
- originalCBIInit();
+ return this.probeSystemFeatures().finally(this.initDOM);
+ },
+ initDOM: function() {
+ originalCBIInit();
Poll.start();
-
document.dispatchEvent(new CustomEvent('luci-loaded'));
},
diff --git a/modules/luci-base/root/usr/libexec/rpcd/luci b/modules/luci-base/root/usr/libexec/rpcd/luci
index 7644745ef..d2e90bc35 100755
--- a/modules/luci-base/root/usr/libexec/rpcd/luci
+++ b/modules/luci-base/root/usr/libexec/rpcd/luci
@@ -320,6 +320,92 @@ local methods = {
return { helpers = rv }
end
+ },
+
+ getFeatures = {
+ call = function()
+ local fs = require "nixio.fs"
+ local rv = {}
+ local ok, fd
+
+ rv.firewall = fs.access("/sbin/fw3")
+ rv.opkg = fs.access("/bin/opkg")
+ rv.offloading = fs.access("/sys/module/xt_FLOWOFFLOAD/refcnt")
+ rv.br2684ctl = fs.access("/usr/sbin/br2684ctl")
+ rv.swconfig = fs.access("/sbin/swconfig")
+ rv.odhcpd = fs.access("/usr/sbin/odhcpd")
+
+ local wifi_features = { "eap", "11n", "11ac", "11r", "11w", "acs", "sae", "owe", "suiteb192" }
+
+ if fs.access("/usr/sbin/hostapd") then
+ rv.hostapd = {}
+
+ local _, feature
+ for _, feature in ipairs(wifi_features) do
+ rv.hostapd[feature] =
+ (os.execute(string.format("/usr/sbin/hostapd -v%s >/dev/null 2>/dev/null", feature)) == 0)
+ end
+ end
+
+ if fs.access("/usr/sbin/wpa_supplicant") then
+ rv.wpasupplicant = {}
+
+ local _, feature
+ for _, feature in ipairs(wifi_features) do
+ rv.wpasupplicant[feature] =
+ (os.execute(string.format("/usr/sbin/wpa_supplicant -v%s >/dev/null 2>/dev/null", feature)) == 0)
+ end
+ end
+
+ ok, fd = pcall(io.popen, "dnsmasq --version 2>/dev/null")
+ if ok then
+ rv.dnsmasq = {}
+
+ while true do
+ local line = fd:read("*l")
+ if not line then
+ break
+ end
+
+ local opts = line:match("^Compile time options: (.+)$")
+ if opts then
+ local opt
+ for opt in opts:gmatch("%S+") do
+ local no = opt:match("^no%-(%S+)$")
+ rv.dnsmasq[string.lower(no or opt)] = not no
+ end
+ break
+ end
+ end
+
+ fd:close()
+ end
+
+ ok, fd = pcall(io.popen, "ipset --help 2>/dev/null")
+ if ok then
+ rv.ipset = {}
+
+ local sets = false
+
+ while true do
+ local line = fd:read("*l")
+ if not line then
+ break
+ elseif line:match("^Supported set types:") then
+ sets = true
+ elseif sets then
+ local set, ver = line:match("^%s+(%S+)%s+(%d+)")
+ if set and not rv.ipset[set] then
+ rv.ipset[set] = tonumber(ver)
+ end
+ end
+ end
+
+ fd:close()
+ end
+
+ return rv
+ end
}
}
diff --git a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json
index e58c9947b..5d08a4eab 100644
--- a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json
+++ b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json
@@ -1,4 +1,13 @@
{
+ "unauthenticated": {
+ "description": "Allow system feature probing",
+ "read": {
+ "ubus": {
+ "luci": [ "getFeatures" ]
+ }
+ }
+ },
+
"uci-access": {
"description": "Grant uci write access to all configurations",
"read": {