diff options
Diffstat (limited to 'modules')
70 files changed, 1902 insertions, 2000 deletions
diff --git a/modules/luci-base/Makefile b/modules/luci-base/Makefile index d3039ef41b..7f7d7e772f 100644 --- a/modules/luci-base/Makefile +++ b/modules/luci-base/Makefile @@ -12,8 +12,7 @@ LUCI_TYPE:=mod LUCI_BASENAME:=base LUCI_TITLE:=LuCI core libraries -LUCI_DEPENDS:=+lua +libuci-lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc -LUCI_EXTRA_DEPENDS:=libuci-lua (>= 2018-01-01) +LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua PKG_SOURCE:=LuaSrcDiet-0.12.1.tar.bz2 PKG_SOURCE_URL:=https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/luasrcdiet diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js index d40ec34bc6..6c35372cdd 100644 --- a/modules/luci-base/htdocs/luci-static/resources/cbi.js +++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js @@ -218,12 +218,13 @@ var cbi_validators = { ((ipv4only == 1) && cbi_validators.ip4addr.apply(this)); }, - 'hostname': function() + 'hostname': function(strict) { if (this.length <= 253) - return (this.match(/^[a-zA-Z0-9]+$/) != null || + return (this.match(/^[a-zA-Z0-9_]+$/) != null || (this.match(/^[a-zA-Z0-9_][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$/) && - this.match(/[^0-9.]/))); + this.match(/[^0-9.]/))) && + (!strict || !this.match(/^_/)); return false; }, diff --git a/modules/luci-base/htdocs/luci-static/resources/xhr.js b/modules/luci-base/htdocs/luci-static/resources/xhr.js index 3385f8f230..91dcf3fefe 100644 --- a/modules/luci-base/htdocs/luci-static/resources/xhr.js +++ b/modules/luci-base/htdocs/luci-static/resources/xhr.js @@ -39,7 +39,7 @@ XHR = function() this._xmlHttp.abort(); } - this.get = function(url,data,callback) + this.get = function(url,data,callback,timeout) { this.reinit(); @@ -54,6 +54,9 @@ XHR = function() else url += '?' + code; + if (!isNaN(timeout)) + xhr.timeout = timeout; + xhr.open('GET', url, true); xhr.onreadystatechange = function() @@ -76,7 +79,7 @@ XHR = function() xhr.send(null); } - this.post = function(url,data,callback) + this.post = function(url,data,callback,timeout) { this.reinit(); @@ -89,6 +92,9 @@ XHR = function() callback(xhr); } + if (!isNaN(timeout)) + xhr.timeout = timeout; + xhr.open('POST', url, true); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(code); @@ -168,7 +174,7 @@ XHR.get = function(url, data, callback) (new XHR()).get(url, data, callback); } -XHR.poll = function(interval, url, data, callback) +XHR.poll = function(interval, url, data, callback, post) { if (isNaN(interval) || interval < 1) interval = 5; @@ -181,22 +187,38 @@ XHR.poll = function(interval, url, data, callback) for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i]) { if (!(XHR._t % e.interval) && !e.xhr.busy()) - e.xhr.get(e.url, e.data, e.callback); + e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 - 5); } XHR._t++; }; } - XHR._q.push({ + var e = { interval: interval, callback: callback, url: url, data: data, xhr: new XHR() - }); + }; + XHR._q.push(e); XHR.run(); + + return e; +} + +XHR.stop = function(e) +{ + for (var i = 0; XHR._q && XHR._q[i]; i++) { + if (XHR._q[i] === e) { + e.xhr.cancel(); + XHR._q.splice(i, 1); + return true; + } + } + + return false; } XHR.halt = function() diff --git a/modules/luci-base/luasrc/cbi/datatypes.lua b/modules/luci-base/luasrc/cbi/datatypes.lua index 55cdf8a74b..99113e0b7a 100644 --- a/modules/luci-base/luasrc/cbi/datatypes.lua +++ b/modules/luci-base/luasrc/cbi/datatypes.lua @@ -199,13 +199,13 @@ function macaddr(val) return ip.checkmac(val) and true or false end -function hostname(val) +function hostname(val, strict) if val and (#val < 254) and ( val:match("^[a-zA-Z_]+$") or (val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and val:match("[^0-9%.]")) ) then - return true + return (not strict or not val:match("^_")) end return false end diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 16b32548e6..1984fc4ad2 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -75,11 +75,16 @@ function error404(message) http.status(404, "Not Found") message = message or "Not Found" - require("luci.template") - if not util.copcall(luci.template.render, "error404") then + local function render() + local template = require "luci.template" + template.render("error404") + end + + if not util.copcall(render) then http.prepare_content("text/plain") http.write(message) end + return false end @@ -113,7 +118,8 @@ function httpdispatch(request, prefix) end end - for node in pathinfo:gmatch("[^/]+") do + local node + for node in pathinfo:gmatch("[^/%z]+") do r[#r+1] = node end @@ -136,8 +142,7 @@ local function require_post_security(target) if (type(required_val) == "string" and request_val ~= required_val) or - (required_val == true and - (request_val == nil or request_val == "")) + (required_val == true and request_val == nil) then return false end @@ -346,15 +351,23 @@ function dispatch(request) ifattr = function(...) return _ifattr(...) end; attr = function(...) return _ifattr(true, ...) end; url = build_url; - }, {__index=function(table, key) + }, {__index=function(tbl, key) if key == "controller" then return build_url() elseif key == "REQUEST_URI" then return build_url(unpack(ctx.requestpath)) + elseif key == "FULL_REQUEST_URI" then + local url = { http.getenv("SCRIPT_NAME"), http.getenv("PATH_INFO") } + local query = http.getenv("QUERY_STRING") + if query and #query > 0 then + url[#url+1] = "?" + url[#url+1] = query + end + return table.concat(url, "") elseif key == "token" then return ctx.authtoken else - return rawget(table, key) or _G[key] + return rawget(tbl, key) or _G[key] end end}) end @@ -429,6 +442,13 @@ function dispatch(request) ctx.authuser = sdat.username end + if track.cors and http.getenv("REQUEST_METHOD") == "OPTIONS" then + luci.http.status(200, "OK") + luci.http.header("Access-Control-Allow-Origin", http.getenv("HTTP_ORIGIN") or "*") + luci.http.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + return + end + if c and require_post_security(c.target) then if not test_post_security(c) then return @@ -650,6 +670,23 @@ function node(...) return c end +function lookup(...) + local i, path = nil, {} + for i = 1, select('#', ...) do + local name, arg = nil, tostring(select(i, ...)) + for name in arg:gmatch("[^/]+") do + path[#path+1] = name + end + end + + for i = #path, 1, -1 do + local node = context.treecache[table.concat(path, ".", 1, i)] + if node and (i == #path or node.leaf) then + return node, build_url(unpack(path)) + end + end +end + function _create_node(path) if #path == 0 then return context.tree @@ -791,7 +828,16 @@ local function _cbi(self, ...) local state = nil + local i, res for i, res in ipairs(maps) do + if util.instanceof(res, cbi.SimpleForm) then + io.stderr:write("Model %s returns SimpleForm but is dispatched via cbi(),\n" + % self.model) + + io.stderr:write("please change %s to use the form() action instead.\n" + % table.concat(context.request, "/")) + end + res.flow = config local cstate = res:parse() if cstate and (not state or cstate < state) then @@ -884,7 +930,7 @@ end function cbi(model, config) return { type = "cbi", - post = { ["cbi.submit"] = "1" }, + post = { ["cbi.submit"] = true }, config = config, model = model, target = _cbi @@ -912,6 +958,7 @@ local function _form(self, ...) local maps = luci.cbi.load(self.model, ...) local state = nil + local i, res for i, res in ipairs(maps) do local cstate = res:parse() if cstate and (not state or cstate < state) then @@ -930,7 +977,7 @@ end function form(model) return { type = "cbi", - post = { ["cbi.submit"] = "1" }, + post = { ["cbi.submit"] = true }, model = model, target = _form } diff --git a/modules/luci-base/luasrc/dispatcher.luadoc b/modules/luci-base/luasrc/dispatcher.luadoc index 743463c74f..ddf534b3e1 100644 --- a/modules/luci-base/luasrc/dispatcher.luadoc +++ b/modules/luci-base/luasrc/dispatcher.luadoc @@ -116,8 +116,8 @@ Create a new dispatching node and define common parameters. ---[[ Fetch or create a dispatching node without setting the target module or - enabling the node. + @class function @name get @param ... Virtual path @@ -134,6 +134,15 @@ Fetch or create a new dispatching node. ]] ---[[ +Lookup node in dispatching tree. + +@class function +@name lookup +@param ... Virtual path +@return Node object, canonical url or nil if the path was not found. +]] + +---[[ Alias the first (lowest order) page automatically diff --git a/modules/luci-base/luasrc/http.lua b/modules/luci-base/luasrc/http.lua index 9cc9857867..16fb04c549 100644 --- a/modules/luci-base/luasrc/http.lua +++ b/modules/luci-base/luasrc/http.lua @@ -1,18 +1,21 @@ -- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2010-2018 Jo-Philipp Wich <jo@mein.io> -- Licensed to the public under the Apache License 2.0. -local ltn12 = require "luci.ltn12" -local protocol = require "luci.http.protocol" local util = require "luci.util" -local string = require "string" local coroutine = require "coroutine" local table = require "table" +local lhttp = require "lucihttp" +local nixio = require "nixio" +local ltn12 = require "luci.ltn12" -local ipairs, pairs, next, type, tostring, error = - ipairs, pairs, next, type, tostring, error +local table, ipairs, pairs, type, tostring, tonumber, error = + table, ipairs, pairs, type, tostring, tonumber, error module "luci.http" +HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size + context = util.threadlocal() Request = util.class() @@ -28,7 +31,7 @@ function Request.__init__(self, env, sourcein, sinkerr) self.message = { env = env, headers = {}, - params = protocol.urldecode_params(env.QUERY_STRING or ""), + params = urldecode_params(env.QUERY_STRING or ""), } self.parsed_input = false @@ -73,10 +76,7 @@ function Request.content(self) end function Request.getcookie(self, name) - local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";") - local p = ";" .. name .. "=(.-);" - local i, j, value = c:find(p) - return value and urldecode(value) + return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name) end function Request.getenv(self, name) @@ -90,40 +90,34 @@ end function Request.setfilehandler(self, callback) self.filehandler = callback - -- If input has already been parsed then any files are either in temporary files - -- or are in self.message.params[key] - if self.parsed_input then - for param, value in pairs(self.message.params) do - repeat - -- We're only interested in files - if (not value["file"]) then break end - -- If we were able to write to temporary file - if (value["fd"]) then - fd = value["fd"] - local eof = false - repeat - filedata = fd:read(1024) - if (filedata:len() < 1024) then - eof = true - end - callback({ name=value["name"], file=value["file"] }, filedata, eof) - until (eof) - fd:close() - value["fd"] = nil - -- We had to read into memory - else - -- There should only be one numbered value in table - the data - for k, v in ipairs(value) do - callback({ name=value["name"], file=value["file"] }, v, true) + if not self.parsed_input then + return + end + + -- If input has already been parsed then uploads are stored as unlinked + -- temporary files pointed to by open file handles in the parameter + -- value table. Loop all params, and invoke the file callback for any + -- param with an open file handle. + local name, value + for name, value in pairs(self.message.params) do + if type(value) == "table" then + while value.fd do + local data = value.fd:read(1024) + local eof = (not data or data == "") + + callback(value, data, eof) + + if eof then + value.fd:close() + value.fd = nil end end - until true end end end function Request._parse_input(self) - protocol.parse_message_body( + parse_message_body( self.input, self.message, self.filehandler @@ -254,23 +248,307 @@ function redirect(url) end function build_querystring(q) - local s = { "?" } + local s, n, k, v = {}, 1, nil, nil for k, v in pairs(q) do - if #s > 1 then s[#s+1] = "&" end - - s[#s+1] = urldecode(k) - s[#s+1] = "=" - s[#s+1] = urldecode(v) + s[n+0] = (n == 1) and "?" or "&" + s[n+1] = util.urlencode(k) + s[n+2] = "=" + s[n+3] = util.urlencode(v) + n = n + 4 end return table.concat(s, "") end -urldecode = protocol.urldecode +urldecode = util.urldecode -urlencode = protocol.urlencode +urlencode = util.urlencode function write_json(x) util.serialize_json(x, write) end + +-- from given url or string. Returns a table with urldecoded values. +-- Simple parameters are stored as string values associated with the parameter +-- name within the table. Parameters with multiple values are stored as array +-- containing the corresponding values. +function urldecode_params(url, tbl) + local parser, name + local params = tbl or { } + + parser = lhttp.urlencoded_parser(function (what, buffer, length) + if what == parser.TUPLE then + name, value = nil, nil + elseif what == parser.NAME then + name = lhttp.urldecode(buffer) + elseif what == parser.VALUE and name then + params[name] = lhttp.urldecode(buffer) or "" + end + + return true + end) + + if parser then + parser:parse((url or ""):match("[^?]*$")) + parser:parse(nil) + end + + return params +end + +-- separated by "&". Tables are encoded as parameters with multiple values by +-- repeating the parameter name with each value. +function urlencode_params(tbl) + local k, v + local n, enc = 1, {} + for k, v in pairs(tbl) do + if type(v) == "table" then + local i, v2 + for i, v2 in ipairs(v) do + if enc[1] then + enc[n] = "&" + n = n + 1 + end + + enc[n+0] = lhttp.urlencode(k) + enc[n+1] = "=" + enc[n+2] = lhttp.urlencode(v2) + n = n + 3 + end + else + if enc[1] then + enc[n] = "&" + n = n + 1 + end + + enc[n+0] = lhttp.urlencode(k) + enc[n+1] = "=" + enc[n+2] = lhttp.urlencode(v) + n = n + 3 + end + end + + return table.concat(enc, "") +end + +-- Content-Type. Stores all extracted data associated with its parameter name +-- in the params table within the given message object. Multiple parameter +-- values are stored as tables, ordinary ones as strings. +-- If an optional file callback function is given then it is feeded with the +-- file contents chunk by chunk and only the extracted file name is stored +-- within the params table. The callback function will be called subsequently +-- with three arguments: +-- o Table containing decoded (name, file) and raw (headers) mime header data +-- o String value containing a chunk of the file data +-- o Boolean which indicates wheather the current chunk is the last one (eof) +function mimedecode_message_body(src, msg, file_cb) + local parser, header, field + local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) + + parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length) + if what == parser.PART_INIT then + field = { } + + elseif what == parser.HEADER_NAME then + header = buffer:lower() + + elseif what == parser.HEADER_VALUE and header then + if header:lower() == "content-disposition" and + lhttp.header_attribute(buffer, nil) == "form-data" + then + field.name = lhttp.header_attribute(buffer, "name") + field.file = lhttp.header_attribute(buffer, "filename") + field[1] = field.file + end + + if field.headers then + field.headers[header] = buffer + else + field.headers = { [header] = buffer } + end + + elseif what == parser.PART_BEGIN then + return not field.file + + elseif what == parser.PART_DATA and field.name and length > 0 then + if field.file then + if file_cb then + file_cb(field, buffer, false) + msg.params[field.name] = msg.params[field.name] or field + else + if not field.fd then + field.fd = nixio.mkstemp(field.name) + end + + if field.fd then + field.fd:write(buffer) + msg.params[field.name] = msg.params[field.name] or field + end + end + else + field.value = buffer + end + + elseif what == parser.PART_END and field.name then + if field.file and msg.params[field.name] then + if file_cb then + file_cb(field, "", true) + elseif field.fd then + field.fd:seek(0, "set") + end + else + local val = msg.params[field.name] + + if type(val) == "table" then + val[#val+1] = field.value or "" + elseif val ~= nil then + msg.params[field.name] = { val, field.value or "" } + else + msg.params[field.name] = field.value or "" + end + end + + field = nil + + elseif what == parser.ERROR then + err = buffer + end + + return true + end) + + return ltn12.pump.all(src, function (chunk) + len = len + (chunk and #chunk or 0) + + if maxlen and len > maxlen + 2 then + return nil, "Message body size exceeds Content-Length" + end + + if not parser or not parser:parse(chunk) then + return nil, err + end + + return true + end) +end + +-- Content-Type. Stores all extracted data associated with its parameter name +-- in the params table within the given message object. Multiple parameter +-- values are stored as tables, ordinary ones as strings. +function urldecode_message_body(src, msg) + local err, name, value, parser + local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) + + parser = lhttp.urlencoded_parser(function (what, buffer, length) + if what == parser.TUPLE then + name, value = nil, nil + elseif what == parser.NAME then + name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) + elseif what == parser.VALUE and name then + local val = msg.params[name] + + if type(val) == "table" then + val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" + elseif val ~= nil then + msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" } + else + msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" + end + elseif what == parser.ERROR then + err = buffer + end + + return true + end) + + return ltn12.pump.all(src, function (chunk) + len = len + (chunk and #chunk or 0) + + if maxlen and len > maxlen + 2 then + return nil, "Message body size exceeds Content-Length" + elseif len > HTTP_MAX_CONTENT then + return nil, "Message body size exceeds maximum allowed length" + end + + if not parser or not parser:parse(chunk) then + return nil, err + end + + return true + end) +end + +-- This function will examine the Content-Type within the given message object +-- to select the appropriate content decoder. +-- Currently the application/x-www-urlencoded and application/form-data +-- mime types are supported. If the encountered content encoding can't be +-- handled then the whole message body will be stored unaltered as "content" +-- property within the given message object. +function parse_message_body(src, msg, filecb) + if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then + local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil) + + -- Is it multipart/mime ? + if ctype == "multipart/form-data" then + return mimedecode_message_body(src, msg, filecb) + + -- Is it application/x-www-form-urlencoded ? + elseif ctype == "application/x-www-form-urlencoded" then + return urldecode_message_body(src, msg) + + end + + -- Unhandled encoding + -- If a file callback is given then feed it chunk by chunk, else + -- store whole buffer in message.content + local sink + + -- If we have a file callback then feed it + if type(filecb) == "function" then + local meta = { + name = "raw", + encoding = msg.env.CONTENT_TYPE + } + sink = function( chunk ) + if chunk then + return filecb(meta, chunk, false) + else + return filecb(meta, nil, true) + end + end + -- ... else append to .content + else + msg.content = "" + msg.content_length = 0 + + sink = function( chunk ) + if chunk then + if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then + msg.content = msg.content .. chunk + msg.content_length = msg.content_length + #chunk + return true + else + return nil, "POST data exceeds maximum allowed length" + end + end + return true + end + end + + -- Pump data... + while true do + local ok, err = ltn12.pump.step( src, sink ) + + if not ok and err then + return nil, err + elseif not ok then -- eof + return true + end + end + + return true + end + + return false +end diff --git a/modules/luci-base/luasrc/http.luadoc b/modules/luci-base/luasrc/http.luadoc index 8a325db21a..f8121230b6 100644 --- a/modules/luci-base/luasrc/http.luadoc +++ b/modules/luci-base/luasrc/http.luadoc @@ -6,25 +6,24 @@ module "luci.http" ---[[ Close the HTTP-Connection. - -@class function -@name close +@class function +@name close ]] ---[[ Return the request content if the request was of unknown type. -@class function -@name content -@return HTTP request body -@return HTTP request body length +@class function +@name content +@return HTTP request body +@return HTTP request body length ]] ---[[ Get a certain HTTP input value or a table of all input values. -@class function -@name formvalue +@class function +@name formvalue @param name Name of the GET or POST variable to fetch @param noparse Don't parse POST data before getting the value @return HTTP input value or table of all input value @@ -33,8 +32,8 @@ Get a certain HTTP input value or a table of all input values. ---[[ Get a table of all HTTP input values with a certain prefix. -@class function -@name formvaluetable +@class function +@name formvaluetable @param prefix Prefix @return Table of all HTTP input values with given prefix ]] @@ -42,18 +41,18 @@ Get a table of all HTTP input values with a certain prefix. ---[[ Get the value of a certain HTTP-Cookie. -@class function -@name getcookie +@class function +@name getcookie @param name Cookie Name @return String containing cookie data ]] ---[[ Get the value of a certain HTTP environment variable - or the environment table itself. -@class function -@name getenv + +@class function +@name getenv @param name Environment variable @return HTTP environment value or environment table ]] @@ -61,41 +60,41 @@ or the environment table itself. ---[[ Set a handler function for incoming user file uploads. -@class function -@name setfilehandler +@class function +@name setfilehandler @param callback Handler function ]] ---[[ Send a HTTP-Header. -@class function -@name header -@param key Header key -@param value Header value +@class function +@name header +@param key Header key +@param value Header value ]] ---[[ Set the mime type of following content data. -@class function -@name prepare_content -@param mime Mimetype of following content +@class function +@name prepare_content +@param mime Mimetype of following content ]] ---[[ Get the RAW HTTP input source -@class function -@name source -@return HTTP LTN12 source +@class function +@name source +@return HTTP LTN12 source ]] ---[[ Set the HTTP status code and status message. -@class function -@name status +@class function +@name status @param code Status code @param message Status message ]] @@ -105,8 +104,9 @@ Send a chunk of content data to the client. This function is as a valid LTN12 sink. If the content chunk is nil this function will automatically invoke close. -@class function -@name write + +@class function +@name write @param content Content chunk @param src_err Error object from source (optional) @see close @@ -115,51 +115,146 @@ If the content chunk is nil this function will automatically invoke close. ---[[ Splice data from a filedescriptor to the client. -@class function -@name splice -@param fp File descriptor -@param size Bytes to splice (optional) +@class function +@name splice +@param fp File descriptor +@param size Bytes to splice (optional) ]] ---[[ Redirects the client to a new URL and closes the connection. -@class function -@name redirect -@param url Target URL +@class function +@name redirect +@param url Target URL ]] ---[[ Create a querystring out of a table of key - value pairs. -@class function -@name build_querystring -@param table Query string source table +@class function +@name build_querystring +@param table Query string source table @return Encoded HTTP query string ]] ---[[ Return the URL-decoded equivalent of a string. +@class function +@name urldecode @param str URL-encoded string @param no_plus Don't decode + to " " @return URL-decoded string -@see urlencode +@see urlencode ]] ---[[ Return the URL-encoded equivalent of a string. +@class function +@name urlencode @param str Source string @return URL-encoded string -@see urldecode +@see urldecode ]] ---[[ Send the given data as JSON encoded string. -@class function -@name write_json +@class function +@name write_json @param data Data to send ]] +---[[ +Extract and split urlencoded data pairs, separated bei either "&" or ";" +from given url or string. Returns a table with urldecoded values. + +Simple parameters are stored as string values associated with the parameter +name within the table. Parameters with multiple values are stored as array +containing the corresponding values. + +@class function +@name urldecode_params +@param url The url or string which contains x-www-urlencoded form data +@param tbl Use the given table for storing values (optional) +@return Table containing the urldecoded parameters +@see urlencode_params +]] + +---[[ +Encode each key-value-pair in given table to x-www-urlencoded format, +separated by "&". + +Tables are encoded as parameters with multiple values by repeating the +parameter name with each value. + +@class function +@name urlencode_params +@param tbl Table with the values +@return String containing encoded values +@see urldecode_params +]] + +---[[ +Decode a mime encoded http message body with multipart/form-data Content-Type. + +Stores all extracted data associated with its parameter name +in the params table within the given message object. Multiple parameter +values are stored as tables, ordinary ones as strings. + +If an optional file callback function is given then it is feeded with the +file contents chunk by chunk and only the extracted file name is stored +within the params table. The callback function will be called subsequently +with three arguments: + o Table containing decoded (name, file) and raw (headers) mime header data + o String value containing a chunk of the file data + o Boolean which indicates wheather the current chunk is the last one (eof) + +@class function +@name mimedecode_message_body +@param src Ltn12 source function +@param msg HTTP message object +@param filecb File callback function (optional) +@return Value indicating successful operation (not nil means "ok") +@return String containing the error if unsuccessful +@see parse_message_header +]] + +---[[ +Decode an urlencoded http message body with application/x-www-urlencoded +Content-Type. + +Stores all extracted data associated with its parameter name in the params +table within the given message object. Multiple parameter values are stored +as tables, ordinary ones as strings. + +@class function +@name urldecode_message_body +@param src Ltn12 source function +@param msg HTTP message object +@return Value indicating successful operation (not nil means "ok") +@return String containing the error if unsuccessful +@see parse_message_header +]] + +---[[ +Try to extract and decode a http message body from the given ltn12 source. +This function will examine the Content-Type within the given message object +to select the appropriate content decoder. + +Currently the application/x-www-urlencoded and application/form-data +mime types are supported. If the encountered content encoding can't be +handled then the whole message body will be stored unaltered as "content" +property within the given message object. + +@class function +@name parse_message_body +@param src Ltn12 source function +@param msg HTTP message object +@param filecb File data callback (optional, see mimedecode_message_body()) +@return Value indicating successful operation (not nil means "ok") +@return String containing the error if unsuccessful +@see parse_message_header +]] diff --git a/modules/luci-base/luasrc/http/protocol.lua b/modules/luci-base/luasrc/http/protocol.lua deleted file mode 100644 index 0a8b2fbab9..0000000000 --- a/modules/luci-base/luasrc/http/protocol.lua +++ /dev/null @@ -1,649 +0,0 @@ --- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org> --- Licensed to the public under the Apache License 2.0. - --- This class contains several functions useful for http message- and content --- decoding and to retrive form data from raw http messages. -module("luci.http.protocol", package.seeall) - -local ltn12 = require("luci.ltn12") - -HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size - --- the "+" sign to " " - and return the decoded string. -function urldecode( str, no_plus ) - - local function __chrdec( hex ) - return string.char( tonumber( hex, 16 ) ) - end - - if type(str) == "string" then - if not no_plus then - str = str:gsub( "+", " " ) - end - - str = str:gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec ) - end - - return str -end - --- from given url or string. Returns a table with urldecoded values. --- Simple parameters are stored as string values associated with the parameter --- name within the table. Parameters with multiple values are stored as array --- containing the corresponding values. -function urldecode_params( url, tbl ) - - local params = tbl or { } - - if url:find("?") then - url = url:gsub( "^.+%?([^?]+)", "%1" ) - end - - for pair in url:gmatch( "[^&;]+" ) do - - -- find key and value - local key = urldecode( pair:match("^([^=]+)") ) - local val = urldecode( pair:match("^[^=]+=(.+)$") ) - - -- store - if type(key) == "string" and key:len() > 0 then - if type(val) ~= "string" then val = "" end - - if not params[key] then - params[key] = val - elseif type(params[key]) ~= "table" then - params[key] = { params[key], val } - else - table.insert( params[key], val ) - end - end - end - - return params -end - -function urlencode( str ) - - local function __chrenc( chr ) - return string.format( - "%%%02x", string.byte( chr ) - ) - end - - if type(str) == "string" then - str = str:gsub( - "([^a-zA-Z0-9$_%-%.%~])", - __chrenc - ) - end - - return str -end - --- separated by "&". Tables are encoded as parameters with multiple values by --- repeating the parameter name with each value. -function urlencode_params( tbl ) - local enc = "" - - for k, v in pairs(tbl) do - if type(v) == "table" then - for i, v2 in ipairs(v) do - enc = enc .. ( #enc > 0 and "&" or "" ) .. - urlencode(k) .. "=" .. urlencode(v2) - end - else - enc = enc .. ( #enc > 0 and "&" or "" ) .. - urlencode(k) .. "=" .. urlencode(v) - end - end - - return enc -end - --- (Internal function) --- Initialize given parameter and coerce string into table when the parameter --- already exists. -local function __initval( tbl, key ) - if tbl[key] == nil then - tbl[key] = "" - elseif type(tbl[key]) == "string" then - tbl[key] = { tbl[key], "" } - else - table.insert( tbl[key], "" ) - end -end - --- (Internal function) --- Initialize given file parameter. -local function __initfileval( tbl, key, filename, fd ) - if tbl[key] == nil then - tbl[key] = { file=filename, fd=fd, name=key, "" } - else - table.insert( tbl[key], "" ) - end -end - --- (Internal function) --- Append given data to given parameter, either by extending the string value --- or by appending it to the last string in the parameter's value table. -local function __appendval( tbl, key, chunk ) - if type(tbl[key]) == "table" then - tbl[key][#tbl[key]] = tbl[key][#tbl[key]] .. chunk - else - tbl[key] = tbl[key] .. chunk - end -end - --- (Internal function) --- Finish the value of given parameter, either by transforming the string value --- or - in the case of multi value parameters - the last element in the --- associated values table. -local function __finishval( tbl, key, handler ) - if handler then - if type(tbl[key]) == "table" then - tbl[key][#tbl[key]] = handler( tbl[key][#tbl[key]] ) - else - tbl[key] = handler( tbl[key] ) - end - end -end - - --- Table of our process states -local process_states = { } - --- Extract "magic", the first line of a http message. --- Extracts the message type ("get", "post" or "response"), the requested uri --- or the status code if the line descripes a http response. -process_states['magic'] = function( msg, chunk, err ) - - if chunk ~= nil then - -- ignore empty lines before request - if #chunk == 0 then - return true, nil - end - - -- Is it a request? - local method, uri, http_ver = chunk:match("^([A-Z]+) ([^ ]+) HTTP/([01]%.[019])$") - - -- Yup, it is - if method then - - msg.type = "request" - msg.request_method = method:lower() - msg.request_uri = uri - msg.http_version = tonumber( http_ver ) - msg.headers = { } - - -- We're done, next state is header parsing - return true, function( chunk ) - return process_states['headers']( msg, chunk ) - end - - -- Is it a response? - else - - local http_ver, code, message = chunk:match("^HTTP/([01]%.[019]) ([0-9]+) ([^\r\n]+)$") - - -- Is a response - if code then - - msg.type = "response" - msg.status_code = code - msg.status_message = message - msg.http_version = tonumber( http_ver ) - msg.headers = { } - - -- We're done, next state is header parsing - return true, function( chunk ) - return process_states['headers']( msg, chunk ) - end - end - end - end - - -- Can't handle it - return nil, "Invalid HTTP message magic" -end - - --- Extract headers from given string. -process_states['headers'] = function( msg, chunk ) - - if chunk ~= nil then - - -- Look for a valid header format - local hdr, val = chunk:match( "^([A-Za-z][A-Za-z0-9%-_]+): +(.+)$" ) - - if type(hdr) == "string" and hdr:len() > 0 and - type(val) == "string" and val:len() > 0 - then - msg.headers[hdr] = val - - -- Valid header line, proceed - return true, nil - - elseif #chunk == 0 then - -- Empty line, we won't accept data anymore - return false, nil - else - -- Junk data - return nil, "Invalid HTTP header received" - end - else - return nil, "Unexpected EOF" - end -end - - --- data line by line with the trailing \r\n stripped of. -function header_source( sock ) - return ltn12.source.simplify( function() - - local chunk, err, part = sock:receive("*l") - - -- Line too long - if chunk == nil then - if err ~= "timeout" then - return nil, part - and "Line exceeds maximum allowed length" - or "Unexpected EOF" - else - return nil, err - end - - -- Line ok - elseif chunk ~= nil then - - -- Strip trailing CR - chunk = chunk:gsub("\r$","") - - return chunk, nil - end - end ) -end - --- Content-Type. Stores all extracted data associated with its parameter name --- in the params table within the given message object. Multiple parameter --- values are stored as tables, ordinary ones as strings. --- If an optional file callback function is given then it is feeded with the --- file contents chunk by chunk and only the extracted file name is stored --- within the params table. The callback function will be called subsequently --- with three arguments: --- o Table containing decoded (name, file) and raw (headers) mime header data --- o String value containing a chunk of the file data --- o Boolean which indicates wheather the current chunk is the last one (eof) -function mimedecode_message_body( src, msg, filecb ) - - if msg and msg.env.CONTENT_TYPE then - msg.mime_boundary = msg.env.CONTENT_TYPE:match("^multipart/form%-data; boundary=(.+)$") - end - - if not msg.mime_boundary then - return nil, "Invalid Content-Type found" - end - - - local tlen = 0 - local inhdr = false - local field = nil - local store = nil - local lchunk = nil - - local function parse_headers( chunk, field ) - - local stat - repeat - chunk, stat = chunk:gsub( - "^([A-Z][A-Za-z0-9%-_]+): +([^\r\n]+)\r\n", - function(k,v) - field.headers[k] = v - return "" - end - ) - until stat == 0 - - chunk, stat = chunk:gsub("^\r\n","") - - -- End of headers - if stat > 0 then - if field.headers["Content-Disposition"] then - if field.headers["Content-Disposition"]:match("^form%-data; ") then - field.name = field.headers["Content-Disposition"]:match('name="(.-)"') - field.file = field.headers["Content-Disposition"]:match('filename="(.+)"$') - end - end - - if not field.headers["Content-Type"] then - field.headers["Content-Type"] = "text/plain" - end - - if field.name and field.file and filecb then - __initval( msg.params, field.name ) - __appendval( msg.params, field.name, field.file ) - - store = filecb - elseif field.name and field.file then - local nxf = require "nixio" - local fd = nxf.mkstemp(field.name) - __initfileval ( msg.params, field.name, field.file, fd ) - if fd then - store = function(hdr, buf, eof) - fd:write(buf) - if (eof) then - fd:seek(0, "set") - end - end - else - store = function( hdr, buf, eof ) - __appendval( msg.params, field.name, buf ) - end - end - elseif field.name then - __initval( msg.params, field.name ) - - store = function( hdr, buf, eof ) - __appendval( msg.params, field.name, buf ) - end - else - store = nil - end - - return chunk, true - end - - return chunk, false - end - - local function snk( chunk ) - - tlen = tlen + ( chunk and #chunk or 0 ) - - if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then - return nil, "Message body size exceeds Content-Length" - end - - if chunk and not lchunk then - lchunk = "\r\n" .. chunk - - elseif lchunk then - local data = lchunk .. ( chunk or "" ) - local spos, epos, found - - repeat - spos, epos = data:find( "\r\n--" .. msg.mime_boundary .. "\r\n", 1, true ) - - if not spos then - spos, epos = data:find( "\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true ) - end - - - if spos then - local predata = data:sub( 1, spos - 1 ) - - if inhdr then - predata, eof = parse_headers( predata, field ) - - if not eof then - return nil, "Invalid MIME section header" - elseif not field.name then - return nil, "Invalid Content-Disposition header" - end - end - - if store then - store( field, predata, true ) - end - - - field = { headers = { } } - found = found or true - - data, eof = parse_headers( data:sub( epos + 1, #data ), field ) - inhdr = not eof - end - until not spos - - if found then - -- We found at least some boundary. Save - -- the unparsed remaining data for the - -- next chunk. - lchunk, data = data, nil - else - -- There was a complete chunk without a boundary. Parse it as headers or - -- append it as data, depending on our current state. - if inhdr then - lchunk, eof = parse_headers( data, field ) - inhdr = not eof - else - -- We're inside data, so append the data. Note that we only append - -- lchunk, not all of data, since there is a chance that chunk - -- contains half a boundary. Assuming that each chunk is at least the - -- boundary in size, this should prevent problems - store( field, lchunk, false ) - lchunk, chunk = chunk, nil - end - end - end - - return true - end - - return ltn12.pump.all( src, snk ) -end - --- Content-Type. Stores all extracted data associated with its parameter name --- in the params table within the given message object. Multiple parameter --- values are stored as tables, ordinary ones as strings. -function urldecode_message_body( src, msg ) - - local tlen = 0 - local lchunk = nil - - local function snk( chunk ) - - tlen = tlen + ( chunk and #chunk or 0 ) - - if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then - return nil, "Message body size exceeds Content-Length" - elseif tlen > HTTP_MAX_CONTENT then - return nil, "Message body size exceeds maximum allowed length" - end - - if not lchunk and chunk then - lchunk = chunk - - elseif lchunk then - local data = lchunk .. ( chunk or "&" ) - local spos, epos - - repeat - spos, epos = data:find("^.-[;&]") - - if spos then - local pair = data:sub( spos, epos - 1 ) - local key = pair:match("^(.-)=") - local val = pair:match("=([^%s]*)%s*$") - - if key and #key > 0 then - __initval( msg.params, key ) - __appendval( msg.params, key, val ) - __finishval( msg.params, key, urldecode ) - end - - data = data:sub( epos + 1, #data ) - end - until not spos - - lchunk = data - end - - return true - end - - return ltn12.pump.all( src, snk ) -end - --- version, message headers and resulting CGI environment variables from the --- given ltn12 source. -function parse_message_header( src ) - - local ok = true - local msg = { } - - local sink = ltn12.sink.simplify( - function( chunk ) - return process_states['magic']( msg, chunk ) - end - ) - - -- Pump input data... - while ok do - - -- get data - ok, err = ltn12.pump.step( src, sink ) - - -- error - if not ok and err then - return nil, err - - -- eof - elseif not ok then - - -- Process get parameters - if ( msg.request_method == "get" or msg.request_method == "post" ) and - msg.request_uri:match("?") - then - msg.params = urldecode_params( msg.request_uri ) - else - msg.params = { } - end - - -- Populate common environment variables - msg.env = { - CONTENT_LENGTH = msg.headers['Content-Length']; - CONTENT_TYPE = msg.headers['Content-Type'] or msg.headers['Content-type']; - REQUEST_METHOD = msg.request_method:upper(); - REQUEST_URI = msg.request_uri; - SCRIPT_NAME = msg.request_uri:gsub("?.+$",""); - SCRIPT_FILENAME = ""; -- XXX implement me - SERVER_PROTOCOL = "HTTP/" .. string.format("%.1f", msg.http_version); - QUERY_STRING = msg.request_uri:match("?") - and msg.request_uri:gsub("^.+?","") or "" - } - - -- Populate HTTP_* environment variables - for i, hdr in ipairs( { - 'Accept', - 'Accept-Charset', - 'Accept-Encoding', - 'Accept-Language', - 'Connection', - 'Cookie', - 'Host', - 'Referer', - 'User-Agent', - } ) do - local var = 'HTTP_' .. hdr:upper():gsub("%-","_") - local val = msg.headers[hdr] - - msg.env[var] = val - end - end - end - - return msg -end - --- This function will examine the Content-Type within the given message object --- to select the appropriate content decoder. --- Currently the application/x-www-urlencoded and application/form-data --- mime types are supported. If the encountered content encoding can't be --- handled then the whole message body will be stored unaltered as "content" --- property within the given message object. -function parse_message_body( src, msg, filecb ) - -- Is it multipart/mime ? - if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and - msg.env.CONTENT_TYPE:match("^multipart/form%-data") - then - - return mimedecode_message_body( src, msg, filecb ) - - -- Is it application/x-www-form-urlencoded ? - elseif msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and - msg.env.CONTENT_TYPE:match("^application/x%-www%-form%-urlencoded") - then - return urldecode_message_body( src, msg, filecb ) - - - -- Unhandled encoding - -- If a file callback is given then feed it chunk by chunk, else - -- store whole buffer in message.content - else - - local sink - - -- If we have a file callback then feed it - if type(filecb) == "function" then - local meta = { - name = "raw", - encoding = msg.env.CONTENT_TYPE - } - sink = function( chunk ) - if chunk then - return filecb(meta, chunk, false) - else - return filecb(meta, nil, true) - end - end - -- ... else append to .content - else - msg.content = "" - msg.content_length = 0 - - sink = function( chunk ) - if chunk then - if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then - msg.content = msg.content .. chunk - msg.content_length = msg.content_length + #chunk - return true - else - return nil, "POST data exceeds maximum allowed length" - end - end - return true - end - end - - -- Pump data... - while true do - local ok, err = ltn12.pump.step( src, sink ) - - if not ok and err then - return nil, err - elseif not ok then -- eof - return true - end - end - - return true - end -end - -statusmsg = { - [200] = "OK", - [206] = "Partial Content", - [301] = "Moved Permanently", - [302] = "Found", - [304] = "Not Modified", - [400] = "Bad Request", - [403] = "Forbidden", - [404] = "Not Found", - [405] = "Method Not Allowed", - [408] = "Request Time-out", - [411] = "Length Required", - [412] = "Precondition Failed", - [416] = "Requested range not satisfiable", - [500] = "Internal Server Error", - [503] = "Server Unavailable", -} diff --git a/modules/luci-base/luasrc/http/protocol.luadoc b/modules/luci-base/luasrc/http/protocol.luadoc deleted file mode 100644 index 19a0a3419b..0000000000 --- a/modules/luci-base/luasrc/http/protocol.luadoc +++ /dev/null @@ -1,142 +0,0 @@ ----[[ -LuCI http protocol class. - -This class contains several functions useful for http message- and content -decoding and to retrive form data from raw http messages. -]] -module "luci.http.protocol" - ----[[ -Decode an urlencoded string - optionally without decoding - -the "+" sign to " " - and return the decoded string. -@class function -@name urldecode -@param str Input string in x-www-urlencoded format -@param no_plus Don't decode "+" signs to spaces -@return The decoded string -@see urlencode -]] - ----[[ -Extract and split urlencoded data pairs, separated bei either "&" or ";" - -from given url or string. Returns a table with urldecoded values. -Simple parameters are stored as string values associated with the parameter -name within the table. Parameters with multiple values are stored as array -containing the corresponding values. -@class function -@name urldecode_params -@param url The url or string which contains x-www-urlencoded form data -@param tbl Use the given table for storing values (optional) -@return Table containing the urldecoded parameters -@see urlencode_params -]] - ----[[ -Encode given string to x-www-urlencoded format. - -@class function -@name urlencode -@param str String to encode -@return String containing the encoded data -@see urldecode -]] - ----[[ -Encode each key-value-pair in given table to x-www-urlencoded format, - -separated by "&". Tables are encoded as parameters with multiple values by -repeating the parameter name with each value. -@class function -@name urlencode_params -@param tbl Table with the values -@return String containing encoded values -@see urldecode_params -]] - ----[[ -Creates a ltn12 source from the given socket. The source will return it's - -data line by line with the trailing \r\n stripped of. -@class function -@name header_source -@param sock Readable network socket -@return Ltn12 source function -]] - ----[[ -Decode a mime encoded http message body with multipart/form-data - -Content-Type. Stores all extracted data associated with its parameter name -in the params table within the given message object. Multiple parameter -values are stored as tables, ordinary ones as strings. -If an optional file callback function is given then it is feeded with the -file contents chunk by chunk and only the extracted file name is stored -within the params table. The callback function will be called subsequently -with three arguments: - o Table containing decoded (name, file) and raw (headers) mime header data - o String value containing a chunk of the file data - o Boolean which indicates wheather the current chunk is the last one (eof) -@class function -@name mimedecode_message_body -@param src Ltn12 source function -@param msg HTTP message object -@param filecb File callback function (optional) -@return Value indicating successful operation (not nil means "ok") -@return String containing the error if unsuccessful -@see parse_message_header -]] - ----[[ -Decode an urlencoded http message body with application/x-www-urlencoded - -Content-Type. Stores all extracted data associated with its parameter name -in the params table within the given message object. Multiple parameter -values are stored as tables, ordinary ones as strings. -@class function -@name urldecode_message_body -@param src Ltn12 source function -@param msg HTTP message object -@return Value indicating successful operation (not nil means "ok") -@return String containing the error if unsuccessful -@see parse_message_header -]] - ----[[ -Try to extract an http message header including information like protocol - -version, message headers and resulting CGI environment variables from the -given ltn12 source. -@class function -@name parse_message_header -@param src Ltn12 source function -@return HTTP message object -@see parse_message_body -]] - ----[[ -Try to extract and decode a http message body from the given ltn12 source. - -This function will examine the Content-Type within the given message object -to select the appropriate content decoder. -Currently the application/x-www-urlencoded and application/form-data -mime types are supported. If the encountered content encoding can't be -handled then the whole message body will be stored unaltered as "content" -property within the given message object. -@class function -@name parse_message_body -@param src Ltn12 source function -@param msg HTTP message object -@param filecb File data callback (optional, see mimedecode_message_body()) -@return Value indicating successful operation (not nil means "ok") -@return String containing the error if unsuccessful -@see parse_message_header -]] - ----[[ -Table containing human readable messages for several http status codes. - -@class table -]] - diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.lua b/modules/luci-base/luasrc/http/protocol/conditionals.lua deleted file mode 100644 index d31a4e38a4..0000000000 --- a/modules/luci-base/luasrc/http/protocol/conditionals.lua +++ /dev/null @@ -1,110 +0,0 @@ --- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org> --- Licensed to the public under the Apache License 2.0. - --- This class provides basic ETag handling and implements most of the --- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 . -module("luci.http.protocol.conditionals", package.seeall) - -local date = require("luci.http.protocol.date") - - -function mk_etag( stat ) - if stat ~= nil then - return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime ) - end -end - --- Test whether the given message object contains an "If-Match" header and --- compare it against the given stat object. -function if_match( req, stat ) - local h = req.headers - local etag = mk_etag( stat ) - - -- Check for matching resource - if type(h['If-Match']) == "string" then - for ent in h['If-Match']:gmatch("([^, ]+)") do - if ( ent == '*' or ent == etag ) and stat ~= nil then - return true - end - end - - return false, 412 - end - - return true -end - --- Test whether the given message object contains an "If-Modified-Since" header --- and compare it against the given stat object. -function if_modified_since( req, stat ) - local h = req.headers - - -- Compare mtimes - if type(h['If-Modified-Since']) == "string" then - local since = date.to_unix( h['If-Modified-Since'] ) - - if stat == nil or since < stat.mtime then - return true - end - - return false, 304, { - ["ETag"] = mk_etag( stat ); - ["Date"] = date.to_http( os.time() ); - ["Last-Modified"] = date.to_http( stat.mtime ) - } - end - - return true -end - --- Test whether the given message object contains an "If-None-Match" header and --- compare it against the given stat object. -function if_none_match( req, stat ) - local h = req.headers - local etag = mk_etag( stat ) - local method = req.env and req.env.REQUEST_METHOD or "GET" - - -- Check for matching resource - if type(h['If-None-Match']) == "string" then - for ent in h['If-None-Match']:gmatch("([^, ]+)") do - if ( ent == '*' or ent == etag ) and stat ~= nil then - if method == "GET" or method == "HEAD" then - return false, 304, { - ["ETag"] = etag; - ["Date"] = date.to_http( os.time() ); - ["Last-Modified"] = date.to_http( stat.mtime ) - } - else - return false, 412 - end - end - end - end - - return true -end - --- The If-Range header is currently not implemented due to the lack of general --- byte range stuff in luci.http.protocol . This function will always return --- false, 412 to indicate a failed precondition. -function if_range( req, stat ) - -- Sorry, no subranges (yet) - return false, 412 -end - --- Test whether the given message object contains an "If-Unmodified-Since" --- header and compare it against the given stat object. -function if_unmodified_since( req, stat ) - local h = req.headers - - -- Compare mtimes - if type(h['If-Unmodified-Since']) == "string" then - local since = date.to_unix( h['If-Unmodified-Since'] ) - - if stat ~= nil and since <= stat.mtime then - return false, 412 - end - end - - return true -end diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.luadoc b/modules/luci-base/luasrc/http/protocol/conditionals.luadoc deleted file mode 100644 index 9cfe02dd50..0000000000 --- a/modules/luci-base/luasrc/http/protocol/conditionals.luadoc +++ /dev/null @@ -1,85 +0,0 @@ ----[[ -LuCI http protocol implementation - HTTP/1.1 bits. - -This class provides basic ETag handling and implements most of the -conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 . -]] -module "luci.http.protocol.conditionals" - ----[[ -Implement 14.19 / ETag. - -@class function -@name mk_etag -@param stat A file.stat structure -@return String containing the generated tag suitable for ETag headers -]] - ----[[ -14.24 / If-Match - -Test whether the given message object contains an "If-Match" header and -compare it against the given stat object. -@class function -@name if_match -@param req HTTP request message object -@param stat A file.stat object -@return Boolean indicating whether the precondition is ok -@return Alternative status code if the precondition failed -]] - ----[[ -14.25 / If-Modified-Since - -Test whether the given message object contains an "If-Modified-Since" header -and compare it against the given stat object. -@class function -@name if_modified_since -@param req HTTP request message object -@param stat A file.stat object -@return Boolean indicating whether the precondition is ok -@return Alternative status code if the precondition failed -@return Table containing extra HTTP headers if the precondition failed -]] - ----[[ -14.26 / If-None-Match - -Test whether the given message object contains an "If-None-Match" header and -compare it against the given stat object. -@class function -@name if_none_match -@param req HTTP request message object -@param stat A file.stat object -@return Boolean indicating whether the precondition is ok -@return Alternative status code if the precondition failed -@return Table containing extra HTTP headers if the precondition failed -]] - ----[[ -14.27 / If-Range - -The If-Range header is currently not implemented due to the lack of general -byte range stuff in luci.http.protocol . This function will always return -false, 412 to indicate a failed precondition. -@class function -@name if_range -@param req HTTP request message object -@param stat A file.stat object -@return Boolean indicating whether the precondition is ok -@return Alternative status code if the precondition failed -]] - ----[[ -14.28 / If-Unmodified-Since - -Test whether the given message object contains an "If-Unmodified-Since" -header and compare it against the given stat object. -@class function -@name if_unmodified_since -@param req HTTP request message object -@param stat A file.stat object -@return Boolean indicating whether the precondition is ok -@return Alternative status code if the precondition failed -]] - diff --git a/modules/luci-base/luasrc/http/protocol/date.lua b/modules/luci-base/luasrc/http/protocol/date.lua deleted file mode 100644 index e440219a9c..0000000000 --- a/modules/luci-base/luasrc/http/protocol/date.lua +++ /dev/null @@ -1,87 +0,0 @@ --- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org> --- Licensed to the public under the Apache License 2.0. - --- This class contains functions to parse, compare and format http dates. -module("luci.http.protocol.date", package.seeall) - -require("luci.sys.zoneinfo") - - -MONTHS = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" -} - -function tz_offset(tz) - - if type(tz) == "string" then - - -- check for a numeric identifier - local s, v = tz:match("([%+%-])([0-9]+)") - if s == '+' then s = 1 else s = -1 end - if v then v = tonumber(v) end - - if s and v then - return s * 60 * ( math.floor( v / 100 ) * 60 + ( v % 100 ) ) - - -- lookup symbolic tz - elseif luci.sys.zoneinfo.OFFSET[tz:lower()] then - return luci.sys.zoneinfo.OFFSET[tz:lower()] - end - - end - - -- bad luck - return 0 -end - -function to_unix(date) - - local wd, day, mon, yr, hr, min, sec, tz = date:match( - "([A-Z][a-z][a-z]), ([0-9]+) " .. - "([A-Z][a-z][a-z]) ([0-9]+) " .. - "([0-9]+):([0-9]+):([0-9]+) " .. - "([A-Z0-9%+%-]+)" - ) - - if day and mon and yr and hr and min and sec then - -- find month - local month = 1 - for i = 1, 12 do - if MONTHS[i] == mon then - month = i - break - end - end - - -- convert to epoch time - return tz_offset(tz) + os.time( { - year = yr, - month = month, - day = day, - hour = hr, - min = min, - sec = sec - } ) - end - - return 0 -end - -function to_http(time) - return os.date( "%a, %d %b %Y %H:%M:%S GMT", time ) -end - -function compare(d1, d2) - - if d1:match("[^0-9]") then d1 = to_unix(d1) end - if d2:match("[^0-9]") then d2 = to_unix(d2) end - - if d1 == d2 then - return 0 - elseif d1 < d2 then - return -1 - else - return 1 - end -end diff --git a/modules/luci-base/luasrc/http/protocol/date.luadoc b/modules/luci-base/luasrc/http/protocol/date.luadoc deleted file mode 100644 index d6f1c8d658..0000000000 --- a/modules/luci-base/luasrc/http/protocol/date.luadoc +++ /dev/null @@ -1,46 +0,0 @@ ----[[ -LuCI http protocol implementation - date helper class. - -This class contains functions to parse, compare and format http dates. -]] -module "luci.http.protocol.date" - ----[[ -Return the time offset in seconds between the UTC and given time zone. - -@class function -@name tz_offset -@param tz Symbolic or numeric timezone specifier -@return Time offset to UTC in seconds -]] - ----[[ -Parse given HTTP date string and convert it to unix epoch time. - -@class function -@name to_unix -@param data String containing the date -@return Unix epoch time -]] - ----[[ -Convert the given unix epoch time to valid HTTP date string. - -@class function -@name to_http -@param time Unix epoch time -@return String containing the formatted date -]] - ----[[ -Compare two dates which can either be unix epoch times or HTTP date strings. - -@class function -@name compare -@param d1 The first date or epoch time to compare -@param d2 The first date or epoch time to compare -@return -1 - if d1 is lower then d2 -@return 0 - if both dates are equal -@return 1 - if d1 is higher then d2 -]] - diff --git a/modules/luci-base/luasrc/http/protocol/mime.lua b/modules/luci-base/luasrc/http/protocol/mime.lua deleted file mode 100644 index 2b99d8e74e..0000000000 --- a/modules/luci-base/luasrc/http/protocol/mime.lua +++ /dev/null @@ -1,78 +0,0 @@ --- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org> --- Licensed to the public under the Apache License 2.0. - --- This class provides functions to guess mime types from file extensions and --- vice versa. -module("luci.http.protocol.mime", package.seeall) - -require("luci.util") - -MIME_TYPES = { - ["txt"] = "text/plain"; - ["js"] = "text/javascript"; - ["css"] = "text/css"; - ["htm"] = "text/html"; - ["html"] = "text/html"; - ["patch"] = "text/x-patch"; - ["c"] = "text/x-csrc"; - ["h"] = "text/x-chdr"; - ["o"] = "text/x-object"; - ["ko"] = "text/x-object"; - - ["bmp"] = "image/bmp"; - ["gif"] = "image/gif"; - ["png"] = "image/png"; - ["jpg"] = "image/jpeg"; - ["jpeg"] = "image/jpeg"; - ["svg"] = "image/svg+xml"; - - ["zip"] = "application/zip"; - ["pdf"] = "application/pdf"; - ["xml"] = "application/xml"; - ["xsl"] = "application/xml"; - ["doc"] = "application/msword"; - ["ppt"] = "application/vnd.ms-powerpoint"; - ["xls"] = "application/vnd.ms-excel"; - ["odt"] = "application/vnd.oasis.opendocument.text"; - ["odp"] = "application/vnd.oasis.opendocument.presentation"; - ["pl"] = "application/x-perl"; - ["sh"] = "application/x-shellscript"; - ["php"] = "application/x-php"; - ["deb"] = "application/x-deb"; - ["iso"] = "application/x-cd-image"; - ["tgz"] = "application/x-compressed-tar"; - - ["mp3"] = "audio/mpeg"; - ["ogg"] = "audio/x-vorbis+ogg"; - ["wav"] = "audio/x-wav"; - - ["mpg"] = "video/mpeg"; - ["mpeg"] = "video/mpeg"; - ["avi"] = "video/x-msvideo"; -} - --- "application/octet-stream" if the extension is unknown. -function to_mime(filename) - if type(filename) == "string" then - local ext = filename:match("[^%.]+$") - - if ext and MIME_TYPES[ext:lower()] then - return MIME_TYPES[ext:lower()] - end - end - - return "application/octet-stream" -end - --- given mime-type is unknown. -function to_ext(mimetype) - if type(mimetype) == "string" then - for ext, type in luci.util.kspairs( MIME_TYPES ) do - if type == mimetype then - return ext - end - end - end - - return nil -end diff --git a/modules/luci-base/luasrc/http/protocol/mime.luadoc b/modules/luci-base/luasrc/http/protocol/mime.luadoc deleted file mode 100644 index 195b5fcc89..0000000000 --- a/modules/luci-base/luasrc/http/protocol/mime.luadoc +++ /dev/null @@ -1,34 +0,0 @@ ----[[ -LuCI http protocol implementation - mime helper class. - -This class provides functions to guess mime types from file extensions and -vice versa. -]] -module "luci.http.protocol.mime" - ----[[ -MIME mapping table containg extension - mimetype relations. - -@class table -]] - ----[[ -Extract extension from a filename and return corresponding mime-type or - -"application/octet-stream" if the extension is unknown. -@class function -@name to_mime -@param filename The filename for which the mime type is guessed -@return String containign the determined mime type -]] - ----[[ -Return corresponding extension for a given mime type or nil if the - -given mime-type is unknown. -@class function -@name to_ext -@param mimetype The mimetype to retrieve the extension from -@return String with the extension or nil for unknown type -]] - diff --git a/modules/luci-base/luasrc/model/ipkg.lua b/modules/luci-base/luasrc/model/ipkg.lua index e653b03465..e27ea52895 100644 --- a/modules/luci-base/luasrc/model/ipkg.lua +++ b/modules/luci-base/luasrc/model/ipkg.lua @@ -20,12 +20,14 @@ module "luci.model.ipkg" -- Internal action function local function _action(cmd, ...) - local pkg = "" + local cmdline = { ipkg, cmd } + + local k, v for k, v in pairs({...}) do - pkg = pkg .. " '" .. v:gsub("'", "") .. "'" + cmdline[#cmdline+1] = util.shellquote(v) end - local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg } + local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ") local r = os.execute(c) local e = fs.readfile("/tmp/opkg.stderr") local o = fs.readfile("/tmp/opkg.stdout") @@ -74,17 +76,17 @@ local function _parselist(rawdata) end -- Internal lookup function -local function _lookup(act, pkg) - local cmd = ipkg .. " " .. act +local function _lookup(cmd, pkg) + local cmdline = { ipkg, cmd } if pkg then - cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'" + cmdline[#cmdline+1] = util.shellquote(pkg) end -- OPKG sometimes kills the whole machine because it sucks -- Therefore we have to use a sucky approach too and use -- tmpfiles instead of directly reading the output local tmpfile = os.tmpname() - os.execute(cmd .. (" >%s 2>/dev/null" % tmpfile)) + os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile }) local data = _parselist(io.lines(tmpfile)) os.remove(tmpfile) @@ -123,9 +125,12 @@ end -- List helper local function _list(action, pat, cb) - local fd = io.popen(ipkg .. " " .. action .. - (pat and (" '%s'" % pat:gsub("'", "")) or "")) + local cmdline = { ipkg, action } + if pat then + cmdline[#cmdline+1] = util.shellquote(pat) + end + local fd = io.popen(table.concat(cmdline, " ")) if fd then local name, version, sz, desc while true do diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua index 056fc67b14..dfe818bcc7 100644 --- a/modules/luci-base/luasrc/model/network.lua +++ b/modules/luci-base/luasrc/model/network.lua @@ -629,7 +629,7 @@ function get_interface(self, i) if _interfaces[i] or _wifi_iface(i) then return interface(i) else - local netid = _wifi_netid_by_netname(i) + local netid = _wifi_netid_by_sid(i) return netid and interface(netid) end end diff --git a/modules/luci-base/luasrc/model/uci.lua b/modules/luci-base/luasrc/model/uci.lua index 577c6cde08..fc2a605b34 100644 --- a/modules/luci-base/luasrc/model/uci.lua +++ b/modules/luci-base/luasrc/model/uci.lua @@ -2,13 +2,12 @@ -- Licensed to the public under the Apache License 2.0. local os = require "os" -local uci = require "uci" local util = require "luci.util" local table = require "table" local setmetatable, rawget, rawset = setmetatable, rawget, rawset -local require, getmetatable = require, getmetatable +local require, getmetatable, assert = require, getmetatable, assert local error, pairs, ipairs = error, pairs, ipairs local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack @@ -20,151 +19,436 @@ local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack -- reloaded. module "luci.model.uci" -cursor = uci.cursor +local ERRSTR = { + "Invalid command", + "Invalid argument", + "Method not found", + "Entry not found", + "No data", + "Permission denied", + "Timeout", + "Not supported", + "Unknown error", + "Connection failed" +} + +local session_id = nil + +local function call(cmd, args) + if type(args) == "table" and session_id then + args.ubus_rpc_session = session_id + end + return util.ubus("uci", cmd, args) +end -APIVERSION = uci.APIVERSION + +function cursor() + return _M +end function cursor_state() - return cursor(nil, "/var/state") + return _M end +function substate(self) + return self +end -inst = cursor() -inst_state = cursor_state() -local Cursor = getmetatable(inst) +function get_confdir(self) + return "/etc/config" +end -function Cursor.apply(self, configlist, command) - configlist = self:_affected(configlist) - if command then - return { "/sbin/luci-reload", unpack(configlist) } - else - return os.execute("/sbin/luci-reload %s >/dev/null 2>&1" - % table.concat(configlist, " ")) - end +function get_savedir(self) + return "/tmp/.uci" end +function get_session_id(self) + return session_id +end --- returns a boolean whether to delete the current section (optional) -function Cursor.delete_all(self, config, stype, comparator) - local del = {} +function set_confdir(self, directory) + return false +end - if type(comparator) == "table" then - local tbl = comparator - comparator = function(section) - for k, v in pairs(tbl) do - if section[k] ~= v then - return false +function set_savedir(self, directory) + return false +end + +function set_session_id(self, id) + session_id = id + return true +end + + +function load(self, config) + return true +end + +function save(self, config) + return true +end + +function unload(self, config) + return true +end + + +function changes(self, config) + local rv = call("changes", { config = config }) + local res = {} + + if type(rv) == "table" and type(rv.changes) == "table" then + local package, changes + for package, changes in pairs(rv.changes) do + res[package] = {} + + local _, change + for _, change in ipairs(changes) do + local operation, section, option, value = unpack(change) + if option and value and operation ~= "add" then + res[package][section] = res[package][section] or { } + + if operation == "list-add" then + local v = res[package][section][option] + if type(v) == "table" then + v[#v+1] = value or "" + elseif v ~= nil then + res[package][section][option] = { v, value } + else + res[package][section][option] = { value } + end + else + res[package][section][option] = value or "" + end + else + res[package][section] = res[package][section] or {} + res[package][section][".type"] = option or "" end end - return true end end - local function helper (section) + return res +end + + +function revert(self, config) + local _, err = call("revert", { config = config }) + return (err == nil), ERRSTR[err] +end + +function commit(self, config) + local _, err = call("commit", { config = config }) + return (err == nil), ERRSTR[err] +end + +--[[ +function apply(self, configs, command) + local _, config + + assert(not command, "Apply command not supported anymore") - if not comparator or comparator(section) then - del[#del+1] = section[".name"] + if type(configs) == "table" then + for _, config in ipairs(configs) do + call("service", "event", { + type = "config.change", + data = { package = config } + }) end end +end +]] + + +function foreach(self, config, stype, callback) + if type(callback) == "function" then + local rv, err = call("get", { + config = config, + type = stype + }) + + if type(rv) == "table" and type(rv.values) == "table" then + local sections = { } + local res = false + local index = 1 + + local _, section + for _, section in pairs(rv.values) do + section[".index"] = section[".index"] or index + sections[index] = section + index = index + 1 + end - self:foreach(config, stype, helper) + table.sort(sections, function(a, b) + return a[".index"] < b[".index"] + end) - for i, j in ipairs(del) do - self:delete(config, j) + for _, section in ipairs(sections) do + local continue = callback(section) + res = true + if continue == false then + break + end + end + return res + else + return false, ERRSTR[err] or "No data" + end + else + return false, "Invalid argument" end end -function Cursor.section(self, config, type, name, values) - local stat = true - if name then - stat = self:set(config, name, type) +local function _get(self, operation, config, section, option) + if section == nil then + return nil + elseif type(option) == "string" and option:byte(1) ~= 46 then + local rv, err = call(operation, { + config = config, + section = section, + option = option + }) + + if type(rv) == "table" then + return rv.value or nil + elseif err then + return false, ERRSTR[err] + else + return nil + end + elseif option == nil then + local values = self:get_all(config, section) + if values then + return values[".type"], values[".name"] + else + return nil + end else - name = self:add(config, type) - stat = name and true + return false, "Invalid argument" end +end - if stat and values then - stat = self:tset(config, name, values) - end +function get(self, ...) + return _get(self, "get", ...) +end - return stat and name +function get_state(self, ...) + return _get(self, "state", ...) end -function Cursor.tset(self, config, section, values) - local stat = true - for k, v in pairs(values) do - if k:sub(1, 1) ~= "." then - stat = stat and self:set(config, section, k, v) - end +function get_all(self, config, section) + local rv, err = call("get", { + config = config, + section = section + }) + + if type(rv) == "table" and type(rv.values) == "table" then + return rv.values + elseif err then + return false, ERRSTR[err] + else + return nil end - return stat end -function Cursor.get_bool(self, ...) +function get_bool(self, ...) local val = self:get(...) - return ( val == "1" or val == "true" or val == "yes" or val == "on" ) + return (val == "1" or val == "true" or val == "yes" or val == "on") +end + +function get_first(self, config, stype, option, default) + local rv = default + + self:foreach(config, stype, function(s) + local val = not option and s[".name"] or s[option] + + if type(default) == "number" then + val = tonumber(val) + elseif type(default) == "boolean" then + val = (val == "1" or val == "true" or + val == "yes" or val == "on") + end + + if val ~= nil then + rv = val + return false + end + end) + + return rv end -function Cursor.get_list(self, config, section, option) +function get_list(self, config, section, option) if config and section and option then local val = self:get(config, section, option) - return ( type(val) == "table" and val or { val } ) + return (type(val) == "table" and val or { val }) end - return {} + return { } end -function Cursor.get_first(self, conf, stype, opt, def) - local rv = def - self:foreach(conf, stype, - function(s) - local val = not opt and s['.name'] or s[opt] +function section(self, config, stype, name, values) + local rv, err = call("add", { + config = config, + type = stype, + name = name, + values = values + }) + + if type(rv) == "table" then + return rv.section + elseif err then + return false, ERRSTR[err] + else + return nil + end +end - if type(def) == "number" then - val = tonumber(val) - elseif type(def) == "boolean" then - val = (val == "1" or val == "true" or - val == "yes" or val == "on") + +function add(self, config, stype) + return self:section(config, stype) +end + +function set(self, config, section, option, value) + if value == nil then + local sname, err = self:section(config, option, section) + return (not not sname), err + else + local _, err = call("set", { + config = config, + section = section, + values = { [option] = value } + }) + return (err == nil), ERRSTR[err] + end +end + +function set_list(self, config, section, option, value) + if section == nil or option == nil then + return false + elseif value == nil or (type(value) == "table" and #value == 0) then + return self:delete(config, section, option) + elseif type(value) == "table" then + return self:set(config, section, option, value) + else + return self:set(config, section, option, { value }) + end +end + +function tset(self, config, section, values) + local _, err = call("set", { + config = config, + section = section, + values = values + }) + return (err == nil), ERRSTR[err] +end + +function reorder(self, config, section, index) + local sections + + if type(section) == "string" and type(index) == "number" then + local pos = 0 + + sections = { } + + self:foreach(config, nil, function(s) + if pos == index then + pos = pos + 1 end - if val ~= nil then - rv = val - return false + if s[".name"] ~= section then + pos = pos + 1 + sections[pos] = s[".name"] + else + sections[index + 1] = section end end) + elseif type(section) == "table" then + sections = section + else + return false, "Invalid argument" + end - return rv + local _, err = call("order", { + config = config, + sections = sections + }) + + return (err == nil), ERRSTR[err] end -function Cursor.set_list(self, config, section, option, value) - if config and section and option then - if not value or #value == 0 then - return self:delete(config, section, option) + +function delete(self, config, section, option) + local _, err = call("delete", { + config = config, + section = section, + option = option + }) + return (err == nil), ERRSTR[err] +end + +function delete_all(self, config, stype, comparator) + local _, err + if type(comparator) == "table" then + _, err = call("delete", { + config = config, + type = stype, + match = comparator + }) + elseif type(comparator) == "function" then + local rv = call("get", { + config = config, + type = stype + }) + + if type(rv) == "table" and type(rv.values) == "table" then + local sname, section + for sname, section in pairs(rv.values) do + if comparator(section) then + _, err = call("delete", { + config = config, + section = sname + }) + end + end end - return self:set( - config, section, option, - ( type(value) == "table" and value or { value } ) - ) + elseif comparator == nil then + _, err = call("delete", { + config = config, + type = stype + }) + else + return false, "Invalid argument" end - return false + + return (err == nil), ERRSTR[err] end --- Return a list of initscripts affected by configuration changes. -function Cursor._affected(self, configlist) - configlist = type(configlist) == "table" and configlist or {configlist} - local c = cursor() - c:load("ucitrack") +function apply(self, configlist, command) + configlist = self:_affected(configlist) + if command then + return { "/sbin/luci-reload", unpack(configlist) } + else + return os.execute("/sbin/luci-reload %s >/dev/null 2>&1" + % util.shellquote(table.concat(configlist, " "))) + end +end + +-- Return a list of initscripts affected by configuration changes. +function _affected(self, configlist) + configlist = type(configlist) == "table" and configlist or { configlist } -- Resolve dependencies - local reloadlist = {} + local reloadlist = { } local function _resolve_deps(name) - local reload = {name} - local deps = {} + local reload = { name } + local deps = { } - c:foreach("ucitrack", name, + self:foreach("ucitrack", name, function(section) if section.affects then for i, aff in ipairs(section.affects) do @@ -173,7 +457,9 @@ function Cursor._affected(self, configlist) end end) + local i, dep for i, dep in ipairs(deps) do + local j, add for j, add in ipairs(_resolve_deps(dep)) do reload[#reload+1] = add end @@ -183,7 +469,9 @@ function Cursor._affected(self, configlist) end -- Collect initscripts + local j, config for j, config in ipairs(configlist) do + local i, e for i, e in ipairs(_resolve_deps(config)) do if not util.contains(reloadlist, e) then reloadlist[#reloadlist+1] = e @@ -193,44 +481,3 @@ function Cursor._affected(self, configlist) return reloadlist end - --- curser, means it the parent unloads or loads configs, the sub state will --- do so as well. -function Cursor.substate(self) - Cursor._substates = Cursor._substates or { } - Cursor._substates[self] = Cursor._substates[self] or cursor_state() - return Cursor._substates[self] -end - -local _load = Cursor.load -function Cursor.load(self, ...) - if Cursor._substates and Cursor._substates[self] then - _load(Cursor._substates[self], ...) - end - return _load(self, ...) -end - -local _unload = Cursor.unload -function Cursor.unload(self, ...) - if Cursor._substates and Cursor._substates[self] then - _unload(Cursor._substates[self], ...) - end - return _unload(self, ...) -end - - - - - - - - - - - - - - - - - diff --git a/modules/luci-base/luasrc/model/uci.luadoc b/modules/luci-base/luasrc/model/uci.luadoc index 49093c7930..ef89d09b9e 100644 --- a/modules/luci-base/luasrc/model/uci.luadoc +++ b/modules/luci-base/luasrc/model/uci.luadoc @@ -14,224 +14,226 @@ module "luci.model.uci" ---[[ Create a new UCI-Cursor. -@class function -@name cursor -@return UCI-Cursor +@class function +@name cursor +@return UCI-Cursor ]] ---[[ Create a new Cursor initialized to the state directory. -@class function -@name cursor_state -@return UCI cursor +@class function +@name cursor_state +@return UCI cursor ]] ---[[ Applies UCI configuration changes -@class function -@name Cursor.apply -@param configlist List of UCI configurations -@param command Don't apply only return the command +@class function +@name Cursor.apply +@param configlist List of UCI configurations +@param command Don't apply only return the command ]] ---[[ Delete all sections of a given type that match certain criteria. -@class function -@name Cursor.delete_all +@class function +@name Cursor.delete_all @param config UCI config @param type UCI section type -@param comparator Function that will be called for each section and -returns a boolean whether to delete the current section (optional) +@param comparator Function that will be called for each section and returns + a boolean whether to delete the current section (optional) ]] ---[[ Create a new section and initialize it with data. -@class function -@name Cursor.section -@param config UCI config -@param type UCI section type -@param name UCI section name (optional) -@param values Table of key - value pairs to initialize the section with -@return Name of created section +@class function +@name Cursor.section +@param config UCI config +@param type UCI section type +@param name UCI section name (optional) +@param values Table of key - value pairs to initialize the section with +@return Name of created section ]] ---[[ Updated the data of a section using data from a table. -@class function -@name Cursor.tset -@param config UCI config -@param section UCI section name (optional) -@param values Table of key - value pairs to update the section with +@class function +@name Cursor.tset +@param config UCI config +@param section UCI section name (optional) +@param values Table of key - value pairs to update the section with ]] ---[[ Get a boolean option and return it's value as true or false. -@class function -@name Cursor.get_bool -@param config UCI config -@param section UCI section name -@param option UCI option -@return Boolean +@class function +@name Cursor.get_bool +@param config UCI config +@param section UCI section name +@param option UCI option +@return Boolean ]] ---[[ Get an option or list and return values as table. -@class function -@name Cursor.get_list -@param config UCI config -@param section UCI section name -@param option UCI option -@return table. If the option was not found, you will simply get --- an empty table. +@class function +@name Cursor.get_list +@param config UCI config +@param section UCI section name +@param option UCI option +@return table. If the option was not found, you will simply get an empty + table. ]] ---[[ Get the given option from the first section with the given type. -@class function -@name Cursor.get_first -@param config UCI config -@param type UCI section type -@param option UCI option (optional) -@param default Default value (optional) -@return UCI value +@class function +@name Cursor.get_first +@param config UCI config +@param type UCI section type +@param option UCI option (optional) +@param default Default value (optional) +@return UCI value ]] ---[[ Set given values as list. Setting a list option to an empty list has the same effect as deleting the option. -@class function -@name Cursor.set_list -@param config UCI config -@param section UCI section name -@param option UCI option -@param value value or table. Raw values will become a single item table. -@return Boolean whether operation succeeded +@class function +@name Cursor.set_list +@param config UCI config +@param section UCI section name +@param option UCI option +@param value Value or table. Non-table values will be set as single + item UCI list. +@return Boolean whether operation succeeded ]] ---[[ -Create a sub-state of this cursor. The sub-state is tied to the parent +Create a sub-state of this cursor. -curser, means it the parent unloads or loads configs, the sub state will -do so as well. -@class function -@name Cursor.substate -@return UCI state cursor tied to the parent cursor +The sub-state is tied to the parent curser, means it the parent unloads or +loads configs, the sub state will do so as well. + +@class function +@name Cursor.substate +@return UCI state cursor tied to the parent cursor ]] ---[[ Add an anonymous section. -@class function -@name Cursor.add -@param config UCI config -@param type UCI section type -@return Name of created section +@class function +@name Cursor.add +@param config UCI config +@param type UCI section type +@return Name of created section ]] ---[[ Get a table of saved but uncommitted changes. -@class function -@name Cursor.changes -@param config UCI config -@return Table of changes -@see Cursor.save +@class function +@name Cursor.changes +@param config UCI config +@return Table of changes +@see Cursor.save ]] ---[[ Commit saved changes. -@class function -@name Cursor.commit -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.revert -@see Cursor.save +@class function +@name Cursor.commit +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.revert +@see Cursor.save ]] ---[[ Deletes a section or an option. -@class function -@name Cursor.delete -@param config UCI config -@param section UCI section name -@param option UCI option (optional) -@return Boolean whether operation succeeded +@class function +@name Cursor.delete +@param config UCI config +@param section UCI section name +@param option UCI option (optional) +@return Boolean whether operation succeeded ]] ---[[ Call a function for every section of a certain type. -@class function -@name Cursor.foreach -@param config UCI config -@param type UCI section type -@param callback Function to be called -@return Boolean whether operation succeeded +@class function +@name Cursor.foreach +@param config UCI config +@param type UCI section type +@param callback Function to be called +@return Boolean whether operation succeeded ]] ---[[ Get a section type or an option -@class function -@name Cursor.get -@param config UCI config -@param section UCI section name -@param option UCI option (optional) -@return UCI value +@class function +@name Cursor.get +@param config UCI config +@param section UCI section name +@param option UCI option (optional) +@return UCI value ]] ---[[ Get all sections of a config or all values of a section. -@class function -@name Cursor.get_all -@param config UCI config -@param section UCI section name (optional) -@return Table of UCI sections or table of UCI values +@class function +@name Cursor.get_all +@param config UCI config +@param section UCI section name (optional) +@return Table of UCI sections or table of UCI values ]] ---[[ Manually load a config. -@class function -@name Cursor.load -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.save -@see Cursor.unload +@class function +@name Cursor.load +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.save +@see Cursor.unload ]] ---[[ Revert saved but uncommitted changes. -@class function -@name Cursor.revert -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.commit -@see Cursor.save +@class function +@name Cursor.revert +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.commit +@see Cursor.save ]] ---[[ Saves changes made to a config to make them committable. -@class function -@name Cursor.save -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.load -@see Cursor.unload +@class function +@name Cursor.save +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.load +@see Cursor.unload ]] ---[[ @@ -243,57 +245,74 @@ then a named section of the given type is created. When invoked with four arguments `config`, `sectionname`, `optionname` and `optionvalue` then the value of the specified option is set to the given value. -@class function -@name Cursor.set -@param config UCI config -@param section UCI section name -@param option UCI option or UCI section type +@class function +@name Cursor.set +@param config UCI config +@param section UCI section name +@param option UCI option or UCI section type @param value UCI value or nothing if you want to create a section -@return Boolean whether operation succeeded +@return Boolean whether operation succeeded ]] ---[[ Get the configuration directory. -@class function -@name Cursor.get_confdir -@return Configuration directory +@class function +@name Cursor.get_confdir +@return Configuration directory ]] ---[[ Get the directory for uncomitted changes. -@class function -@name Cursor.get_savedir -@return Save directory +@class function +@name Cursor.get_savedir +@return Save directory +]] + +---[[ +Get the effective session ID. + +@class function +@name Cursor.get_session_id +@return String containing the session ID ]] ---[[ Set the configuration directory. -@class function -@name Cursor.set_confdir +@class function +@name Cursor.set_confdir @param directory UCI configuration directory -@return Boolean whether operation succeeded +@return Boolean whether operation succeeded ]] ---[[ Set the directory for uncommited changes. -@class function -@name Cursor.set_savedir +@class function +@name Cursor.set_savedir @param directory UCI changes directory -@return Boolean whether operation succeeded +@return Boolean whether operation succeeded +]] + +---[[ +Set the effective session ID. + +@class function +@name Cursor.set_session_id +@param id String containing the session ID to set +@return Boolean whether operation succeeded ]] ---[[ Discard changes made to a config. -@class function -@name Cursor.unload -@param config UCI config -@return Boolean whether operation succeeded -@see Cursor.load -@see Cursor.save +@class function +@name Cursor.unload +@param config UCI config +@return Boolean whether operation succeeded +@see Cursor.load +@see Cursor.save ]] diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-base/luasrc/sys.lua index 12b20e4c38..823e20770c 100644 --- a/modules/luci-base/luasrc/sys.lua +++ b/modules/luci-base/luasrc/sys.lua @@ -87,10 +87,10 @@ end function httpget(url, stream, target) if not target then local source = stream and io.popen or luci.util.exec - return source("wget -qO- '"..url:gsub("'", "").."'") + return source("wget -qO- %s" % luci.util.shellquote(url)) else - return os.execute("wget -qO '%s' '%s'" % - {target:gsub("'", ""), url:gsub("'", "")}) + return os.execute("wget -qO %s %s" % + {luci.util.shellquote(target), luci.util.shellquote(url)}) end end @@ -443,18 +443,11 @@ function user.checkpasswd(username, pass) end function user.setpasswd(username, password) - if password then - password = password:gsub("'", [['"'"']]) - end - - if username then - username = username:gsub("'", [['"'"']]) - end - - return os.execute( - "(echo '" .. password .. "'; sleep 1; echo '" .. password .. "') | " .. - "passwd '" .. username .. "' >/dev/null 2>&1" - ) + return os.execute("(echo %s; sleep 1; echo %s) | passwd %s >/dev/null 2>&1" %{ + luci.util.shellquote(password), + luci.util.shellquote(password), + luci.util.shellquote(username) + }) end diff --git a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua b/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua index 6668dad839..47cb901a5b 100644 --- a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua +++ b/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua @@ -202,7 +202,7 @@ TZ = { { 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' }, { 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' }, { 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'Antarctica/Casey', '<+11>-11' }, + { 'Antarctica/Casey', '<+08>-8' }, { 'Antarctica/Davis', '<+07>-7' }, { 'Antarctica/DumontDUrville', '<+10>-10' }, { 'Antarctica/Macquarie', '<+11>-11' }, @@ -239,8 +239,8 @@ TZ = { { 'Asia/Dubai', '<+04>-4' }, { 'Asia/Dushanbe', '<+05>-5' }, { 'Asia/Famagusta', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Asia/Gaza', 'EET-2EEST,M3.5.6/1,M10.5.6/1' }, - { 'Asia/Hebron', 'EET-2EEST,M3.5.6/1,M10.5.6/1' }, + { 'Asia/Gaza', 'EET-2EEST,M3.4.6/1,M10.5.6/1' }, + { 'Asia/Hebron', 'EET-2EEST,M3.4.6/1,M10.5.6/1' }, { 'Asia/Ho Chi Minh', '<+07>-7' }, { 'Asia/Hong Kong', 'HKT-8' }, { 'Asia/Hovd', '<+07>-7' }, diff --git a/modules/luci-base/luasrc/tools/status.lua b/modules/luci-base/luasrc/tools/status.lua index 5012111815..06a9ad4154 100644 --- a/modules/luci-base/luasrc/tools/status.lua +++ b/modules/luci-base/luasrc/tools/status.lua @@ -187,7 +187,9 @@ function switch_status(devs) local switches = { } for dev in devs:gmatch("[^%s,]+") do local ports = { } - local swc = io.popen("swconfig dev %q show" % dev, "r") + local swc = io.popen("swconfig dev %s show" + % luci.util.shellquote(dev), "r") + if swc then local l repeat diff --git a/modules/luci-base/luasrc/util.lua b/modules/luci-base/luasrc/util.lua index 0e7334be87..ce42af2fb0 100644 --- a/modules/luci-base/luasrc/util.lua +++ b/modules/luci-base/luasrc/util.lua @@ -10,6 +10,7 @@ local string = require "string" local coroutine = require "coroutine" local tparser = require "luci.template.parser" local json = require "luci.jsonc" +local lhttp = require "lucihttp" local _ubus = require "ubus" local _ubus_connection = nil @@ -160,10 +161,33 @@ function pcdata(value) return value and tparser.pcdata(tostring(value)) end +function urlencode(value) + if value ~= nil then + local str = tostring(value) + return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL) + or str + end + return nil +end + +function urldecode(value, decode_plus) + if value ~= nil then + local flag = decode_plus and lhttp.DECODE_PLUS or 0 + local str = tostring(value) + return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag) + or str + end + return nil +end + function striptags(value) return value and tparser.striptags(tostring(value)) end +function shellquote(value) + return string.format("'%s'", string.gsub(value or "", "'", "'\\''")) +end + -- for bash, ash and similar shells single-quoted strings are taken -- literally except for single quotes (which terminate the string) -- (and the exception noted below for dash (-) at the start of a @@ -383,16 +407,6 @@ function clone(object, deep) end -function dtable() - return setmetatable({}, { __index = - function(tbl, key) - return rawget(tbl, key) - or rawget(rawset(tbl, key, dtable()), key) - end - }) -end - - -- Serialize the contents of a table value. function _serialize_table(t, seen) assert(not seen[t], "Recursion detected.") @@ -617,6 +631,20 @@ function execl(command) return data end + +local ubus_codes = { + "INVALID_COMMAND", + "INVALID_ARGUMENT", + "METHOD_NOT_FOUND", + "NOT_FOUND", + "NO_DATA", + "PERMISSION_DENIED", + "TIMEOUT", + "NOT_SUPPORTED", + "UNKNOWN_ERROR", + "CONNECTION_FAILED" +} + function ubus(object, method, data) if not _ubus_connection then _ubus_connection = _ubus.connect() @@ -627,7 +655,8 @@ function ubus(object, method, data) if type(data) ~= "table" then data = { } end - return _ubus_connection:call(object, method, data) + local rv, err = _ubus_connection:call(object, method, data) + return rv, err, ubus_codes[err] elseif object then return _ubus_connection:signatures(object) else @@ -652,10 +681,11 @@ end function checklib(fullpathexe, wantedlib) local fs = require "nixio.fs" local haveldd = fs.access('/usr/bin/ldd') - if not haveldd then + local haveexe = fs.access(fullpathexe) + if not haveldd or not haveexe then return false end - local libs = exec("/usr/bin/ldd " .. fullpathexe) + local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe))) if not libs then return false end diff --git a/modules/luci-base/luasrc/util.luadoc b/modules/luci-base/luasrc/util.luadoc index 949aeb21c0..c4f28d039a 100644 --- a/modules/luci-base/luasrc/util.luadoc +++ b/modules/luci-base/luasrc/util.luadoc @@ -15,126 +15,164 @@ Class can be instantiated by calling them. All parameters will be passed to the __init__ function of this class - if such a function exists. The __init__ function must be used to set any object parameters that are not shared with other objects of this class. Any return values will be ignored. -@class function -@name class -@param base The base class to inherit from (optional) -@return A class object -@see instanceof -@see clone + +@class function +@name class +@param base The base class to inherit from (optional) +@return A class object +@see instanceof +@see clone ]] ---[[ Test whether the given object is an instance of the given class. -@class function -@name instanceof -@param object Object instance +@class function +@name instanceof +@param object Object instance @param class Class object to test against -@return Boolean indicating whether the object is an instance +@return Boolean indicating whether the object is an instance @see class @see clone ]] ---[[ Create a new or get an already existing thread local store associated with +the current active coroutine. -the current active coroutine. A thread local store is private a table object +A thread local store is private a table object whose values can't be accessed from outside of the running coroutine. -@class function -@name threadlocal -@return Table value representing the corresponding thread local store + +@class function +@name threadlocal +@return Table value representing the corresponding thread local store ]] ---[[ Write given object to stderr. -@class function -@name perror -@param obj Value to write to stderr -@return Boolean indicating whether the write operation was successful +@class function +@name perror +@param obj Value to write to stderr +@return Boolean indicating whether the write operation was successful ]] ---[[ Recursively dumps a table to stdout, useful for testing and debugging. -@class function -@name dumptable -@param t Table value to dump -@param maxdepth Maximum depth -@return Always nil +@class function +@name dumptable +@param t Table value to dump +@param maxdepth Maximum depth +@return Always nil ]] ---[[ Create valid XML PCDATA from given string. -@class function -@name pcdata -@param value String value containing the data to escape -@return String value containing the escaped data +@class function +@name pcdata +@param value String value containing the data to escape +@return String value containing the escaped data +]] + +---[[ +Decode an URL-encoded string - optionally decoding the "+" sign to space. + +@class function +@name urldecode +@param str Input string in x-www-urlencoded format +@param decode_plus Decode "+" signs to spaces if true (optional) +@return The decoded string +@see urlencode +]] + +---[[ +URL-encode given string. + +@class function +@name urlencode +@param str String to encode +@return String containing the encoded data +@see urldecode ]] ---[[ Strip HTML tags from given string. -@class function -@name striptags -@param value String containing the HTML text -@return String with HTML tags stripped of +@class function +@name striptags +@param value String containing the HTML text +@return String with HTML tags stripped of ]] ---[[ -Splits given string on a defined separator sequence and return a table +Safely quote value for use in shell commands. + +@class function +@name shellquote +@param value String containing the value to quote +@return Single-quote enclosed string with embedded quotes escaped +]] -containing the resulting substrings. The optional max parameter specifies -the number of bytes to process, regardless of the actual length of the given -string. The optional last parameter, regex, specifies whether the separator -sequence is interpreted as regular expression. -@class function -@name split -@param str String value containing the data to split up -@param pat String with separator pattern (optional, defaults to "\n") -@param max Maximum times to split (optional) -@param regex Boolean indicating whether to interpret the separator +---[[ +Splits given string on a defined separator sequence and return a table +containing the resulting substrings. + +The optional max parameter specifies the number of bytes to process, +regardless of the actual length of the given string. The optional last +parameter, regex, specifies whether the separator sequence is +nterpreted as regular expression. + +@class function +@name split +@param str String value containing the data to split up +@param pat String with separator pattern (optional, defaults to "\n") +@param max Maximum times to split (optional) +@param regex Boolean indicating whether to interpret the separator -- pattern as regular expression (optional, default is false) -@return Table containing the resulting substrings +@return Table containing the resulting substrings ]] ---[[ Remove leading and trailing whitespace from given string value. -@class function -@name trim -@param str String value containing whitespace padded data -@return String value with leading and trailing space removed +@class function +@name trim +@param str String value containing whitespace padded data +@return String value with leading and trailing space removed ]] ---[[ Count the occurrences of given substring in given string. -@class function -@name cmatch -@param str String to search in -@param pattern String containing pattern to find -@return Number of found occurrences +@class function +@name cmatch +@param str String to search in +@param pattern String containing pattern to find +@return Number of found occurrences ]] ---[[ -Return a matching iterator for the given value. The iterator will return +Return a matching iterator for the given value. + +The iterator will return one token per invocation, the tokens are separated by +whitespace. If the input value is a table, it is transformed into a string first. +A nil value will result in a valid interator which aborts with the first invocation. -one token per invocation, the tokens are separated by whitespace. If the -input value is a table, it is transformed into a string first. A nil value -will result in a valid interator which aborts with the first invocation. -@class function -@name imatch -@param val The value to scan (table, string or nil) -@return Iterator which returns one token per call +@class function +@name imatch +@param val The value to scan (table, string or nil) +@return Iterator which returns one token per call ]] ---[[ Parse certain units from the given string and return the canonical integer +value or 0 if the unit is unknown. -value or 0 if the unit is unknown. Upper- or lower case is irrelevant. +Upper- or lower case is irrelevant. Recognized units are: + -- o "y" - one year (60*60*24*366) o "m" - one month (60*60*24*31) o "w" - one week (60*60*24*7) @@ -147,232 +185,229 @@ Recognized units are: o "kib" - one si kilobyte (1000) o "mib" - one si megabyte (1000*1000) o "gib" - one si gigabyte (1000*1000*1000) -@class function -@name parse_units -@param ustr String containing a numerical value with trailing unit -@return Number containing the canonical value + +@class function +@name parse_units +@param ustr String containing a numerical value with trailing unit +@return Number containing the canonical value ]] ---[[ Appends numerically indexed tables or single objects to a given table. -@class function -@name append -@param src Target table -@param ... Objects to insert -@return Target table +@class function +@name append +@param src Target table +@param ... Objects to insert +@return Target table ]] ---[[ Combines two or more numerically indexed tables and single objects into one table. -@class function -@name combine -@param tbl1 Table value to combine -@param tbl2 Table value to combine -@param ... More tables to combine -@return Table value containing all values of given tables +@class function +@name combine +@param tbl1 Table value to combine +@param tbl2 Table value to combine +@param ... More tables to combine +@return Table value containing all values of given tables ]] ---[[ Checks whether the given table contains the given value. -@class function -@name contains -@param table Table value -@param value Value to search within the given table -@return number indicating the first index at which the given value occurs --- within table or false. +@class function +@name contains +@param table Table value +@param value Value to search within the given table +@return Number indicating the first index at which the given value occurs +-- within table or false. ]] ---[[ Update values in given table with the values from the second given table. Both table are - in fact - merged together. -@class function -@name update + +@class function +@name update @param t Table which should be updated -@param updates Table containing the values to update -@return Always nil +@param updates Table containing the values to update +@return Always nil ]] ---[[ Retrieve all keys of given associative table. -@class function -@name keys -@param t Table to extract keys from -@return Sorted table containing the keys +@class function +@name keys +@param t Table to extract keys from +@return Sorted table containing the keys ]] ---[[ Clones the given object and return it's copy. -@class function -@name clone -@param object Table value to clone -@param deep Boolean indicating whether to do recursive cloning -@return Cloned table value -]] - ----[[ -Create a dynamic table which automatically creates subtables. - -@class function -@name dtable -@return Dynamic Table +@class function +@name clone +@param object Table value to clone +@param deep Boolean indicating whether to do recursive cloning +@return Cloned table value ]] ---[[ Recursively serialize given data to lua code, suitable for restoring - with loadstring(). -@class function -@name serialize_data -@param val Value containing the data to serialize -@return String value containing the serialized code -@see restore_data -@see get_bytecode + +@class function +@name serialize_data +@param val Value containing the data to serialize +@return String value containing the serialized code +@see restore_data +@see get_bytecode ]] ---[[ Restore data previously serialized with serialize_data(). -@class function -@name restore_data -@param str String containing the data to restore -@return Value containing the restored data structure -@see serialize_data -@see get_bytecode +@class function +@name restore_data +@param str String containing the data to restore +@return Value containing the restored data structure +@see serialize_data +@see get_bytecode ]] ---[[ Return the current runtime bytecode of the given data. The byte code - will be stripped before it is returned. -@class function -@name get_bytecode -@param val Value to return as bytecode -@return String value containing the bytecode of the given data + +@class function +@name get_bytecode +@param val Value to return as bytecode +@return String value containing the bytecode of the given data ]] ---[[ -Strips unnescessary lua bytecode from given string. Information like line +Strips unnescessary lua bytecode from given string. + +Information like line numbers and debugging numbers will be discarded. +Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) -numbers and debugging numbers will be discarded. Original version by -Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) -@class function -@name strip_bytecode -@param code String value containing the original lua byte code -@return String value containing the stripped lua byte code +@class function +@name strip_bytecode +@param code String value containing the original lua byte code +@return String value containing the stripped lua byte code ]] ---[[ Return a key, value iterator which returns the values sorted according to - the provided callback function. -@class function -@name spairs -@param t The table to iterate -@param f A callback function to decide the order of elements -@return Function value containing the corresponding iterator + +@class function +@name spairs +@param t The table to iterate +@param f A callback function to decide the order of elements +@return Function value containing the corresponding iterator ]] ---[[ Return a key, value iterator for the given table. The table pairs are sorted by key. -@class function -@name kspairs -@param t The table to iterate -@return Function value containing the corresponding iterator + +@class function +@name kspairs +@param t The table to iterate +@return Function value containing the corresponding iterator ]] ---[[ Return a key, value iterator for the given table. The table pairs are sorted by value. -@class function -@name vspairs -@param t The table to iterate -@return Function value containing the corresponding iterator + +@class function +@name vspairs +@param t The table to iterate +@return Function value containing the corresponding iterator ]] ---[[ Test whether the current system is operating in big endian mode. -@class function -@name bigendian -@return Boolean value indicating whether system is big endian +@class function +@name bigendian +@return Boolean value indicating whether system is big endian ]] ---[[ Execute given commandline and gather stdout. -@class function -@name exec -@param command String containing command to execute -@return String containing the command's stdout +@class function +@name exec +@param command String containing command to execute +@return String containing the command's stdout ]] ---[[ Return a line-buffered iterator over the output of given command. -@class function -@name execi -@param command String containing the command to execute -@return Iterator +@class function +@name execi +@param command String containing the command to execute +@return Iterator ]] ---[[ Issue an ubus call. -@class function -@name ubus +@class function +@name ubus @param object String containing the ubus object to call @param method String containing the ubus method to call @param values Table containing the values to pass -@return Table containin the ubus result +@return Table containin the ubus result ]] ---[[ Convert data structure to JSON -@class function -@name serialize_json -@param data The data to serialize -@param writer A function to write a chunk of JSON data (optional) -@return String containing the JSON if called without write callback +@class function +@name serialize_json +@param data The data to serialize +@param writer A function to write a chunk of JSON data (optional) +@return String containing the JSON if called without write callback ]] ---[[ Returns the absolute path to LuCI base directory. -@class function -@name libpath -@return String containing the directory path +@class function +@name libpath +@return String containing the directory path ]] ---[[ This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function -@class function -@name coxpcall -@param f Lua function to be called protected -@param err Custom error handler -@param ... Parameters passed to the function -@return A boolean whether the function call succeeded and the return --- values of either the function or the error handler +@class function +@name coxpcall +@param f Lua function to be called protected +@param err Custom error handler +@param ... Parameters passed to the function +@return A boolean whether the function call succeeded and the return +-- values of either the function or the error handler ]] ---[[ This is a coroutine-safe drop-in replacement for Lua's "pcall"-function -@class function -@name copcall -@param f Lua function to be called protected -@param ... Parameters passed to the function -@return A boolean whether the function call succeeded and the returns --- values of the function or the error object +@class function +@name copcall +@param f Lua function to be called protected +@param ... Parameters passed to the function +@return A boolean whether the function call succeeded and the returns +-- values of the function or the error object ]] diff --git a/modules/luci-base/luasrc/view/cbi/filebrowser.htm b/modules/luci-base/luasrc/view/cbi/filebrowser.htm index a79beebba7..806b1b5f40 100644 --- a/modules/luci-base/luasrc/view/cbi/filebrowser.htm +++ b/modules/luci-base/luasrc/view/cbi/filebrowser.htm @@ -22,9 +22,9 @@ <script type="text/javascript"> function callback(path) { if( window.opener ) { - var input = window.opener.document.getElementById('<%=luci.http.formvalue('field')%>'); + var input = window.opener.document.getElementById(decodeURIComponent('<%=luci.http.urlencode(luci.http.formvalue('field'))%>')); if( input ) { - input.value = path; + input.value = decodeURIComponent(path); window.close(); } } @@ -48,33 +48,44 @@ end end - local filepath = table.concat( path, '/' ) - local filestat = nixio.fs.stat( filepath ) - local baseurl = luci.dispatcher.build_url('admin', 'filebrowser') + local filestat = nixio.fs.stat(table.concat(path, '/')) + local baseurl = { 'admin', 'filebrowser' } if filestat and filestat.type == "reg" then - table.remove( path, #path ) - filepath = table.concat( path, '/' ) .. '/' - elseif not ( filestat and filestat.type == "dir" ) then - path = { '' } - filepath = '/' + path[#path] = '' + elseif not (filestat and filestat.type == "dir") then + path = { '', '' } else - filepath = filepath .. '/' + path[#path+1] = '' end - local entries = nixio.util.consume((nixio.fs.dir(filepath))) + filepath = table.concat(path, '/') + + local entries = {} + local _, e + for _, e in luci.util.vspairs(nixio.util.consume((nixio.fs.dir(filepath)))) do + local p = filepath .. e + local s = nixio.fs.stat(p) + if s then + entries[#entries+1] = { + name = e, + path = p, + type = s.type + } + end + end -%> - <div id="path"> + <div id="path"> Location: <% for i, dir in ipairs(path) do %> <% if i == 1 then %> - <a href="<%=baseurl%>?field=<%=field%>">(root)</a> + <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>">(root)</a> <% elseif next(path, i) then %> - <% baseurl = baseurl .. '/' .. dir %> - / <a href="<%=baseurl%>?field=<%=field%>"><%=dir%></a> + <% baseurl[#baseurl+1] = luci.http.urlencode(dir) %> + / <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(dir)%></a> <% else %> - <% baseurl = baseurl .. '/' .. dir %> - / <%=dir%> + <% baseurl[#baseurl+1] = luci.http.urlencode(dir) %> + / <%=pcdata(dir)%> <% end %> <% end %> </div> @@ -83,23 +94,17 @@ <div id="listing"> <ul> - <% for _, e in luci.util.vspairs(entries) do - local stat = nixio.fs.stat(filepath..e) - if stat and stat.type == 'dir' then - -%> + <% for _, e in ipairs(entries) do if e.type == 'dir' then -%> <li class="dir"> <img src="<%=resource%>/cbi/folder.gif" alt="<%:Directory%>" /> - <a href="<%=baseurl%>/<%=e%>?field=<%=field%>"><%=e%>/</a> + <a href="<%=url(unpack(baseurl))%>/<%=luci.http.urlencode(e.name)%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(e.name)%>/</a> </li> <% end end -%> - <% for _, e in luci.util.vspairs(entries) do - local stat = nixio.fs.stat(filepath..e) - if stat and stat.type ~= 'dir' then - -%> + <% for _, e in ipairs(entries) do if e.type ~= 'dir' then -%> <li class="file"> <img src="<%=resource%>/cbi/file.gif" alt="<%:File%>" /> - <a href="#" onclick="callback('<%=filepath..e%>')"><%=e%></a> + <a href="#" onclick="callback('<%=luci.http.urlencode(e.path)%>')"><%=pcdata(e.name)%></a> </li> <% end end -%> </ul> diff --git a/modules/luci-base/luasrc/view/cbi/simpleform.htm b/modules/luci-base/luasrc/view/cbi/simpleform.htm index 78f5c5a544..3b758d70ee 100644 --- a/modules/luci-base/luasrc/view/cbi/simpleform.htm +++ b/modules/luci-base/luasrc/view/cbi/simpleform.htm @@ -52,7 +52,8 @@ <%- if not self.cancel then -%><%-:Cancel-%><%-else-%><%=self.cancel%><%end-%> " /> <% end %> - <script type="text/javascript">cbi_d_update();</script> </div> </form> <% end %> + +<script type="text/javascript">cbi_init();</script> diff --git a/modules/luci-base/luasrc/view/cbi/tblsection.htm b/modules/luci-base/luasrc/view/cbi/tblsection.htm index 26d13f9372..3cb87563f1 100644 --- a/modules/luci-base/luasrc/view/cbi/tblsection.htm +++ b/modules/luci-base/luasrc/view/cbi/tblsection.htm @@ -35,7 +35,7 @@ end <%- else -%> <th> </th> <%- end -%> - <%- end -%> + <%- count = count +1; end -%> <%- for i, k in pairs(self.children) do if not k.optional then -%> <th class="cbi-section-table-cell"<%=width(k)%>> <%- if k.titleref then -%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%- end -%> @@ -44,7 +44,7 @@ end </th> <%- count = count + 1; end; end; if self.sortable then -%> <th class="cbi-section-table-cell"><%:Sort%></th> - <%- end; if self.extedit or self.addremove then -%> + <%- count = count + 1; end; if self.extedit or self.addremove then -%> <th class="cbi-section-table-cell"> </th> <%- count = count + 1; end -%> </tr> diff --git a/modules/luci-base/luasrc/view/error404.htm b/modules/luci-base/luasrc/view/error404.htm index bc74226830..a762f6038b 100644 --- a/modules/luci-base/luasrc/view/error404.htm +++ b/modules/luci-base/luasrc/view/error404.htm @@ -7,5 +7,5 @@ <%+header%> <h2 name="content">404 <%:Not Found%></h2> <p><%:Sorry, the object you requested was not found.%></p> -<tt><%:Unable to dispatch%>: <%=luci.http.request.env.PATH_INFO%></tt> +<tt><%:Unable to dispatch%>: <%=url(unpack(luci.dispatcher.context.request))%></tt> <%+footer%> diff --git a/modules/luci-base/luasrc/view/sysauth.htm b/modules/luci-base/luasrc/view/sysauth.htm index f6b0f5706a..b3ec9b7617 100644 --- a/modules/luci-base/luasrc/view/sysauth.htm +++ b/modules/luci-base/luasrc/view/sysauth.htm @@ -6,7 +6,7 @@ <%+header%> -<form method="post" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>"> +<form method="post" action="<%=pcdata(FULL_REQUEST_URI)%>"> <%- if fuser then %> <div class="errorbox"><%:Invalid username and/or password! Please try again.%></div> <% end -%> diff --git a/modules/luci-base/po/ca/base.po b/modules/luci-base/po/ca/base.po index a6a8843a74..c413b7172d 100644 --- a/modules/luci-base/po/ca/base.po +++ b/modules/luci-base/po/ca/base.po @@ -744,6 +744,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2154,6 +2159,9 @@ msgstr "Avís" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "D'acord" @@ -2913,6 +2921,9 @@ msgstr "Mida" msgid "Size (.ipk)" msgstr "Mida (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Salta" @@ -3305,7 +3316,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/cs/base.po b/modules/luci-base/po/cs/base.po index c69654f1ed..89714cc818 100644 --- a/modules/luci-base/po/cs/base.po +++ b/modules/luci-base/po/cs/base.po @@ -738,6 +738,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2162,6 +2167,9 @@ msgstr "Oznámení" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2939,6 +2947,9 @@ msgstr "Velikost" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Přeskočit" @@ -3347,7 +3358,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/de/base.po b/modules/luci-base/po/de/base.po index 47472a37cf..fd495b9507 100644 --- a/modules/luci-base/po/de/base.po +++ b/modules/luci-base/po/de/base.po @@ -764,6 +764,11 @@ msgid "Custom feeds" msgstr "Eigene Repositories" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "Passt das Verhalten der Geräte-LEDs an - wenn dies möglich ist." @@ -2228,6 +2233,9 @@ msgstr "Notiz" msgid "Nslookup" msgstr "DNS-Auflösung" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -3039,6 +3047,9 @@ msgstr "Größe" msgid "Size (.ipk)" msgstr "Größe (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Überspringen" @@ -3480,10 +3491,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Dies ist die lokale, vom Broker zugewiesene IPv6-Adresse, sie endet " -"üblicherweise mit <code>:2</code>" +"üblicherweise mit <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/el/base.po b/modules/luci-base/po/el/base.po index d0b9e240f6..ad5ed07fb9 100644 --- a/modules/luci-base/po/el/base.po +++ b/modules/luci-base/po/el/base.po @@ -747,6 +747,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2170,6 +2175,9 @@ msgstr "Επισήμανση" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "Εντάξει" @@ -2931,6 +2939,9 @@ msgstr "Μέγεθος" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Παράκαμψη" @@ -3307,7 +3318,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/en/base.po b/modules/luci-base/po/en/base.po index fbaa03b6f0..f629135950 100644 --- a/modules/luci-base/po/en/base.po +++ b/modules/luci-base/po/en/base.po @@ -734,6 +734,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2137,6 +2142,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2895,6 +2903,9 @@ msgstr "Size" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Skip" @@ -3267,7 +3278,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/es/base.po b/modules/luci-base/po/es/base.po index a92bb43c1b..776f7fb15c 100644 --- a/modules/luci-base/po/es/base.po +++ b/modules/luci-base/po/es/base.po @@ -743,6 +743,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2176,6 +2181,9 @@ msgstr "Aviso" msgid "Nslookup" msgstr "NSLookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "Aceptar" @@ -2952,6 +2960,9 @@ msgstr "Tamaño" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Saltar" @@ -3372,10 +3383,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Esta es la dirección de punto final asignada por el broker del túnel, suele " -"terminar con <code>:2</code>" +"terminar con <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/fr/base.po b/modules/luci-base/po/fr/base.po index cba7caca37..9de1687204 100644 --- a/modules/luci-base/po/fr/base.po +++ b/modules/luci-base/po/fr/base.po @@ -750,6 +750,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2190,6 +2195,9 @@ msgstr "Note" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2966,6 +2974,9 @@ msgstr "Taille" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Passer au suivant" @@ -3387,10 +3398,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Il s'agit de l'adresse de l'extrémité locale attribuée par le fournisseur de " -"tunnels, elle se termine habituellement avec <code>:2</code>" +"tunnels, elle se termine habituellement avec <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/he/base.po b/modules/luci-base/po/he/base.po index 6d98134a44..8d5daf3890 100644 --- a/modules/luci-base/po/he/base.po +++ b/modules/luci-base/po/he/base.po @@ -727,6 +727,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2110,6 +2115,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "" @@ -2862,6 +2870,9 @@ msgstr "" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3228,7 +3239,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/hu/base.po b/modules/luci-base/po/hu/base.po index e7b3a79bc0..5e2ea2b176 100644 --- a/modules/luci-base/po/hu/base.po +++ b/modules/luci-base/po/hu/base.po @@ -745,6 +745,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2179,6 +2184,9 @@ msgstr "Megjegyzés" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2957,6 +2965,9 @@ msgstr "Méret" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Ugrás" @@ -3375,10 +3386,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Ez az alagút közvetítő (tunnel broker) által megadott helyi végpont címe, " -"általában így végződik: <code>:2</code>" +"általában így végződik: <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/it/base.po b/modules/luci-base/po/it/base.po index 414fddf39a..6b55e23e22 100644 --- a/modules/luci-base/po/it/base.po +++ b/modules/luci-base/po/it/base.po @@ -750,6 +750,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2179,6 +2184,9 @@ msgstr "Notifica" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2941,6 +2949,9 @@ msgstr "Dimensione" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Salta" @@ -3335,7 +3346,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/ja/base.po b/modules/luci-base/po/ja/base.po index c06994002b..b643e8cf5b 100644 --- a/modules/luci-base/po/ja/base.po +++ b/modules/luci-base/po/ja/base.po @@ -3,18 +3,18 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-06-10 03:40+0200\n" -"PO-Revision-Date: 2017-10-20 13:54+0900\n" +"PO-Revision-Date: 2018-04-26 00:23+0900\n" "Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 2.0.4\n" +"X-Generator: Poedit 2.0.7\n" "Language-Team: \n" msgid "%.1f dB" -msgstr "" +msgstr "%.1f dB" msgid "%s is untagged in multiple VLANs!" msgstr "%s は複数のVLANにUntaggedしています!" @@ -137,7 +137,7 @@ msgid "<abbr title=\"Media Access Control\">MAC</abbr>-Address" msgstr "<abbr title=\"Media Access Control\">MAC</abbr>-アドレス" msgid "<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>" -msgstr "" +msgstr "<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>" msgid "" "<abbr title=\"maximal\">Max.</abbr> <abbr title=\"Dynamic Host Configuration " @@ -251,6 +251,8 @@ msgstr "追加" msgid "Add local domain suffix to names served from hosts files" msgstr "" +"hosts ファイルにより解決される名前にローカルドメイン サフィックスを付加しま" +"す。" msgid "Add new interface..." msgstr "インターフェースの新規作成..." @@ -751,6 +753,13 @@ msgid "Custom feeds" msgstr "カスタム フィード" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" +"カスタム ファイル(証明書, スクリプト)がシステムに残るかもしれません。これを" +"防ぐには、まず最初に factory-reset を行います。" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -1254,7 +1263,7 @@ msgid "Force use of NAT-T" msgstr "NAT-Tの強制使用" msgid "Form token mismatch" -msgstr "" +msgstr "フォーム トークンの不一致" msgid "Forward DHCP traffic" msgstr "DHCPトラフィックを転送する" @@ -1661,7 +1670,7 @@ msgstr "" "ユーザー名かパスワード、もしくは両方が不正です!もう一度入力してください。" msgid "Isolate Clients" -msgstr "" +msgstr "クライアント間の分離" msgid "" "It appears that you are trying to flash an image that does not fit into the " @@ -1756,6 +1765,8 @@ msgstr "割り当て数" msgid "Limit DNS service to subnets interfaces on which we are serving DNS." msgstr "" +"DNS サービスを、現在 DNS を提供しているサブネットのインターフェースに限定しま" +"す。" msgid "Limit listening to these interfaces, and loopback." msgstr "待ち受けをこれらのインターフェースとループバックに制限します。" @@ -1840,7 +1851,7 @@ msgid "Local IPv6 address" msgstr "ローカル IPv6 アドレス" msgid "Local Service Only" -msgstr "" +msgstr "ローカルサービスのみ" msgid "Local Startup" msgstr "ローカル スタートアップ" @@ -1855,6 +1866,8 @@ msgid "" "Local domain specification. Names matching this domain are never forwarded " "and are resolved from DHCP or hosts files only" msgstr "" +"ローカル ドメインの定義です。このドメインに一致する名前は転送が行われず、 " +"DHCP または hosts ファイルのみにより解決されます。" msgid "Local domain suffix appended to DHCP names and hosts file entries" msgstr "" @@ -2178,6 +2191,9 @@ msgstr "注意" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2962,6 +2978,9 @@ msgstr "サイズ" msgid "Size (.ipk)" msgstr "サイズ (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "スキップ" @@ -3085,10 +3104,10 @@ msgid "Submit" msgstr "送信" msgid "Suppress logging" -msgstr "" +msgstr "ログの抑制" msgid "Suppress logging of the routine operation of these protocols" -msgstr "" +msgstr "これらのプロトコルのルーチン的操作についてのログを抑制します。" msgid "Swap" msgstr "スワップ" @@ -3110,7 +3129,7 @@ msgid "" msgstr "" msgid "Switch Port Mask" -msgstr "" +msgstr "スイッチポート マスク" msgid "Switch VLAN" msgstr "" @@ -3338,13 +3357,16 @@ msgstr "" "サービスを有効にするために、管理者パスワードを設定してください。" msgid "This IPv4 address of the relay" -msgstr "" +msgstr "リレーの IPv4 アドレス" msgid "" "This file may contain lines like 'server=/domain/1.2.3.4' or " "'server=1.2.3.4' fordomain-specific or full upstream <abbr title=\"Domain " "Name System\">DNS</abbr> servers." msgstr "" +"このファイルは、特定ドメイン用、または上位 <abbr title=\"Domain Name System" +"\">DNS</abbr> サーバーのための 'server=/domain/1.2.3.4' や 'server=1.2.3.4' " +"というような行を含めることができます。" msgid "" "This is a list of shell glob patterns for matching files and directories to " @@ -3369,17 +3391,17 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "プロバイダからアサインされた、ローカルのエンドポイント アドレスです。通常、" -"<code>:2</code>が終端に設定されます。" +"<code>...:2/64</code>が終端に設定されます。" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" "abbr> in the local network" msgstr "" -"ローカル ネットワーク内のみの <abbr title=\"Dynamic Host Configuration " -"Protocol\">DHCP</abbr>として使用する" +"これはローカル ネットワーク内のみの <abbr title=\"Dynamic Host Configuration " +"Protocol\">DHCP</abbr> です。" msgid "This is the plain username for logging into the account" msgstr "" @@ -3946,24 +3968,3 @@ msgstr "はい" msgid "« Back" msgstr "« 戻る" - -#~ msgid "Action" -#~ msgstr "動作" - -#~ msgid "Buttons" -#~ msgstr "ボタン" - -#~ msgid "Handler" -#~ msgstr "ハンドラ" - -#~ msgid "Maximum hold time" -#~ msgstr "最大保持時間" - -#~ msgid "Minimum hold time" -#~ msgstr "最短保持時間" - -#~ msgid "Path to executable which handles the button event" -#~ msgstr "ボタンイベントをハンドルする実行ファイルのパス" - -#~ msgid "This page allows the configuration of custom button actions" -#~ msgstr "このページでは、ボタンの動作を変更することができます。" diff --git a/modules/luci-base/po/ko/base.po b/modules/luci-base/po/ko/base.po index c56c05e2a2..04d3c6a23a 100644 --- a/modules/luci-base/po/ko/base.po +++ b/modules/luci-base/po/ko/base.po @@ -732,6 +732,11 @@ msgid "Custom feeds" msgstr "Custom feed 들" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2128,6 +2133,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "" @@ -2890,6 +2898,9 @@ msgstr "Size" msgid "Size (.ipk)" msgstr "크기 (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3270,7 +3281,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/ms/base.po b/modules/luci-base/po/ms/base.po index ff33243158..b478bd623b 100644 --- a/modules/luci-base/po/ms/base.po +++ b/modules/luci-base/po/ms/base.po @@ -712,6 +712,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "Mengkustomisasi perilaku peranti LED jika mungkin." @@ -2108,6 +2113,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "Baik" @@ -2864,6 +2872,9 @@ msgstr "Saiz" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Skip" @@ -3238,7 +3249,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/no/base.po b/modules/luci-base/po/no/base.po index f8b40c1e84..502c3b38a8 100644 --- a/modules/luci-base/po/no/base.po +++ b/modules/luci-base/po/no/base.po @@ -734,6 +734,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2153,6 +2158,9 @@ msgstr "Merk" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2930,6 +2938,9 @@ msgstr "Størrelse" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Gå videre" @@ -3343,10 +3354,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Dette er den lokale endepunkt adressen som ble tildelt av tunnel 'broker', " -"adressen ender vanligvis med <code>:2</code>" +"adressen ender vanligvis med <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/pl/base.po b/modules/luci-base/po/pl/base.po index 9bc33a46cc..956e566e91 100644 --- a/modules/luci-base/po/pl/base.po +++ b/modules/luci-base/po/pl/base.po @@ -752,6 +752,11 @@ msgstr "" msgid "Custom feeds" msgstr "" +msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + # Spacji zabrało i napisy się skleiły msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" @@ -2198,6 +2203,9 @@ msgstr "Spostrzeżenie" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2978,6 +2986,9 @@ msgstr "Rozmiar" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Pomiń" @@ -3400,10 +3411,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "To jest lokalny adres końcowy przypisany przez tunnel broker'a, zwykle " -"kończący się z <code>:2</code>" +"kończący się z <code>...:2/64</code>" # w tłumaczeniu pojawiła się spacja po DHCP</abbr> co powoduje niepoprawne wyświetlanie się strony z lang PL msgid "" diff --git a/modules/luci-base/po/pt-br/base.po b/modules/luci-base/po/pt-br/base.po index bf0de75dd4..9c4901f3d4 100644 --- a/modules/luci-base/po/pt-br/base.po +++ b/modules/luci-base/po/pt-br/base.po @@ -787,6 +787,11 @@ msgid "Custom feeds" msgstr "Fontes de pacotes customizadas" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2279,6 +2284,9 @@ msgstr "Aviso" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -3084,6 +3092,9 @@ msgstr "Tamanho" msgid "Size (.ipk)" msgstr "Tamanho (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Pular" @@ -3519,10 +3530,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Este é o endereço da ponta local designado pelo agente de túnel. normalmente " -"ele termina com <code>:2</code>" +"ele termina com <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/pt/base.po b/modules/luci-base/po/pt/base.po index 3109903896..8f2622c26d 100644 --- a/modules/luci-base/po/pt/base.po +++ b/modules/luci-base/po/pt/base.po @@ -747,6 +747,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2177,6 +2182,9 @@ msgstr "Reparo" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2948,6 +2956,9 @@ msgstr "Tamanho" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Saltar" @@ -3347,7 +3358,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/ro/base.po b/modules/luci-base/po/ro/base.po index 955cff6500..86eaa6495d 100644 --- a/modules/luci-base/po/ro/base.po +++ b/modules/luci-base/po/ro/base.po @@ -722,6 +722,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2107,6 +2112,9 @@ msgstr "Notificare" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2858,6 +2866,9 @@ msgstr "Marime" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3220,7 +3231,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/ru/base.po b/modules/luci-base/po/ru/base.po index c0b53eb9d9..4ffb7233c2 100644 --- a/modules/luci-base/po/ru/base.po +++ b/modules/luci-base/po/ru/base.po @@ -778,6 +778,11 @@ msgid "Custom feeds" msgstr "Список custom-ных feed-ов" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2235,6 +2240,9 @@ msgstr "Заметка" msgid "Nslookup" msgstr "DNS-запрос" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -3043,6 +3051,9 @@ msgstr "Размер" msgid "Size (.ipk)" msgstr "Размер (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Пропустить" @@ -3471,10 +3482,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Это локальный адрес, назначенный туннельным брокером, обычно заканчивается " -"на <code>:2</code>." +"на <code>...:2/64</code>." msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/sk/base.po b/modules/luci-base/po/sk/base.po index ec72661dd2..a17ac98e20 100644 --- a/modules/luci-base/po/sk/base.po +++ b/modules/luci-base/po/sk/base.po @@ -705,6 +705,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2082,6 +2087,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "" @@ -2830,6 +2838,9 @@ msgstr "" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3190,7 +3201,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/sv/base.po b/modules/luci-base/po/sv/base.po index a7f906e819..089546a37d 100644 --- a/modules/luci-base/po/sv/base.po +++ b/modules/luci-base/po/sv/base.po @@ -719,6 +719,11 @@ msgid "Custom feeds" msgstr "Anpassade flöden" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2103,6 +2108,9 @@ msgstr "Avisering" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2853,6 +2861,9 @@ msgstr "Storlek" msgid "Size (.ipk)" msgstr "Storlek (.ipk)" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Hoppa över" @@ -3215,7 +3226,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/templates/base.pot b/modules/luci-base/po/templates/base.pot index a8409213fe..de8b7fb22c 100644 --- a/modules/luci-base/po/templates/base.pot +++ b/modules/luci-base/po/templates/base.pot @@ -698,6 +698,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2075,6 +2080,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "" @@ -2823,6 +2831,9 @@ msgstr "" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3183,7 +3194,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/tr/base.po b/modules/luci-base/po/tr/base.po index 496d96f7c3..45f4a7c342 100644 --- a/modules/luci-base/po/tr/base.po +++ b/modules/luci-base/po/tr/base.po @@ -718,6 +718,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2095,6 +2100,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "" @@ -2843,6 +2851,9 @@ msgstr "" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3203,7 +3214,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/uk/base.po b/modules/luci-base/po/uk/base.po index 520bff481e..b1feed3d18 100644 --- a/modules/luci-base/po/uk/base.po +++ b/modules/luci-base/po/uk/base.po @@ -756,6 +756,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2191,6 +2196,9 @@ msgstr "Попередження" msgid "Nslookup" msgstr "DNS-запит" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK" @@ -2973,6 +2981,9 @@ msgstr "Розмір" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "Пропустити" @@ -3391,10 +3402,10 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" "Це локальна адреса кінцевої точки, присвоєна тунельним брокером, зазвичай " -"закінчується на <code>:2</code>" +"закінчується на <code>...:2/64</code>" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/vi/base.po b/modules/luci-base/po/vi/base.po index 2287dfba92..ecb369e13e 100644 --- a/modules/luci-base/po/vi/base.po +++ b/modules/luci-base/po/vi/base.po @@ -712,6 +712,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2112,6 +2117,9 @@ msgstr "" msgid "Nslookup" msgstr "" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "OK " @@ -2870,6 +2878,9 @@ msgstr "Dung lượng " msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "" @@ -3240,7 +3251,7 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" +"ends with <code>...:2/64</code>" msgstr "" msgid "" diff --git a/modules/luci-base/po/zh-cn/base.po b/modules/luci-base/po/zh-cn/base.po index c0a5351573..c76511b991 100644 --- a/modules/luci-base/po/zh-cn/base.po +++ b/modules/luci-base/po/zh-cn/base.po @@ -721,6 +721,12 @@ msgid "Custom feeds" msgstr "自定义软件源" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" +"自定义文件(证书、脚本)会保留在系统上。若无需保留,请先执行恢复出厂设置。" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "自定义此设备的 <abbr title=\"Light Emitting Diode\">LED</abbr> 行为。" @@ -2127,6 +2133,9 @@ msgstr "注意" msgid "Nslookup" msgstr "Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "缓存的 DNS 条目数量(最大 10000,0 表示不缓存)" + msgid "OK" msgstr "确认" @@ -2900,6 +2909,9 @@ msgstr "大小" msgid "Size (.ipk)" msgstr "大小(.ipk)" +msgid "Size of DNS query cache" +msgstr "DNS 查询缓存的大小" + msgid "Skip" msgstr "跳过" @@ -3283,8 +3295,8 @@ msgstr "启动脚本插入到 'exit 0' 之前即可随系统启动运行。" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" -msgstr "隧道代理分配的本地终端地址,通常以 <code>:2</code> 结尾" +"ends with <code>...:2/64</code>" +msgstr "隧道代理分配的本地终端地址,通常以 <code>...:2/64</code> 结尾" msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" diff --git a/modules/luci-base/po/zh-tw/base.po b/modules/luci-base/po/zh-tw/base.po index d78223f2a5..28a806e839 100644 --- a/modules/luci-base/po/zh-tw/base.po +++ b/modules/luci-base/po/zh-tw/base.po @@ -723,6 +723,11 @@ msgid "Custom feeds" msgstr "" msgid "" +"Custom files (certificates, scripts) may remain on the system. To prevent " +"this, perform a factory-reset first." +msgstr "" + +msgid "" "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode" "\">LED</abbr>s if possible." msgstr "" @@ -2119,6 +2124,9 @@ msgstr "通知" msgid "Nslookup" msgstr "DNS偵錯Nslookup" +msgid "Number of cached DNS entries (max is 10000, 0 is no caching)" +msgstr "" + msgid "OK" msgstr "行" @@ -2883,6 +2891,9 @@ msgstr "大小" msgid "Size (.ipk)" msgstr "" +msgid "Size of DNS query cache" +msgstr "" + msgid "Skip" msgstr "跳過" @@ -3275,8 +3286,8 @@ msgstr "" msgid "" "This is the local endpoint address assigned by the tunnel broker, it usually " -"ends with <code>:2</code>" -msgstr "這是由通道代理人指定的本地終端位址, 通常用 <code>:2</code>結尾." +"ends with <code>...:2/64</code>" +msgstr "這是由通道代理人指定的本地終端位址, 通常用 <code>...:2/64</code>結尾." msgid "" "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" 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 new file mode 100644 index 0000000000..ed7ad8aa8a --- /dev/null +++ b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json @@ -0,0 +1,11 @@ +{ + "uci-access": { + "description": "Grant uci write access to all configurations", + "read": { + "uci": [ "*" ] + }, + "write": { + "uci": [ "*" ] + } + } +} diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua index 33f6a67038..ab6db4fefb 100644 --- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua @@ -82,7 +82,7 @@ function index() end - page = entry({"admin", "network", "iface_add"}, cbi("admin_network/iface_add"), nil) + page = entry({"admin", "network", "iface_add"}, form("admin_network/iface_add"), nil) page.leaf = true page = entry({"admin", "network", "iface_delete"}, post("iface_delete"), nil) @@ -289,7 +289,8 @@ function iface_reconnect(iface) local netmd = require "luci.model.network".init() local net = netmd:get_network(iface) if net then - luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface) + luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null" + % luci.util.shellquote(iface)) luci.http.status(200, "Reconnected") return end @@ -301,7 +302,8 @@ function iface_shutdown(iface) local netmd = require "luci.model.network".init() local net = netmd:get_network(iface) if net then - luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface) + luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null" + % luci.util.shellquote(iface)) luci.http.status(200, "Shutdown") return end @@ -313,7 +315,8 @@ function iface_delete(iface) local netmd = require "luci.model.network".init() local net = netmd:del_network(iface) if net then - luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface) + luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null" + % luci.util.shellquote(iface)) luci.http.redirect(luci.dispatcher.build_url("admin/network/network")) netmd:commit("network") netmd:commit("wireless") @@ -389,7 +392,7 @@ function diag_command(cmd, addr) if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then luci.http.prepare_content("text/plain") - local util = io.popen(cmd % addr) + local util = io.popen(cmd % luci.util.shellquote(addr)) if util then while true do local ln = util:read("*l") @@ -408,21 +411,21 @@ function diag_command(cmd, addr) end function diag_ping(addr) - diag_command("ping -c 5 -W 1 %q 2>&1", addr) + diag_command("ping -c 5 -W 1 %s 2>&1", addr) end function diag_traceroute(addr) - diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr) + diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr) end function diag_nslookup(addr) - diag_command("nslookup %q 2>&1", addr) + diag_command("nslookup %s 2>&1", addr) end function diag_ping6(addr) - diag_command("ping6 -c 5 %q 2>&1", addr) + diag_command("ping6 -c 5 %s 2>&1", addr) end function diag_traceroute6(addr) - diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr) + diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr) end diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua index 22e1b7e173..4471fd597a 100644 --- a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua @@ -14,7 +14,7 @@ function index() entry({"admin", "status", "routes"}, template("admin_status/routes"), _("Routes"), 3) entry({"admin", "status", "syslog"}, call("action_syslog"), _("System Log"), 4) entry({"admin", "status", "dmesg"}, call("action_dmesg"), _("Kernel Log"), 5) - entry({"admin", "status", "processes"}, cbi("admin_status/processes"), _("Processes"), 6) + entry({"admin", "status", "processes"}, form("admin_status/processes"), _("Processes"), 6) entry({"admin", "status", "realtime"}, alias("admin", "status", "realtime", "load"), _("Realtime Graphs"), 7) @@ -62,7 +62,9 @@ end function action_bandwidth(iface) luci.http.prepare_content("application/json") - local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface) + local bwc = io.popen("luci-bwc -i %s 2>/dev/null" + % luci.util.shellquote(iface)) + if bwc then luci.http.write("[") @@ -80,7 +82,9 @@ end function action_wireless(iface) luci.http.prepare_content("application/json") - local bwc = io.popen("luci-bwc -r %q 2>/dev/null" % iface) + local bwc = io.popen("luci-bwc -r %s 2>/dev/null" + % luci.util.shellquote(iface)) + if bwc then luci.http.write("[") diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua index 9c33d9c18b..ba317f9f4f 100644 --- a/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua @@ -5,8 +5,8 @@ module("luci.controller.admin.uci", package.seeall) function index() - local redir = luci.http.formvalue("redir", true) or - luci.dispatcher.build_url(unpack(luci.dispatcher.context.request)) + local redir = luci.http.formvalue("redir", true) + or table.concat(luci.dispatcher.context.request, "/") entry({"admin", "uci"}, nil, _("Configuration")) entry({"admin", "uci", "changes"}, call("action_changes"), _("Changes"), 40).query = {redir=redir} diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua index 66d9942a11..fbde431df8 100644 --- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua +++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua @@ -115,7 +115,7 @@ s:taboption("advanced", Flag, "nonegcache", s:taboption("advanced", Value, "serversfile", translate("Additional servers file"), translate("This file may contain lines like 'server=/domain/1.2.3.4' or 'server=1.2.3.4' for".. - "domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers.")) + "domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers.")) s:taboption("advanced", Flag, "strictorder", translate("Strict order"), @@ -212,6 +212,12 @@ cq.optional = true cq.datatype = "uinteger" cq.placeholder = 150 +cs = s:taboption("advanced", Value, "cachesize", + translate("Size of DNS query cache"), + translate("Number of cached DNS entries (max is 10000, 0 is no caching)")) +cs.optional = true +cs.datatype = "range(0,10000)" +cs.placeholder = 150 s:taboption("tftp", Flag, "enable_tftp", translate("Enable TFTP server")).optional = true @@ -274,7 +280,7 @@ s.anonymous = true s.template = "cbi/tblsection" name = s:option(Value, "name", translate("Hostname")) -name.datatype = "hostname" +name.datatype = "hostname('strict')" name.rmempty = true function name.write(self, section, value) @@ -295,7 +301,7 @@ ip = s:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\ ip.datatype = "or(ip4addr,'ignore')" time = s:option(Value, "leasetime", translate("Lease time")) -time.rmempty = true +time.rmempty = true duid = s:option(Value, "duid", translate("<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>")) duid.datatype = "and(rangelength(20,36),hexstring)" diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua index 89a73a5ca8..b52dff13ac 100644 --- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua +++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua @@ -5,6 +5,7 @@ m = Map("network", translate("Switch"), translate("The network ports on this device can be combined to several <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s in which computers can communicate directly with each other. <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network.")) local fs = require "nixio.fs" +local ut = require "luci.util" local nw = require "luci.model.network" local switches = { } @@ -74,7 +75,7 @@ m.uci:foreach("network", "switch", end -- Parse some common switch properties from swconfig help output. - local swc = io.popen("swconfig dev %q help 2>/dev/null" % switch_name) + local swc = io.popen("swconfig dev %s help 2>/dev/null" % ut.shellquote(switch_name)) if swc then local is_port_attr = false diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua index c0bb380307..a574d35979 100644 --- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua +++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua @@ -63,7 +63,7 @@ function m.parse(map) Map.parse(map) if m:get(wdev:name(), "type") == "mac80211" and new_cc and new_cc ~= old_cc then - luci.sys.call("iw reg set %q" % new_cc) + luci.sys.call("iw reg set %s" % ut.shellquote(new_cc)) luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless", arg[1])) return end diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm index d5d78289be..88e0fffd9c 100644 --- a/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm +++ b/modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm @@ -69,7 +69,7 @@ end <% if querypat then %> <div class="cbi-value"> <%:Displaying only packages containing%> <strong>"<%=pcdata(query)%>"</strong> - <input type="button" onclick="location.href='?display=<%=pcdata(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" /> + <input type="button" onclick="location.href='?display=<%=luci.http.urlencode(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" /> <br style="clear:both" /> </div> <% end %> diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm b/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm index c3373604f3..6e725c8888 100644 --- a/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm +++ b/modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm @@ -16,9 +16,9 @@ <% end %> <div class="cbi-page-actions"> - <% local r = luci.http.formvalue("redir"); if r and #r > 0 then %> + <% local node, url = luci.dispatcher.lookup(luci.http.formvalue("redir")); if url then %> <div style="float:left"> - <form class="inline" method="get" action="<%=luci.util.pcdata(r)%>"> + <form class="inline" method="get" action="<%=luci.util.pcdata(url)%>"> <input class="cbi-button cbi-button-link" style="float:left; margin:0" type="submit" value="<%:Back%>" /> </form> </div> diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm b/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm index 5da7281a80..20327adff3 100644 --- a/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm +++ b/modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm @@ -18,10 +18,12 @@ <p><strong><%:There are no pending changes to revert!%></strong></p> <% end %> -<div class="cbi-page-actions"> - <form class="inline" method="get" action="<%=luci.util.pcdata(luci.http.formvalue("redir"))%>"> - <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" /> - </form> -</div> +<% local node, url = luci.dispatcher.lookup(luci.http.formvalue("redir")); if url then %> + <div class="cbi-page-actions"> + <form class="inline" method="get" action="<%=luci.util.pcdata(url)%>"> + <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" /> + </form> + </div> +<% end %> <%+footer%> diff --git a/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm b/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm index 18be30be35..9f017c9e72 100644 --- a/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm +++ b/modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm @@ -6,7 +6,7 @@ <script type="text/javascript" src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js"></script> <script type="text/javascript" src="osm.js"></script> </head> -<body onload="init();drawmap();" style="padding:0px; margin:0px"> +<body onload="init();drawmap();" style="padding:0px; margin:0px"> <div id="map"></div> <div style="position:absolute; bottom:0%; width:100%; background:url('cbi/black_60.png'); font-size:10px; color:#fff;z-index:1000"> Map by <a href="http://www.openstreetmap.org" title="www.openstreetmap.org" style="color:#fff;" >openstreetmap.org</a>, License CC-BY-SA @@ -16,5 +16,4 @@ Longitude: <input id="osmlon" name="osmlon" type="text" size="20" style="font-size:10px;"> </span> </div> - </body> diff --git a/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua b/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua index e2291e5ca6..adad7508bc 100644 --- a/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua +++ b/modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua @@ -77,7 +77,7 @@ function index() page.order = 10 page = node("admin", "freifunk", "basics", "profile_expert") - page.target = cbi("freifunk/profile_expert") + page.target = form("freifunk/profile_expert") page.title = _("Profile (Expert)") page.order = 20 diff --git a/modules/luci-mod-rpc/luasrc/controller/rpc.lua b/modules/luci-mod-rpc/luasrc/controller/rpc.lua index 759bb749cf..3326d57a95 100644 --- a/modules/luci-mod-rpc/luasrc/controller/rpc.lua +++ b/modules/luci-mod-rpc/luasrc/controller/rpc.lua @@ -7,23 +7,45 @@ local pairs = pairs local print = print local pcall = pcall local table = table +local type = type +local tonumber = tonumber module "luci.controller.rpc" -function index() - local function authenticator(validator, accs) - local auth = luci.http.formvalue("auth", true) - if auth then -- if authentication token was given - local sdat = (luci.util.ubus("session", "get", { ubus_rpc_session = auth }) or { }).values - if sdat then -- if given token is valid - if sdat.user and luci.util.contains(accs, sdat.user) then - return sdat.user, auth - end - end + +local function session_retrieve(sid, allowed_users) + local util = require "luci.util" + local sdat = util.ubus("session", "get", { + ubus_rpc_session = sid + }) + + if type(sdat) == "table" and + type(sdat.values) == "table" and + type(sdat.values.token) == "string" and + type(sdat.values.secret) == "string" and + type(sdat.values.username) == "string" and + util.contains(allowed_users, sdat.values.username) + then + return sid, sdat.values + end + + return nil +end + +local function authenticator(validator, accs) + local auth = luci.http.formvalue("auth", true) + or luci.http.getcookie("sysauth") + + if auth then -- if authentication token was given + local sid, sdat = session_retrieve(auth, accs) + if sdat then -- if given token is valid + return sdat.username, sid end luci.http.status(403, "Forbidden") end +end +function index() local rpc = node("rpc") rpc.sysauth = "root" rpc.sysauth_authenticator = authenticator @@ -43,39 +65,48 @@ function rpc_auth() local ltn12 = require "luci.ltn12" local util = require "luci.util" - local loginstat - local server = {} server.challenge = function(user, pass) - local sid, token, secret - local config = require "luci.config" - - if sys.user.checkpasswd(user, pass) then - local sdat = util.ubus("session", "create", { timeout = config.sauth.sessiontime }) + local login = util.ubus("session", "login", { + username = user, + password = pass, + timeout = tonumber(config.sauth.sessiontime) + }) + + if type(login) == "table" and + type(login.ubus_rpc_session) == "string" + then + util.ubus("session", "set", { + ubus_rpc_session = login.ubus_rpc_session, + values = { + token = sys.uniqueid(16), + secret = sys.uniqueid(16) + } + }) + + local sid, sdat = session_retrieve(login.ubus_rpc_session, { user }) if sdat then - sid = sdat.ubus_rpc_session - token = sys.uniqueid(16) - secret = sys.uniqueid(16) - - http.header("Set-Cookie", "sysauth="..sid.."; path=/") - util.ubus("session", "set", { - ubus_rpc_session = sid, - values = { - user = user, - token = token, - secret = secret - } - }) + return { + sid = sid, + token = sdat.token, + secret = sdat.secret + } end end - return sid and {sid=sid, token=token, secret=secret} + return nil end server.login = function(...) local challenge = server.challenge(...) - return challenge and challenge.sid + if challenge then + http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ + challenge.sid, + http.getenv("SCRIPT_NAME") + }) + return challenge.sid + end end http.prepare_content("application/json") |