Tue, 09 Mar 2021 12:16:56 +0000
Initial commit
local http_util = require "util.http"; local usercookie = require"util.usercookie"; local uuid = require "util.uuid"; local function unpack_cookies(request) if not request.cookies then request.cookies = usercookie.decode(request.headers.cookie); end end local post_parsers = { ["application/x-www-form-urlencoded"] = http_util.formdecode; }; local function parse_body(request) local content_type = request.headers.content_type; if not content_type then --log("warn", "No Content-Type header sent"); return nil, 400; end local post_parser = post_parsers[content_type]; if not post_parser then --log("warn", "Don't know how to parse %s", content_type); return nil, 415; end local post_body = post_parser(request.body); if type(post_body) ~= "table" then --log("warn", "Could not parse %s %q, got %s", content_type, request.body, type(post_body)); return nil, 415; end return post_body; end local csrf_token_len = #uuid.generate(); local function validate_csrf(csrf_token, request) if request.headers.origin == nil and request.headers.referer == nil then return true; -- Probably a non-browser request end if not (csrf_token and #csrf_token == csrf_token_len) then return false; end unpack_cookies(request); return request.cookies.csrf_token == csrf_token; end local function parse_body_and_csrf(request) local post_body, err = parse_body(request); if not post_body then return nil, err; end if not validate_csrf(post_body.csrf_token, request) then --log("warn", "CSRF error (token: '%s', cookie: '%s')", -- tostring(post_body.csrf_token), tostring(request.headers.cookie)); return nil, 400; end return post_body; end -- Cookies local function add_header(headers, header, value) if headers[header] then headers[header] = headers[header] .. ", " .. value; else headers[header] = value; end end local function prefix_header(headers, header, value) if headers[header] then headers[header] = value .. ", " .. headers[header]; else headers[header] = value; end end local function set_cookie(headers, cookie, opts) if opts then local params = {""}; if opts.path then table.insert(params, "Path="..opts.path); end if opts.ttl then table.insert(params, ("Max-Age=%d"):format(opts.ttl)); end if opts.http_only then table.insert(params, "HttpOnly"); end if opts.secure then table.insert(params, "Secure"); end if #params > 1 then cookie = cookie .. table.concat(params, "; "); end end prefix_header(headers, "set_cookie", cookie); end return { unpack_cookies = unpack_cookies; validate_csrf = validate_csrf; parse_body_and_csrf = parse_body_and_csrf; parse_body = parse_body; add_header = add_header; prefix_header = prefix_header; set_cookie = set_cookie; };