---[[
-LuCI - Dispatcher
+-- Copyright 2008 Steven Barth <steven@midlink.org>
+-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
+-- Licensed to the public under the Apache License 2.0.
-Description:
-The request dispatcher and module dispatcher generators
-
-FileId:
-$Id$
-
-License:
-Copyright 2008 Steven Barth <steven@midlink.org>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-]]--
-
---- LuCI web dispatcher.
local fs = require "nixio.fs"
local sys = require "luci.sys"
local util = require "luci.util"
local fi
---- Build the URL relative to the server webroot from given virtual path.
--- @param ... Virtual path
--- @return Relative URL
function build_url(...)
local path = {...}
local url = { http.getenv("SCRIPT_NAME") or "" }
return table.concat(url, "")
end
---- Check whether a dispatch node shall be visible
--- @param node Dispatch node
--- @return Boolean indicating whether the node should be visible
function node_visible(node)
if node then
return not (
return false
end
---- Return a sorted table of visible childs within a given node
--- @param node Dispatch node
--- @return Ordered table of child node names
function node_childs(node)
local rv = { }
if node then
end
---- Send a 404 error code and render the "error404" template if available.
--- @param message Custom error message (optional)
--- @return false
function error404(message)
http.status(404, "Not Found")
message = message or "Not Found"
return false
end
---- Send a 500 error code and render the "error500" template if available.
--- @param message Custom error message (optional)#
--- @return false
function error500(message)
util.perror(message)
if not context.template_header_sent then
return user
end
- require("luci.i18n")
- require("luci.template")
- context.path = {}
- luci.template.render("sysauth", {duser=default, fuser=user})
+ if context.urltoken.stok then
+ context.urltoken.stok = nil
+
+ local cookie = 'sysauth=%s; expires=%s; path=%s/' %{
+ http.getcookie('sysauth') or 'x',
+ 'Thu, 01 Jan 1970 01:00:00 GMT',
+ build_url()
+ }
+
+ http.header("Set-Cookie", cookie)
+ http.redirect(build_url())
+ else
+ require("luci.i18n")
+ require("luci.template")
+ context.path = {}
+ http.status(403, "Forbidden")
+ luci.template.render("sysauth", {duser=default, fuser=user})
+ end
+
return false
end
---- Dispatch an HTTP request.
--- @param request LuCI HTTP Request object
function httpdispatch(request, prefix)
http.context.request = request
--context._disable_memtrace()
end
---- Dispatches a LuCI virtual path.
--- @param request Virtual path
function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace("l")
local ctx = context
resource = luci.config.main.resourcebase;
ifattr = function(...) return _ifattr(...) end;
attr = function(...) return _ifattr(true, ...) end;
+ token = ctx.urltoken.stok;
+ url = build_url;
}, {__index=function(table, key)
if key == "controller" then
return build_url()
if not util.contains(accs, user) then
if authen then
- ctx.urltoken.stok = nil
local user, sess = authen(sys.user.checkpasswd, accs, def)
+ local token
if not user or not util.contains(accs, user) then
return
else
if not sess then
- local sdat = util.ubus("session", "create", { timeout = luci.config.sauth.sessiontime })
+ local sdat = util.ubus("session", "create", { timeout = tonumber(luci.config.sauth.sessiontime) })
if sdat then
- local token = sys.uniqueid(16)
+ token = sys.uniqueid(16)
util.ubus("session", "set", {
ubus_rpc_session = sdat.ubus_rpc_session,
values = {
}
})
sess = sdat.ubus_rpc_session
- ctx.urltoken.stok = token
end
end
- if sess then
- http.header("Set-Cookie", "sysauth=" .. sess.."; path="..build_url())
+ if sess and token then
+ http.header("Set-Cookie", 'sysauth=%s; path=%s/' %{
+ sess, build_url()
+ })
+
+ ctx.urltoken.stok = token
ctx.authsession = sess
ctx.authuser = user
+
+ http.redirect(build_url(unpack(ctx.requestpath)))
end
end
else
end
end
+ if c and type(c.target) == "table" and c.target.post == true then
+ if http.getenv("REQUEST_METHOD") ~= "POST" then
+ http.status(405, "Method Not Allowed")
+ http.header("Allow", "POST")
+ return
+ end
+
+ if http.formvalue("token") ~= ctx.urltoken.stok then
+ http.status(403, "Forbidden")
+ luci.template.render("csrftoken")
+ return
+ end
+ end
+
if track.setgroup then
sys.process.setgroup(track.setgroup)
end
if track.setuser then
+ -- trigger ubus connection before dropping root privs
+ util.ubus()
+
sys.process.setuser(track.setuser)
end
end
end
---- Generate the dispatching index using the native file-cache based strategy.
function createindex()
local controllers = { }
local base = "%s/controller/" % util.libpath()
end
end
---- Create the dispatching tree from the index.
-- Build the index before if it does not exist yet.
function createtree()
if not index then
return tree
end
---- Register a tree modifier.
--- @param func Modifier function
--- @param order Modifier order value (optional)
function modifier(func, order)
context.modifiers[#context.modifiers+1] = {
func = func,
}
end
---- Clone a node of the dispatching tree to another position.
--- @param path Virtual path destination
--- @param clone Virtual path source
--- @param title Destination node title (optional)
--- @param order Destination node order value (optional)
--- @return Dispatching tree node
function assign(path, clone, title, order)
local obj = node(unpack(path))
obj.nodes = nil
return obj
end
---- Create a new dispatching node and define common parameters.
--- @param path Virtual path
--- @param target Target function to call when dispatched.
--- @param title Destination node title
--- @param order Destination node order value (optional)
--- @return Dispatching tree node
function entry(path, target, title, order)
local c = node(unpack(path))
return c
end
---- Fetch or create a dispatching node without setting the target module or
-- enabling the node.
--- @param ... Virtual path
--- @return Dispatching tree node
function get(...)
return _create_node({...})
end
---- Fetch or create a new dispatching node.
--- @param ... Virtual path
--- @return Dispatching tree node
function node(...)
local c = _create_node({...})
dispatch(path)
end
---- Alias the first (lowest order) page automatically
function firstchild()
return { type = "firstchild", target = _firstchild }
end
---- Create a redirect to another dispatching node.
--- @param ... Virtual path destination
function alias(...)
local req = {...}
return function(...)
end
end
---- Rewrite the first x path values of the request.
--- @param n Number of path values to replace
--- @param ... Virtual path to replace removed path values with
function rewrite(n, ...)
local req = {...}
return function(...)
end
end
---- Create a function-call dispatching target.
--- @param name Target function of local controller
--- @param ... Additional parameters passed to the function
function call(name, ...)
return {type = "call", argv = {...}, name = name, target = _call}
end
+function post(name, ...)
+ return {
+ type = "call",
+ post = true,
+ argv = { ... },
+ name = name,
+ target = _call
+ }
+end
+
local _template = function(self, ...)
require "luci.template".render(self.view)
end
---- Create a template render dispatching target.
--- @param name Template to be rendered
function template(name)
return {type = "template", view = name, target = _template}
end
local cbi = require "luci.cbi"
local tpl = require "luci.template"
local http = require "luci.http"
+ local disp = require "luci.dispatcher"
+
+ if http.formvalue("cbi.submit") == "1" and
+ http.formvalue("token") ~= disp.context.urltoken.stok
+ then
+ http.status(403, "Forbidden")
+ luci.template.render("csrftoken")
+ return
+ end
local config = self.config or {}
local maps = cbi.load(self.model, ...)
end
end
---- Create a CBI model dispatching target.
--- @param model CBI model to be rendered
function cbi(model, config)
return {type = "cbi", config = config, model = model, target = _cbi}
end
target:target(unpack(argv))
end
---- Create a combined dispatching target for non argv and argv requests.
--- @param trg1 Overview Target
--- @param trg2 Detail Target
function arcombine(trg1, trg2)
return {type = "arcombine", env = getfenv(), target = _arcombine, targets = {trg1, trg2}}
end
local cbi = require "luci.cbi"
local tpl = require "luci.template"
local http = require "luci.http"
+ local disp = require "luci.dispatcher"
+
+ if http.formvalue("cbi.submit") == "1" and
+ http.formvalue("token") ~= disp.context.urltoken.stok
+ then
+ http.status(403, "Forbidden")
+ luci.template.render("csrftoken")
+ return
+ end
local maps = luci.cbi.load(self.model, ...)
local state = nil
tpl.render("footer")
end
---- Create a CBI form model dispatching target.
--- @param model CBI form model tpo be rendered
function form(model)
return {type = "cbi", model = model, target = _form}
end
---- Access the luci.i18n translate() api.
--- @class function
--- @name translate
--- @param text Text to translate
translate = i18n.translate
---- No-op function used to mark translation entries for menu labels.
-- This function does not actually translate the given argument but
-- is used by build/i18n-scan.pl to find translatable entries.
function _(text)