Rework the apply confirmation mechanism to be session agnostic in order to circumvent cross domain restrictions which prevent the JS code from issuing apply confirm requests in some cases, e.g. when changing the LAN IP. Confirmation calls may now be done from unauthenticated pages, as long as a matching confirmation token is sent along with the request. The reasoning behind this is that there is little security impact in confirming pending apply sessions, especially since those sessions can only be initiated while being authenticated. After this change, LuCI will now launch a confirmation process on every rendered page when a rollback is pending. The confirmation will happen regardless of whether the user is logged in or not, or if the current page is a CBI form or static template. A confirmation request now also requires a random one-time token which is rendered along with the confirmation JavaScript code in order to succeed. This token is not meant to provide security but to ensure that the confirm was triggered from an interactive browser session and not some background HTTP requests that happened to end up in the admin ui. As a consequence, the different apply/confirm/rollback code paths in CBI maps and the UCI change/revert pages have been consolidated into one common implementation residing in the common global theme agnostic footer template. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
109 lines
2.8 KiB
Lua
109 lines
2.8 KiB
Lua
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
|
-- Copyright 2010-2015 Jo-Philipp Wich <jow@openwrt.org>
|
|
-- Licensed to the public under the Apache License 2.0.
|
|
|
|
module("luci.controller.admin.uci", package.seeall)
|
|
|
|
function index()
|
|
local redir = luci.http.formvalue("redir", true)
|
|
or table.concat(luci.dispatcher.context.request, "/")
|
|
|
|
entry({"admin", "uci"}, nil, _("Configuration"))
|
|
entry({"admin", "uci", "changes"}, post_on({ trigger_apply = true }, "action_changes"), _("Changes"), 40).query = {redir=redir}
|
|
entry({"admin", "uci", "revert"}, post("action_revert"), _("Revert"), 30).query = {redir=redir}
|
|
|
|
local node
|
|
local authen = function(checkpass, allowed_users)
|
|
return "root", luci.http.formvalue("sid")
|
|
end
|
|
|
|
node = entry({"admin", "uci", "apply_rollback"}, post("action_apply_rollback"), nil)
|
|
node.cors = true
|
|
node.sysauth_authenticator = authen
|
|
|
|
node = entry({"admin", "uci", "apply_unchecked"}, post("action_apply_unchecked"), nil)
|
|
node.cors = true
|
|
node.sysauth_authenticator = authen
|
|
|
|
node = entry({"admin", "uci", "confirm"}, call("action_confirm"), nil)
|
|
node.cors = true
|
|
node.sysauth = false
|
|
end
|
|
|
|
|
|
function action_changes()
|
|
local uci = require "luci.model.uci"
|
|
local changes = uci:changes()
|
|
|
|
luci.template.render("admin_uci/changes", {
|
|
changes = next(changes) and changes,
|
|
timeout = timeout,
|
|
trigger_apply = luci.http.formvalue("trigger_apply") and true or false
|
|
})
|
|
end
|
|
|
|
function action_revert()
|
|
local uci = require "luci.model.uci"
|
|
local changes = uci:changes()
|
|
|
|
-- Collect files to be reverted
|
|
local r, tbl
|
|
for r, tbl in pairs(changes) do
|
|
uci:revert(r)
|
|
end
|
|
|
|
luci.template.render("admin_uci/revert", {
|
|
changes = next(changes) and changes,
|
|
trigger_revert = true
|
|
})
|
|
end
|
|
|
|
|
|
local function ubus_state_to_http(errstr)
|
|
local map = {
|
|
["Invalid command"] = 400,
|
|
["Invalid argument"] = 400,
|
|
["Method not found"] = 404,
|
|
["Entry not found"] = 404,
|
|
["No data"] = 204,
|
|
["Permission denied"] = 403,
|
|
["Timeout"] = 504,
|
|
["Not supported"] = 500,
|
|
["Unknown error"] = 500,
|
|
["Connection failed"] = 503
|
|
}
|
|
|
|
local code = map[errstr] or 200
|
|
local msg = errstr or "OK"
|
|
|
|
luci.http.status(code, msg)
|
|
|
|
if code ~= 204 then
|
|
luci.http.prepare_content("text/plain")
|
|
luci.http.write(msg)
|
|
end
|
|
end
|
|
|
|
function action_apply_rollback()
|
|
local uci = require "luci.model.uci"
|
|
local token, errstr = uci:apply(true)
|
|
if token then
|
|
luci.http.prepare_content("application/json")
|
|
luci.http.write_json({ token = token })
|
|
else
|
|
ubus_state_to_http(errstr)
|
|
end
|
|
end
|
|
|
|
function action_apply_unchecked()
|
|
local uci = require "luci.model.uci"
|
|
local _, errstr = uci:apply(false)
|
|
ubus_state_to_http(errstr)
|
|
end
|
|
|
|
function action_confirm()
|
|
local uci = require "luci.model.uci"
|
|
local token = luci.http.formvalue("token")
|
|
local _, errstr = uci:confirm(token)
|
|
ubus_state_to_http(errstr)
|
|
end
|