summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/luasrc
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2019-02-07 18:40:36 +0100
committerJo-Philipp Wich <jo@mein.io>2019-07-07 15:25:49 +0200
commitc89bbd50fdba8b07930c29bae6ca71cc54515e2c (patch)
treefea7f220e1fa00538b6c3270910afc5cf33bd43d /modules/luci-base/luasrc
parent558f8c3b2a40d187068e339be70d4173b555d4a5 (diff)
luci-base: add ubus-http gateway
Add an admin/ubus route mimicking the native uhttpd-mod-ubus protocol. The main difference to the native protocol is that this gateway requires no additional per-object/procedure ACL setup on the router side and that it is located under the same prefix as LuCI itself, allowing the reuse of the session login cookie. This route is meant to be a transitional mechanism until client side RPC calls are eventually migrated to uhttpd-mod-ubus completely. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'modules/luci-base/luasrc')
-rw-r--r--modules/luci-base/luasrc/controller/admin/index.lua112
1 files changed, 112 insertions, 0 deletions
diff --git a/modules/luci-base/luasrc/controller/admin/index.lua b/modules/luci-base/luasrc/controller/admin/index.lua
index 1f7db0cb3..259c34eee 100644
--- a/modules/luci-base/luasrc/controller/admin/index.lua
+++ b/modules/luci-base/luasrc/controller/admin/index.lua
@@ -88,6 +88,9 @@ function index()
page = entry({"admin", "translations"}, call("action_translations"), nil)
page.leaf = true
+ page = entry({"admin", "ubus"}, call("action_ubus"), nil)
+ page.leaf = true
+
-- Logout is last
entry({"admin", "logout"}, call("action_logout"), _("Logout"), 999)
end
@@ -129,6 +132,115 @@ function action_translations(lang)
http.write_json(i18n.dump())
end
+local function ubus_reply(id, data, code, errmsg)
+ local reply = { jsonrpc = "2.0", id = id }
+ if errmsg then
+ reply.error = {
+ code = code,
+ message = errmsg
+ }
+ else
+ reply.result = { code, data }
+ end
+
+ return reply
+end
+
+local ubus_types = {
+ nil,
+ "array",
+ "object",
+ "string",
+ nil, -- INT64
+ "number",
+ nil, -- INT16,
+ "boolean",
+ "double"
+}
+
+local function ubus_request(req)
+ if type(req) ~= "table" or type(req.method) ~= "string" or type(req.params) ~= "table" or
+ #req.params < 2 or req.jsonrpc ~= "2.0" or req.id == nil then
+ return ubus_reply(req.id, nil, -32600, "Invalid request")
+
+ elseif req.method == "call" then
+ local sid, obj, fun, arg =
+ req.params[1], req.params[2], req.params[3], req.params[4] or {}
+ if type(arg) ~= "table" or arg.ubus_rpc_session ~= nil then
+ return ubus_reply(req.id, nil, -32602, "Invalid parameters")
+ end
+
+ if sid == "00000000000000000000000000000000" then
+ sid = luci.dispatcher.context.authsession
+ end
+
+ arg.ubus_rpc_session = sid
+
+ local res, code = luci.util.ubus(obj, fun, arg)
+ return ubus_reply(req.id, res, code or 0)
+
+ elseif req.method == "list" then
+ if type(params) ~= "table" or #params == 0 then
+ local objs = { luci.util.ubus() }
+ return ubus_reply(req.id, objs, 0)
+ else
+ local n, rv = nil, {}
+ for n = 1, #params do
+ if type(params[n]) ~= "string" then
+ return ubus_reply(req.id, nil, -32602, "Invalid parameters")
+ end
+
+ local sig = luci.util.ubus(params[n])
+ if sig and type(sig) == "table" then
+ rv[params[n]] = {}
+
+ local m, p
+ for m, p in pairs(sig) do
+ if type(p) == "table" then
+ rv[params[n]][m] = {}
+
+ local pn, pt
+ for pn, pt in pairs(p) do
+ rv[params[n]][m][pn] = ubus_types[pt] or "unknown"
+ end
+ end
+ end
+ end
+ end
+ return ubus_reply(req.id, rv, 0)
+ end
+ end
+
+ return ubus_reply(req.id, nil, -32601, "Method not found")
+end
+
+function action_ubus()
+ local parser = require "luci.jsonc".new()
+ luci.http.context.request:setfilehandler(function(_, s) parser:parse(s or "") end)
+ luci.http.context.request:content()
+
+ local json = parser:get()
+ if json == nil or type(json) ~= "table" then
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(ubus_reply(nil, nil, -32700, "Parse error"))
+ return
+ end
+
+ local response
+ if #json == 0 then
+ response = ubus_request(json)
+ else
+ response = {}
+
+ local _, request
+ for _, request in ipairs(json) do
+ response[_] = ubus_request(request)
+ end
+ end
+
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(response)
+end
function lease_status()
local s = require "luci.tools.status"