luci-base: expose luci.dispatcher.build_url() as url() in templates
[project/luci.git] / modules / luci-base / luasrc / dispatcher.lua
index 795b62b..5d9d1b0 100644 (file)
@@ -1,4 +1,5 @@
 -- 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.
 
 local fs = require "nixio.fs"
@@ -114,7 +115,14 @@ function authenticator.htmlauth(validator, accs, default)
 
        if context.urltoken.stok then
                context.urltoken.stok = nil
-               http.header("Set-Cookie", "sysauth=; path="..build_url())
+
+               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")
@@ -277,6 +285,8 @@ function dispatch(request)
                   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()
@@ -329,13 +339,14 @@ function dispatch(request)
                if not util.contains(accs, user) then
                        if authen then
                                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 = {
@@ -345,15 +356,19 @@ function dispatch(request)
                                                                }
                                                        })
                                                        sess = sdat.ubus_rpc_session
-                                                       ctx.urltoken.stok = token
                                                end
                                        end
 
-                                       if sess then
-                                               http.header("Set-Cookie", "sysauth=" .. sess.."; path="..build_url())
-                                               http.redirect(build_url(unpack(ctx.requestpath)))
+                                       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
@@ -366,11 +381,28 @@ function dispatch(request)
                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
 
@@ -688,6 +720,16 @@ 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)
@@ -702,6 +744,15 @@ local function _cbi(self, ...)
        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, ...)
@@ -819,6 +870,15 @@ local function _form(self, ...)
        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