ikibooru/core.lua
2024-09-07 09:53:51 +03:00

212 lines
5.8 KiB
Lua

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, true)
else
succ, val = pcall(Lyre.render, tmpl, env, true)
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