local Lyre = require"lyre" local Mime = require"mimetypes" local BigGlobe = require"bigglobe" local DB = require"db" local Escapes = require"html" local LFS = require"lfs" local SMTPAuth = require"smtpauth" -- Add template inclusions to Lyre local function compiel(fn, sub) local f = io.open(fn, "rb") local buf = {} for l in f:lines() do local includie = l:match("^{#%s*(.*)$") if includie then table.insert(buf, compiel(includie, true)) else table.insert(buf, l) end end f:close() return sub and table.concat(buf, "\n") or Lyre.compile(table.concat(buf, "\n"), fn) end local Static = {} local Templates = { ["/"] = compiel("index.html.l"), ["/search"] = compiel("search.html.l"), ["/obji"] = compiel("obj.html.l"), ["/obje"] = compiel("obje.html.l"), ["/login"] = compiel("login.html.l"), ["/admin"] = compiel("admin.html.l"), ["/user"] = compiel("user.html.l"), ["/invite"] = compiel("invite.html.l"), ["/reportuser"] = compiel("reportuser.html.l"), ["/reg"] = compiel("reg.html.l"), ["/reports"] = compiel("reports.html.l"), ["404"] = compiel("404.html.l"), } local handler = function(req, res) local verified = req:cookie"sesh" and DB.userverify(Escapes.urlunescape(req:cookie"sesh")) if verified and verified.privs == DB.USER_PRIVS_BANNED then verified = nil end if req:path() == "/autocomp" then res:contentType("text/plain;charset=UTF-8") res:write(DB.autocomplete(Escapes.urlunescape(req.querystring.q), req.querystring.a ~= nil)) elseif req:path():match"^/addobj/?$" then if verified then local oid = DB.regnewobj(verified.id, verified.privs >= DB.USER_PRIVS_APPROVED, false) if oid then res:addHeader("Location", "/obje/" .. DB.objhideid(oid)) res:statusCode(303) end else res:statusCode(403) end res:write"" elseif req:path():match"^/addtags/?$" then if verified and verified.privs >= DB.USER_PRIVS_APPROVED then local pohst = req:post() local returndata = {} if pohst.csrf and DB.csrfverify(verified.id, Escapes.urlunescape(pohst.csrf)) then local names = pohst["name[]"] local tcs = pohst["tc[]"] local adults = pohst["adult[]"] if #names == #tcs and #names == #adults then for tag = 1, #names do local tagid = DB.tagadd(tostring(names[tag]), (tonumber(tcs[tag]) or 0) + 1, tostring(adults[tag]) == "1") table.insert(returndata, tagid) end end end res:statusCode(200) res:write(table.concat(returndata, ",")) else res:statusCode(403) res:write"" end elseif req:path():match"^/verif/?$" then res:addHeader("Set-Cookie", "sesh=" .. (req.querystring.q or "") .. "; SameSite=Lax; Secure; HttpOnly") res:addHeader("Location", "/") res:statusCode(303) res:write"" elseif req:path():match"^/apprq/?$" then if verified and verified.privs >= DB.USER_PRIVS_MOD then -- Has decided on something already? if req.querystring.csrf and DB.csrfverify(verified.id, Escapes.urlunescape(req.querystring.csrf)) then local oid = DB.objshowid(Escapes.urlunescape(req.querystring.oid)) if req.querystring.deliamsure and DB.getuserbyid(DB.getobj(oid).owner).privs < verified.privs then if req.querystring.banuser then DB.banuser(DB.getobj(oid).owner) end DB.delobj(oid, req.querystring.delfiles ~= nil) elseif req.querystring.approveiamsure then if req.querystring.approveuser then DB.approveuser(DB.getobj(oid).owner) end DB.approveobj(oid) end end local oid = DB.nexttoapproveobj() res:addHeader("Location", oid and ("/obji/" .. DB.objhideid(oid)) or "/") res:statusCode(303) else res:statusCode(403) end res:write"" elseif req:path():match"^/static/" or req:path():match"^/objd/" or req:path() == "/favicon.ico" then local p = req:path() res:contentType(Mime.guess(p:sub(2):lower()) or "text/plain") -- Force download if p:match"^/objd/" then res:addHeader("Content-Disposition", "attachment;filename=\"" .. p:match"^/objd/[^/]+/(.*)$" .. "\"") end res:addHeader("Cache-Control", "max-age=604800") if req:method() == "HEAD" then res:write"" return end local phys = DB.urltophysical(p) if not BigGlobe.cfg.sendfile:match"^%s*$" then res:addHeader(BigGlobe.cfg.sendfile, BigGlobe.cfg.sendfileprefix .. "/" .. phys) res:write"" else local f = io.open(phys, "rb") if f then local sz = f:seek("end") if req:headers()["range"] then local starto, endo = req:headers()["range"]:match("^bytes%=(%d+)%-(%d*)$") starto = tonumber(starto) endo = tonumber(endo) if not endo then endo = sz - 1 elseif endo >= sz then res:statusCode(416) res:write"" return end if starto and endo and starto <= endo then res:statusCode(206) res:addHeader("Accept-Ranges", "bytes") res:addHeader("Content-Length", endo - starto + 1) res:addHeader("Content-Range", "bytes " .. starto .. "-" .. endo .. "/" .. sz) f:seek("set", starto) res:write(f:read(endo - starto + 1)) end else f:seek("set") res:write(f:read"*a") end f:close() else res:statusCode(404) res:write"" end end else local tmpl = Templates[req:path():sub(1, req:path():sub(2):find("/") or -1)] if not tmpl then res:statusCode(404) tmpl = Templates["404"] end res:statusCode(200) local env = {BigGlobe = BigGlobe, SMTPAuth = SMTPAuth, DB = DB, Escapes = Escapes, LFS = LFS, request = req, response = res, print = print, verified = verified} local succ, val if _ENV then succ, val = xpcall(Lyre.render, debug.traceback, tmpl, env) else succ, val = pcall(Lyre.render, tmpl, env) end if succ then res:write(val) else print("Error!") print(val) res:statusCode(500) res:write"Internal server error. Try not doing that." end end end return handler