diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ebc5817e..b18c02a5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: sudo apt install lua-check + run: sudo apt-get -y update && sudo apt-get -y install lua-check - name: Install example site run: ln -s ./docs/site-example ./site - name: Lint Lua code @@ -22,7 +22,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: sudo apt install shellcheck + run: sudo apt-get -y update && sudo apt-get -y install shellcheck - name: Install example site run: ln -s ./docs/site-example ./site - name: Lint shell code diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html index 31555f16..7778be4a 100644 --- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html +++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade.html @@ -44,7 +44,6 @@ $Id$
-
diff --git a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html index 92c25a63..9733132f 100644 --- a/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html +++ b/package/gluon-web-admin/files/lib/gluon/config-mode/view/admin/upgrade_confirm.html @@ -49,13 +49,11 @@ You may obtain a copy of the License at
" /> -
" /> -
diff --git a/package/gluon-web-model/files/lib/gluon/web/view/model/form.html b/package/gluon-web-model/files/lib/gluon/web/view/model/form.html index 06270be3..d222dde2 100644 --- a/package/gluon-web-model/files/lib/gluon/web/view/model/form.html +++ b/package/gluon-web-model/files/lib/gluon/web/view/model/form.html @@ -1,5 +1,4 @@
-
diff --git a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua index 42dc47d1..d2a6b500 100644 --- a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua +++ b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua @@ -184,9 +184,15 @@ local function dispatch(config, http, request) return end - http:parse_input(node.filehandler) + local ok, err = pcall(http.parse_input, http, node.filehandler) + if not ok then + http:status(400, "Bad request") + http:prepare_content("text/plain") + http:write(err .. "\r\n") + return + end - local ok, err = pcall(node.target) + ok, err = pcall(node.target) if not ok then http:status(500, "Internal Server Error") renderer.render_layout("error/500", { @@ -208,6 +214,6 @@ return function(config, http) if not ok then http:status(500, "Internal Server Error") http:prepare_content("text/plain") - http:write(err) + http:write(err .. "\r\n") end end diff --git a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua index 8d070d95..5f56fa1b 100644 --- a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua +++ b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/http/protocol.lua @@ -108,16 +108,11 @@ end -- o String value containing a chunk of the file data -- o Boolean which indicates whether the current chunk is the last one (eof) local 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=(.+)$") + local mime_boundary = (msg.env.CONTENT_TYPE or ''):match("^multipart/form%-data; boundary=(.+)$") + if not mime_boundary then + error("Invalid Content-Type found") end - if not msg.mime_boundary then - return nil, "Invalid Content-Type found" - end - - local tlen = 0 local inhdr = false local field = nil @@ -188,10 +183,10 @@ local function mimedecode_message_body(src, msg, filecb) local spos, epos, found repeat - spos, epos = data:find("\r\n--" .. msg.mime_boundary .. "\r\n", 1, true) + spos, epos = data:find("\r\n--" .. mime_boundary .. "\r\n", 1, true) if not spos then - spos, epos = data:find("\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true) + spos, epos = data:find("\r\n--" .. mime_boundary .. "--\r\n", 1, true) end @@ -250,20 +245,61 @@ local function mimedecode_message_body(src, msg, filecb) return true end - return pump(src, snk) + assert(pump(src, snk)) +end + +local function check_post_origin(msg) + local default_port = '80' + local request_scheme = 'http' + if msg.env.HTTPS then + default_port = '443' + request_scheme = 'https' + end + + local request_host = msg.env.HTTP_HOST + if not request_host then + error('POST request without Host header') + end + if not request_host:match(':[0-9]+$') then + request_host = request_host .. ':' .. default_port + end + + local origin = msg.env.HTTP_ORIGIN + if not origin then + error('POST request without Origin header') + end + local origin_scheme, origin_host = origin:match('^([^:]*)://(.*)$') + if not origin_host then + error('POST request with invalid Origin header') + end + if not origin_host:match(':[0-9]+$') then + local origin_port + if origin_scheme == 'http' then + origin_port = '80' + elseif origin_scheme == 'https' then + origin_port = '443' + else + error('POST request with invalid Origin header') + end + origin_host = origin_host .. ':' .. origin_port + end + + if request_scheme ~= origin_scheme or request_host ~= origin_host then + error('Invalid cross-origin POST') + end end -- This function will examine the Content-Type within the given message object -- to select the appropriate content decoder. -- Currently only the multipart/form-data mime type is supported. function M.parse_message_body(src, msg, filecb) - if not (msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE) then + if msg.env.REQUEST_METHOD ~= "POST" then return end - if msg.env.CONTENT_TYPE:match("^multipart/form%-data") then - return mimedecode_message_body(src, msg, filecb) - end + check_post_origin(msg) + + mimedecode_message_body(src, msg, filecb) end return M